diff options
Diffstat (limited to 'src')
164 files changed, 12479 insertions, 9488 deletions
diff --git a/src/cjson/lua_cjson.c b/src/cjson/lua_cjson.c index 6af43d8eb7..254355e5a2 100644 --- a/src/cjson/lua_cjson.c +++ b/src/cjson/lua_cjson.c @@ -174,9 +174,9 @@ typedef struct { typedef struct { /* convert null in json objects to lua nil instead of vim.NIL */ - int luanil_object; + bool luanil_object; /* convert null in json arrays to lua nil instead of vim.NIL */ - int luanil_array; + bool luanil_array; } json_options_t; typedef struct { @@ -1453,15 +1453,11 @@ static int json_decode(lua_State *l) luaL_checktype(l, -1, LUA_TTABLE); lua_getfield(l, -1, "object"); - if (!lua_isnil(l, -1)) { - options.luanil_object = true; - } + options.luanil_object = lua_toboolean(l, -1); lua_pop(l, 1); lua_getfield(l, -1, "array"); - if (!lua_isnil(l, -1)) { - options.luanil_array = true; - } + options.luanil_array = lua_toboolean(l, -1); /* Also pop the luanil table */ lua_pop(l, 2); break; diff --git a/src/clint.py b/src/clint.py index 062901b43a..41058469b1 100755 --- a/src/clint.py +++ b/src/clint.py @@ -1689,7 +1689,7 @@ def CheckSpacing(filename, clean_lines, linenum, error): # Look for < that is not surrounded by spaces. This is only # triggered if both sides are missing spaces, even though - # technically should should flag if at least one side is missing a + # technically should flag if at least one side is missing a # space. This is done to avoid some false positives with shifts. match = Search(r'[^\s<]<([^\s=<].*)', reduced_line) if (match and not FindNextMatchingAngleBracket(clean_lines, linenum, @@ -1989,12 +1989,12 @@ def CheckLanguage(filename, clean_lines, linenum, error): match = Search(r'\b(strncpy|STRNCPY)\b', line) if match: error(filename, linenum, 'runtime/printf', 4, - 'Use xstrlcpy or snprintf instead of %s (unless this is from Vim)' + 'Use xstrlcpy, xmemcpyz or snprintf instead of %s (unless this is from Vim)' % match.group(1)) match = Search(r'\b(strcpy)\b', line) if match: error(filename, linenum, 'runtime/printf', 4, - 'Use xstrlcpy or snprintf instead of %s' % match.group(1)) + 'Use xstrlcpy, xmemcpyz or snprintf instead of %s' % match.group(1)) match = Search(r'\b(STRNCAT|strncat|strcat|vim_strcat)\b', line) if match: error(filename, linenum, 'runtime/printf', 4, diff --git a/src/coverity-model.c b/src/coverity-model.c index 4338b75ea2..44953a3de4 100644 --- a/src/coverity-model.c +++ b/src/coverity-model.c @@ -111,3 +111,31 @@ void * xmemdup(const void *data, size_t len) __coverity_writeall__(p); return p; } + +// Teach coverity that lua errors are noreturn + +typedef struct {} lua_State; + +int luaL_typerror(lua_State *L, int narg, const char *tname) +{ + __coverity_panic__(); + return 0; +} + +int luaL_error(lua_State *L, const char *fmt, ...) +{ + __coverity_panic__(); + return 0; +} + +int luaL_argerror(lua_State *L, int numarg, const char *extramsg) +{ + __coverity_panic__(); + return 0; +} + +void *luaL_checkudata(lua_State *L, int ud, const char *tname) +{ + return __coverity_alloc_nosize__() +} + diff --git a/src/klib/kvec.h b/src/klib/kvec.h index a32b35a14c..1b9e6fd9f8 100644 --- a/src/klib/kvec.h +++ b/src/klib/kvec.h @@ -153,6 +153,12 @@ type init_array[INIT_SIZE]; \ } +#define KVI_INITIAL_VALUE(v) { \ + .size = 0, \ + .capacity = ARRAY_SIZE((v).init_array), \ + .items = (v).init_array \ +} + /// Initialize vector with preallocated array /// /// @param[out] v Vector to initialize. @@ -218,6 +224,17 @@ static inline void *_memcpy_free(void *const restrict dest, void *const restrict } \ } while (0) +#define kvi_concat_len(v, data, len) \ + if (len > 0) { \ + kvi_ensure_more_space(v, len); \ + assert((v).items); \ + memcpy((v).items + (v).size, data, sizeof((v).items[0]) * len); \ + (v).size = (v).size + len; \ + } + +#define kvi_concat(v, str) kvi_concat_len(v, str, strlen(str)) +#define kvi_splice(v1, v0) kvi_concat_len(v1, (v0).items, (v0).size) + /// Get location where to store new element to a vector with preallocated array /// /// @param[in,out] v Vector to push to. diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index 047b22edcc..937cfaaa31 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -33,7 +33,7 @@ find_package(Libuv 1.28.0 REQUIRED) find_package(Libvterm 0.3.3 REQUIRED) find_package(Lpeg REQUIRED) find_package(Msgpack 1.0.0 REQUIRED) -find_package(Treesitter 0.20.9 REQUIRED) +find_package(Treesitter 0.22.6 REQUIRED) find_package(Unibilium 2.0 REQUIRED) target_link_libraries(main_lib INTERFACE @@ -327,7 +327,7 @@ set(GENERATED_UI_EVENTS_CALL ${GENERATED_DIR}/ui_events_call.generated.h) set(GENERATED_UI_EVENTS_CLIENT ${GENERATED_DIR}/ui_events_client.generated.h) set(GENERATED_UI_EVENTS_REMOTE ${GENERATED_DIR}/ui_events_remote.generated.h) set(GENERATED_UNICODE_TABLES ${GENERATED_DIR}/unicode_tables.generated.h) -set(LUA_API_C_BINDINGS ${GENERATED_DIR}/lua_api_c_bindings.generated.c) +set(LUA_API_C_BINDINGS ${GENERATED_DIR}/lua_api_c_bindings.generated.h) set(VIM_MODULE_FILE ${GENERATED_DIR}/lua/vim_module.generated.h) # NVIM_RUNTIME_DIR @@ -450,20 +450,27 @@ endif() #------------------------------------------------------------------------------- get_target_property(prop main_lib INTERFACE_COMPILE_DEFINITIONS) -foreach(gen_cdef ${prop}) - if(NOT ${gen_cdef} MATCHES "INCLUDE_GENERATED_DECLARATIONS") - list(APPEND gen_cflags "-D${gen_cdef}") - endif() -endforeach() +if(NOT "${prop}" STREQUAL "prop-NOTFOUND") + foreach(gen_cdef ${prop}) + if(NOT ${gen_cdef} MATCHES "INCLUDE_GENERATED_DECLARATIONS") + list(APPEND gen_cflags "-D${gen_cdef}") + endif() + endforeach() +endif() get_directory_property(targets BUILDSYSTEM_TARGETS) foreach(target ${targets}) get_target_property(prop ${target} INTERFACE_INCLUDE_DIRECTORIES) - foreach(gen_include ${prop}) - list(APPEND gen_cflags "-I${gen_include}") - endforeach() + if(NOT "${prop}" STREQUAL "prop-NOTFOUND") + message(STATUS "${target} props '${prop}'") + foreach(gen_include ${prop}) + list(APPEND gen_cflags "-I${gen_include}") + endforeach() + endif() endforeach() +list(REMOVE_DUPLICATES gen_cflags) + if(APPLE AND CMAKE_OSX_SYSROOT) list(APPEND gen_cflags "-isysroot" "${CMAKE_OSX_SYSROOT}") endif() @@ -498,7 +505,6 @@ set(LUA_GEN_DEPS ${GENERATOR_PRELOAD} $<TARGET_FILE:nlua0>) # NVIM_GENERATED_FOR_HEADERS: generated headers to be included in headers # NVIM_GENERATED_FOR_SOURCES: generated headers to be included in sources -# NVIM_GENERATED_SOURCES: generated source files # These lists must be mutually exclusive. foreach(sfile ${NVIM_SOURCES} ${GENERATED_API_DISPATCH} @@ -613,10 +619,6 @@ add_custom_command( VERBATIM ) -list(APPEND NVIM_GENERATED_SOURCES - "${LUA_API_C_BINDINGS}" -) - add_custom_command( OUTPUT ${GENERATED_UI_EVENTS_CALL} ${GENERATED_UI_EVENTS_REMOTE} @@ -650,10 +652,7 @@ list(APPEND NVIM_GENERATED_FOR_SOURCES "${GENERATED_OPTIONS_MAP}" "${GENERATED_UNICODE_TABLES}" "${VIM_MODULE_FILE}" -) - -list(APPEND NVIM_GENERATED_SOURCES - "${PROJECT_BINARY_DIR}/cmake.config/auto/pathdef.c" + "${PROJECT_BINARY_DIR}/cmake.config/auto/pathdef.h" ) add_custom_command(OUTPUT ${GENERATED_EX_CMDS_ENUM} ${GENERATED_EX_CMDS_DEFS} @@ -702,7 +701,6 @@ endif() target_sources(main_lib INTERFACE ${NVIM_GENERATED_FOR_SOURCES} ${NVIM_GENERATED_FOR_HEADERS} - ${NVIM_GENERATED_SOURCES} ${NVIM_SOURCES} ${NVIM_HEADERS} ${EXTERNAL_SOURCES} @@ -826,9 +824,12 @@ add_glob_target( FLAGS --quiet EXCLUDE ${EXCLUDE_CLANG_TIDY}) -# These are the same warnings as https://neovim.io/doc/reports/clang/. The -# checks we ignore are meant to be removed eventually, but we can only do so -# after we properly fix the problems without breaking CI. +# The checks we ignore are meant to be removed eventually, but we can only +# enable each warning after we fix all instances of that specific warning as to +# not break CI. +if(APPLE) + string(APPEND CLANG_ANALYZER_IGNORE "-clang-analyzer-core.NonNullParamChecker,") +endif() add_glob_target( TARGET clang-analyzer COMMAND ${CLANG_TIDY_PRG} @@ -837,12 +838,12 @@ add_glob_target( --checks=' -*, clang-analyzer-*, - -clang-analyzer-core.NonNullParamChecker, -clang-analyzer-core.NullDereference, -clang-analyzer-core.UndefinedBinaryOperatorResult, -clang-analyzer-core.uninitialized.Assign, -clang-analyzer-optin.performance.Padding, -clang-analyzer-security.insecureAPI.strcpy, + ${CLANG_ANALYZER_IGNORE} ' EXCLUDE ${EXCLUDE_CLANG_TIDY}) @@ -899,15 +900,6 @@ add_subdirectory(po) add_custom_target(generated-sources DEPENDS ${NVIM_GENERATED_FOR_HEADERS} ${NVIM_GENERATED_FOR_SOURCES} - ${NVIM_GENERATED_SOURCES} -) - -set(VIMDOC_FILES - ${NVIM_RUNTIME_DIR}/doc/api.txt - ${NVIM_RUNTIME_DIR}/doc/diagnostic.txt - ${NVIM_RUNTIME_DIR}/doc/lsp.txt - ${NVIM_RUNTIME_DIR}/doc/lua.txt - ${NVIM_RUNTIME_DIR}/doc/treesitter.txt ) file(GLOB API_SOURCES CONFIGURE_DEPENDS ${PROJECT_SOURCE_DIR}/src/nvim/api/*.c) @@ -920,23 +912,22 @@ file(GLOB LUA_SOURCES CONFIGURE_DEPENDS ${NVIM_RUNTIME_DIR}/lua/vim/treesitter/*.lua ) -add_custom_command( - OUTPUT ${VIMDOC_FILES} - COMMAND ${CMAKE_COMMAND} -E env "VIMRUNTIME=${NVIM_RUNTIME_DIR}" - $<TARGET_FILE:nvim_bin> -l scripts/gen_vimdoc.lua +add_target(doc-vim + COMMAND $<TARGET_FILE:nvim_bin> -u NONE -l scripts/gen_vimdoc.lua DEPENDS nvim ${API_SOURCES} ${LUA_SOURCES} ${PROJECT_SOURCE_DIR}/scripts/gen_vimdoc.lua - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} -) - -add_custom_command( - OUTPUT ${GEN_EVAL_TOUCH} - COMMAND ${CMAKE_COMMAND} -E touch ${GEN_EVAL_TOUCH} - COMMAND ${CMAKE_COMMAND} -E env "VIMRUNTIME=${NVIM_RUNTIME_DIR}" - $<TARGET_FILE:nvim_bin> -l ${PROJECT_SOURCE_DIR}/scripts/gen_eval_files.lua + ${NVIM_RUNTIME_DIR}/doc/api.txt + ${NVIM_RUNTIME_DIR}/doc/diagnostic.txt + ${NVIM_RUNTIME_DIR}/doc/lsp.txt + ${NVIM_RUNTIME_DIR}/doc/lua.txt + ${NVIM_RUNTIME_DIR}/doc/treesitter.txt + ) + +add_target(doc-eval + COMMAND $<TARGET_FILE:nvim_bin> -u NONE -l ${PROJECT_SOURCE_DIR}/scripts/gen_eval_files.lua DEPENDS nvim ${FUNCS_METADATA} @@ -944,22 +935,14 @@ add_custom_command( ${PROJECT_SOURCE_DIR}/src/nvim/eval.lua ${PROJECT_SOURCE_DIR}/src/nvim/options.lua ${PROJECT_SOURCE_DIR}/src/nvim/vvars.lua - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} -) + ${NVIM_RUNTIME_DIR}/doc/builtin.txt + ) -add_custom_target(doc-eval DEPENDS ${GEN_EVAL_TOUCH}) -add_custom_target(doc-vim DEPENDS ${VIMDOC_FILES}) add_custom_target(doc) add_dependencies(doc doc-vim doc-eval) -set(lintdoc_touch ${TOUCHES_DIR}/lintdoc) -add_custom_command( - OUTPUT ${lintdoc_touch} - COMMAND ${CMAKE_COMMAND} -E touch ${lintdoc_touch} - COMMAND ${CMAKE_COMMAND} -E env "VIMRUNTIME=${NVIM_RUNTIME_DIR}" - $<TARGET_FILE:nvim_bin> --clean -l scripts/lintdoc.lua - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} +add_target(lintdoc + COMMAND $<TARGET_FILE:nvim_bin> -u NONE -l scripts/lintdoc.lua DEPENDS ${DOCFILES} - USES_TERMINAL) -add_custom_target(lintdoc DEPENDS ${lintdoc_touch}) + CUSTOM_COMMAND_ARGS USES_TERMINAL) add_dependencies(lintdoc nvim) diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index d71bcc4bcf..ca8367b7ce 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -381,15 +381,15 @@ cleanup: /// - desc (string) optional: description (for documentation and troubleshooting). /// - callback (function|string) optional: Lua function (or Vimscript function name, if /// string) called when the event(s) is triggered. Lua callback can return a truthy -/// value (not `false` or `nil`) to delete the autocommand. Receives a table argument -/// with these keys: +/// value (not `false` or `nil`) to delete the autocommand. Receives one argument, +/// a table with these keys: [event-args]() /// - id: (number) autocommand id /// - event: (string) name of the triggered event |autocmd-events| /// - group: (number|nil) autocommand group id, if any /// - match: (string) expanded value of [<amatch>] /// - buf: (number) expanded value of [<abuf>] /// - file: (string) expanded value of [<afile>] -/// - data: (any) arbitrary data passed from [nvim_exec_autocmds()] +/// - data: (any) arbitrary data passed from [nvim_exec_autocmds()] [event-data]() /// - 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/buffer.c b/src/nvim/api/buffer.c index 7f195de959..7e64808709 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -39,6 +39,7 @@ #include "nvim/memory_defs.h" #include "nvim/move.h" #include "nvim/ops.h" +#include "nvim/option_vars.h" #include "nvim/pos_defs.h" #include "nvim/state_defs.h" #include "nvim/types_defs.h" @@ -229,20 +230,6 @@ Boolean nvim_buf_detach(uint64_t channel_id, Buffer buffer, Error *err) return true; } -/// @nodoc -void nvim__buf_redraw_range(Buffer buffer, Integer first, Integer last, Error *err) -{ - buf_T *buf = find_buffer_by_handle(buffer, err); - if (!buf) { - return; - } - if (last < 0) { - last = buf->b_ml.ml_line_count; - } - - redraw_buf_range_later(buf, (linenr_T)first + 1, (linenr_T)last); -} - /// Gets a line-range from the buffer. /// /// Indexing is zero-based, end-exclusive. Negative indices are interpreted @@ -529,18 +516,18 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In // Another call to ml_get_buf() may free the lines, so we make copies char *str_at_start = ml_get_buf(buf, (linenr_T)start_row); - size_t len_at_start = strlen(str_at_start); - str_at_start = arena_memdupz(arena, str_at_start, len_at_start); - start_col = start_col < 0 ? (int64_t)len_at_start + start_col + 1 : start_col; - VALIDATE_RANGE((start_col >= 0 && (size_t)start_col <= len_at_start), "start_col", { + colnr_T len_at_start = ml_get_buf_len(buf, (linenr_T)start_row); + str_at_start = arena_memdupz(arena, str_at_start, (size_t)len_at_start); + start_col = start_col < 0 ? len_at_start + start_col + 1 : start_col; + VALIDATE_RANGE((start_col >= 0 && start_col <= len_at_start), "start_col", { return; }); char *str_at_end = ml_get_buf(buf, (linenr_T)end_row); - size_t len_at_end = strlen(str_at_end); - str_at_end = arena_memdupz(arena, str_at_end, len_at_end); - end_col = end_col < 0 ? (int64_t)len_at_end + end_col + 1 : end_col; - VALIDATE_RANGE((end_col >= 0 && (size_t)end_col <= len_at_end), "end_col", { + colnr_T len_at_end = ml_get_buf_len(buf, (linenr_T)end_row); + str_at_end = arena_memdupz(arena, str_at_end, (size_t)len_at_end); + end_col = end_col < 0 ? len_at_end + end_col + 1 : end_col; + VALIDATE_RANGE((end_col >= 0 && end_col <= len_at_end), "end_col", { return; }); @@ -563,12 +550,10 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In if (start_row == end_row) { old_byte = (bcount_t)end_col - start_col; } else { - old_byte += (bcount_t)len_at_start - start_col; + old_byte += len_at_start - start_col; for (int64_t i = 1; i < end_row - start_row; i++) { int64_t lnum = start_row + i; - - const char *bufline = ml_get_buf(buf, (linenr_T)lnum); - old_byte += (bcount_t)(strlen(bufline)) + 1; + old_byte += ml_get_buf_len(buf, (linenr_T)lnum) + 1; } old_byte += (bcount_t)end_col + 1; } @@ -577,7 +562,7 @@ void nvim_buf_set_text(uint64_t channel_id, Buffer buffer, Integer start_row, In String last_item = replacement.items[replacement.size - 1].data.string; size_t firstlen = (size_t)start_col + first_item.size; - size_t last_part_len = len_at_end - (size_t)end_col; + size_t last_part_len = (size_t)len_at_end - (size_t)end_col; if (replacement.size == 1) { firstlen += last_part_len; } @@ -970,7 +955,7 @@ String nvim_buf_get_name(Buffer buffer, Error *err) return cstr_as_string(buf->b_ffname); } -/// Sets the full file name for a buffer +/// Sets the full file name for a buffer, like |:file_f| /// /// @param buffer Buffer handle, or 0 for current buffer /// @param name Buffer name @@ -986,12 +971,23 @@ void nvim_buf_set_name(Buffer buffer, String name, Error *err) try_start(); + const bool is_curbuf = buf == curbuf; + const int save_acd = p_acd; + if (!is_curbuf) { + // Temporarily disable 'autochdir' when setting file name for another buffer. + p_acd = false; + } + // Using aucmd_*: autocommands will be executed by rename_buffer aco_save_T aco; aucmd_prepbuf(&aco, buf); int ren_ret = rename_buffer(name.data); aucmd_restbuf(&aco); + if (!is_curbuf) { + p_acd = save_acd; + } + if (try_end(err)) { return; } @@ -1271,10 +1267,13 @@ static void fix_cursor(win_T *win, linenr_T lo, linenr_T hi, linenr_T extra) } else if (extra < 0) { check_cursor_lnum(win); } - check_cursor_col_win(win); + check_cursor_col(win); changed_cline_bef_curs(win); + win->w_valid &= ~(VALID_BOTLINE_AP); + update_topline(win); + } else { + invalidate_botline(win); } - invalidate_botline(win); } /// Fix cursor position after replacing text @@ -1309,7 +1308,7 @@ static void fix_cursor_cols(win_T *win, linenr_T start_row, colnr_T start_col, l // it's easier to work with a single value here. // col and coladd are fixed by a later call - // to check_cursor_col_win when necessary + // to check_cursor_col when necessary win->w_cursor.col += win->w_cursor.coladd; win->w_cursor.coladd = 0; @@ -1324,7 +1323,7 @@ static void fix_cursor_cols(win_T *win, linenr_T start_row, colnr_T start_col, l // it already (in case virtualedit is active) // column might be additionally adjusted below // to keep it inside col range if needed - colnr_T len = (colnr_T)strlen(ml_get_buf(win->w_buffer, new_end_row)); + colnr_T len = ml_get_buf_len(win->w_buffer, new_end_row); if (win->w_cursor.col < len) { win->w_cursor.col = len; } @@ -1345,7 +1344,7 @@ static void fix_cursor_cols(win_T *win, linenr_T start_row, colnr_T start_col, l } } - check_cursor_col_win(win); + check_cursor_col(win); changed_cline_bef_curs(win); invalidate_botline(win); } @@ -1424,6 +1423,7 @@ void buf_collect_lines(buf_T *buf, size_t n, linenr_T start, int start_idx, bool for (size_t i = 0; i < n; i++) { linenr_T lnum = start + (linenr_T)i; char *bufstr = ml_get_buf(buf, lnum); - push_linestr(lstate, l, bufstr, strlen(bufstr), start_idx + (int)i, replace_nl, arena); + size_t bufstrlen = (size_t)ml_get_buf_len(buf, lnum); + push_linestr(lstate, l, bufstr, bufstrlen, start_idx + (int)i, replace_nl, arena); } } diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 6254e9fbd8..af3bfe2c03 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -20,6 +20,9 @@ #include "nvim/lua/executor.h" #include "nvim/memory.h" #include "nvim/memory_defs.h" +#include "nvim/msgpack_rpc/channel.h" +#include "nvim/msgpack_rpc/channel_defs.h" +#include "nvim/msgpack_rpc/unpacker.h" #include "nvim/option.h" #include "nvim/option_defs.h" #include "nvim/pos_defs.h" @@ -697,3 +700,109 @@ static void set_option_to(uint64_t channel_id, void *to, OptReqScope req_scope, set_option_value_for(name.data, opt_idx, optval, opt_flags, req_scope, to, err); }); } + +/// @deprecated Use nvim_exec_lua() instead. +/// +/// Calls many API methods atomically. +/// +/// This has two main usages: +/// 1. To perform several requests from an async context atomically, i.e. +/// without interleaving redraws, RPC requests from other clients, or user +/// interactions (however API methods may trigger autocommands or event +/// processing which have such side effects, e.g. |:sleep| may wake timers). +/// 2. To minimize RPC overhead (roundtrips) of a sequence of many requests. +/// +/// @param channel_id +/// @param calls an array of calls, where each call is described by an array +/// with two elements: the request name, and an array of arguments. +/// @param[out] err Validation error details (malformed `calls` parameter), +/// if any. Errors from batched calls are given in the return value. +/// +/// @return Array of two elements. The first is an array of return +/// values. The second is NIL if all calls succeeded. If a call resulted in +/// an error, it is a three-element array with the zero-based index of the call +/// which resulted in an error, the error type and the error message. If an +/// error occurred, the values from all preceding calls will still be returned. +Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *err) + FUNC_API_SINCE(1) FUNC_API_DEPRECATED_SINCE(12) FUNC_API_REMOTE_ONLY +{ + Array rv = arena_array(arena, 2); + Array results = arena_array(arena, calls.size); + Error nested_error = ERROR_INIT; + + size_t i; // also used for freeing the variables + for (i = 0; i < calls.size; i++) { + VALIDATE_T("'calls' item", kObjectTypeArray, calls.items[i].type, { + goto theend; + }); + Array call = calls.items[i].data.array; + VALIDATE_EXP((call.size == 2), "'calls' item", "2-item Array", NULL, { + goto theend; + }); + VALIDATE_T("name", kObjectTypeString, call.items[0].type, { + goto theend; + }); + String name = call.items[0].data.string; + VALIDATE_T("call args", kObjectTypeArray, call.items[1].type, { + goto theend; + }); + Array args = call.items[1].data.array; + + MsgpackRpcRequestHandler handler = + msgpack_rpc_get_handler_for(name.data, + name.size, + &nested_error); + + if (ERROR_SET(&nested_error)) { + break; + } + + Object result = handler.fn(channel_id, args, arena, &nested_error); + if (ERROR_SET(&nested_error)) { + // error handled after loop + break; + } + // TODO(bfredl): wasteful copy. It could be avoided to encoding to msgpack + // directly here. But `result` might become invalid when next api function + // is called in the loop. + ADD_C(results, copy_object(result, arena)); + if (handler.ret_alloc) { + api_free_object(result); + } + } + + ADD_C(rv, ARRAY_OBJ(results)); + if (ERROR_SET(&nested_error)) { + Array errval = arena_array(arena, 3); + ADD_C(errval, INTEGER_OBJ((Integer)i)); + ADD_C(errval, INTEGER_OBJ(nested_error.type)); + ADD_C(errval, STRING_OBJ(copy_string(cstr_as_string(nested_error.msg), arena))); + ADD_C(rv, ARRAY_OBJ(errval)); + } else { + ADD_C(rv, NIL); + } + +theend: + api_clear_error(&nested_error); + return rv; +} + +/// @deprecated +/// +/// @param channel_id Channel id (passed automatically by the dispatcher) +/// @param event Event type string +void nvim_subscribe(uint64_t channel_id, String event) + FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY +{ + // Does nothing. `rpcnotify(0,…)` broadcasts to all channels, there are no "subscriptions". +} + +/// @deprecated +/// +/// @param channel_id Channel id (passed automatically by the dispatcher) +/// @param event Event type string +void nvim_unsubscribe(uint64_t channel_id, String event) + FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY +{ + // Does nothing. `rpcnotify(0,…)` broadcasts to all channels, there are no "subscriptions". +} diff --git a/src/nvim/api/extmark.c b/src/nvim/api/extmark.c index 1b03a97edb..85cce45560 100644 --- a/src/nvim/api/extmark.c +++ b/src/nvim/api/extmark.c @@ -121,7 +121,7 @@ Array virt_text_to_array(VirtText vt, bool hl_name, Arena *arena) Array hl_array = arena_array(arena, i < j ? j - i + 1 : 0); for (; i < j; i++) { int hl_id = kv_A(vt, i).hl_id; - if (hl_id > 0) { + if (hl_id >= 0) { ADD_C(hl_array, hl_group_name(hl_id, hl_name)); } } @@ -131,11 +131,11 @@ Array virt_text_to_array(VirtText vt, bool hl_name, Arena *arena) Array chunk = arena_array(arena, 2); ADD_C(chunk, CSTR_AS_OBJ(text)); if (hl_array.size > 0) { - if (hl_id > 0) { + if (hl_id >= 0) { ADD_C(hl_array, hl_group_name(hl_id, hl_name)); } ADD_C(chunk, ARRAY_OBJ(hl_array)); - } else if (hl_id > 0) { + } else if (hl_id >= 0) { ADD_C(chunk, hl_group_name(hl_id, hl_name)); } ADD_C(chunks, ARRAY_OBJ(chunk)); @@ -489,8 +489,8 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// used together with virt_text. /// - url: A URL to associate with this extmark. In the TUI, the OSC 8 control /// sequence is used to generate a clickable hyperlink to this URL. -/// - scoped: boolean that indicates that the extmark should only be -/// displayed in the namespace scope. (experimental) +/// - scoped: boolean (EXPERIMENTAL) enables "scoping" for the extmark. See +/// |nvim__win_add_ns()| /// /// @param[out] err Error details, if any /// @return Id of the created/updated extmark @@ -682,7 +682,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer goto error; }); - size_t len = 0; + colnr_T len = 0; if (HAS_KEY(opts, set_extmark, spell)) { hl.flags |= (opts->spell) ? kSHSpellOn : kSHSpellOff; @@ -712,16 +712,16 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer }); line = buf->b_ml.ml_line_count; } else if (line < buf->b_ml.ml_line_count) { - len = opts->ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line + 1)); + len = opts->ephemeral ? MAXCOL : ml_get_buf_len(buf, (linenr_T)line + 1); } if (col == -1) { - col = (Integer)len; - } else if (col > (Integer)len) { + col = len; + } else if (col > len) { VALIDATE_RANGE(!strict, "col", { goto error; }); - col = (Integer)len; + col = len; } else if (col < -1) { VALIDATE_RANGE(false, "col", { goto error; @@ -730,7 +730,7 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer if (col2 >= 0) { if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) { - len = opts->ephemeral ? MAXCOL : strlen(ml_get_buf(buf, (linenr_T)line2 + 1)); + len = opts->ephemeral ? MAXCOL : ml_get_buf_len(buf, (linenr_T)line2 + 1); } else if (line2 == buf->b_ml.ml_line_count) { // We are trying to add an extmark past final newline len = 0; @@ -738,11 +738,11 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer // reuse len from before line2 = (int)line; } - if (col2 > (Integer)len) { + if (col2 > len) { VALIDATE_RANGE(!strict, "end_col", { goto error; }); - col2 = (int)len; + col2 = len; } } else if (line2 >= 0) { col2 = 0; @@ -761,32 +761,20 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer col2 = c; } - DecorPriority subpriority = DECOR_PRIORITY_BASE; - if (HAS_KEY(opts, set_extmark, _subpriority)) { - VALIDATE_RANGE((opts->_subpriority >= 0 && opts->_subpriority <= UINT16_MAX), - "_subpriority", { - goto error; - }); - subpriority = (DecorPriority)opts->_subpriority; - } - if (kv_size(virt_text.data.virt_text)) { - decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_text, NULL), true, - subpriority); + decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_text, NULL), true); } if (kv_size(virt_lines.data.virt_lines)) { - decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true, - subpriority); + decor_range_add_virt(&decor_state, r, c, line2, col2, decor_put_vt(virt_lines, NULL), true); } if (url != NULL) { DecorSignHighlight sh = DECOR_SIGN_HIGHLIGHT_INIT; sh.url = url; - decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, 0, 0, subpriority); + decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, 0, 0); } if (has_hl) { DecorSignHighlight sh = decor_sh_from_inline(hl); - decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id, - subpriority); + decor_range_add_sh(&decor_state, r, c, line2, col2, &sh, true, (uint32_t)ns_id, id); } } else { if (opts->ephemeral) { @@ -1177,7 +1165,7 @@ VirtText parse_virt_text(Array chunks, Error *err, int *width) String str = chunk.items[0].data.string; - int hl_id = 0; + int hl_id = -1; if (chunk.size == 2) { Object hl = chunk.items[1]; if (hl.type == kObjectTypeArray) { @@ -1227,13 +1215,15 @@ String nvim__buf_debug_extmarks(Buffer buffer, Boolean keys, Boolean dot, Error return mt_inspect(buf->b_marktree, keys, dot); } -/// Adds the namespace scope to the window. +/// EXPERIMENTAL: this API will change in the future. +/// +/// Scopes a namespace to the a window, so extmarks in the namespace will be active only in the +/// given window. /// /// @param window Window handle, or 0 for current window -/// @param ns_id the namespace to add +/// @param ns_id Namespace /// @return true if the namespace was added, else false -Boolean nvim_win_add_ns(Window window, Integer ns_id, Error *err) - FUNC_API_SINCE(12) +Boolean nvim__win_add_ns(Window window, Integer ns_id, Error *err) { win_T *win = find_window_by_handle(window, err); if (!win) { @@ -1246,17 +1236,20 @@ Boolean nvim_win_add_ns(Window window, Integer ns_id, Error *err) set_put(uint32_t, &win->w_ns_set, (uint32_t)ns_id); - changed_window_setting_win(win); + if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(win); + } return true; } -/// Gets all the namespaces scopes associated with a window. +/// EXPERIMENTAL: this API will change in the future. +/// +/// Gets the namespace scopes for a given window. /// /// @param window Window handle, or 0 for current window /// @return a list of namespaces ids -ArrayOf(Integer) nvim_win_get_ns(Window window, Arena *arena, Error *err) - FUNC_API_SINCE(12) +ArrayOf(Integer) nvim__win_get_ns(Window window, Arena *arena, Error *err) { win_T *win = find_window_by_handle(window, err); if (!win) { @@ -1272,13 +1265,14 @@ ArrayOf(Integer) nvim_win_get_ns(Window window, Arena *arena, Error *err) return rv; } -/// Removes the namespace scope from the window. +/// EXPERIMENTAL: this API will change in the future. +/// +/// Unscopes a namespace (un-binds it from the given scope). /// /// @param window Window handle, or 0 for current window /// @param ns_id the namespace to remove /// @return true if the namespace was removed, else false -Boolean nvim_win_remove_ns(Window window, Integer ns_id, Error *err) - FUNC_API_SINCE(12) +Boolean nvim__win_del_ns(Window window, Integer ns_id, Error *err) { win_T *win = find_window_by_handle(window, err); if (!win) { @@ -1291,7 +1285,9 @@ Boolean nvim_win_remove_ns(Window window, Integer ns_id, Error *err) set_del(uint32_t, &win->w_ns_set, (uint32_t)ns_id); - changed_window_setting_win(win); + if (map_has(uint32_t, win->w_buffer->b_extmark_ns, (uint32_t)ns_id)) { + changed_window_setting(win); + } return true; } diff --git a/src/nvim/api/keysets_defs.h b/src/nvim/api/keysets_defs.h index fe91d9760d..00d8aa8428 100644 --- a/src/nvim/api/keysets_defs.h +++ b/src/nvim/api/keysets_defs.h @@ -56,8 +56,6 @@ typedef struct { Boolean undo_restore; String url; Boolean scoped; - - Integer _subpriority; } Dict(set_extmark); typedef struct { @@ -375,3 +373,17 @@ typedef struct { Boolean ignore_blank_lines; Boolean indent_heuristic; } Dict(xdl_diff); + +typedef struct { + OptionalKeys is_set__redraw_; + Boolean flush; + Boolean cursor; + Boolean valid; + Boolean statuscolumn; + Boolean statusline; + Boolean tabline; + Boolean winbar; + Array range; + Window win; + Buffer buf; +} Dict(redraw); diff --git a/src/nvim/api/private/converter.c b/src/nvim/api/private/converter.c index a70ef1e50b..a78d78c057 100644 --- a/src/nvim/api/private/converter.c +++ b/src/nvim/api/private/converter.c @@ -76,8 +76,7 @@ static Object typval_cbuf_to_obj(EncodedData *edata, const char *data, size_t le do { \ ufunc_T *fp = find_func(fun); \ if (fp != NULL && (fp->uf_flags & FC_LUAREF)) { \ - LuaRef ref = api_new_luaref(fp->uf_luaref); \ - kvi_push(edata->stack, LUAREF_OBJ(ref)); \ + kvi_push(edata->stack, LUAREF_OBJ(api_new_luaref(fp->uf_luaref))); \ } else { \ TYPVAL_ENCODE_CONV_NIL(tv); \ } \ diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 1cd98aa0c4..a17e78cc31 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -524,10 +524,10 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col } char *bufstr = ml_get_buf(buf, (linenr_T)lnum); - size_t line_length = strlen(bufstr); + colnr_T line_length = ml_get_buf_len(buf, (linenr_T)lnum); - start_col = start_col < 0 ? (int64_t)line_length + start_col + 1 : start_col; - end_col = end_col < 0 ? (int64_t)line_length + end_col + 1 : end_col; + start_col = start_col < 0 ? line_length + start_col + 1 : start_col; + end_col = end_col < 0 ? line_length + end_col + 1 : end_col; if (start_col >= MAXCOL || end_col >= MAXCOL) { api_set_error(err, kErrorTypeValidation, "Column index is too high"); @@ -539,7 +539,7 @@ String buf_get_text(buf_T *buf, int64_t lnum, int64_t start_col, int64_t end_col return rv; } - if ((size_t)start_col >= line_length) { + if (start_col >= line_length) { return rv; } diff --git a/src/nvim/api/tabpage.c b/src/nvim/api/tabpage.c index 040abb1e3f..56a3f1cf23 100644 --- a/src/nvim/api/tabpage.c +++ b/src/nvim/api/tabpage.c @@ -146,7 +146,11 @@ void nvim_tabpage_set_win(Tabpage tabpage, Window win, Error *err) } if (tp == curtab) { - win_enter(wp, true); + try_start(); + win_goto(wp); + if (!try_end(err) && curwin != wp) { + api_set_error(err, kErrorTypeException, "Failed to switch to window %d", win); + } } else if (tp->tp_curwin != wp) { tp->tp_prevwin = tp->tp_curwin; tp->tp_curwin = wp; diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 692e3f95fc..fdf25c75d7 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -67,7 +67,6 @@ static void mpack_str_small(char **buf, const char *str, size_t len) static void remote_ui_destroy(RemoteUI *ui) FUNC_ATTR_NONNULL_ALL { - kv_destroy(ui->call_buf); xfree(ui->packer.startptr); XFREE_CLEAR(ui->term_name); xfree(ui); @@ -190,8 +189,6 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona .anydata = ui, }; ui->wildmenu_active = false; - ui->call_buf = (Array)ARRAY_DICT_INIT; - kv_ensure_space(ui->call_buf, 16); pmap_put(uint64_t)(&connected_uis, channel_id, ui); ui_attach_impl(ui, channel_id); @@ -533,7 +530,8 @@ static void ui_alloc_buf(RemoteUI *ui) static void prepare_call(RemoteUI *ui, const char *name) { - if (ui->packer.startptr && BUF_POS(ui) > UI_BUF_SIZE - EVENT_BUF_SIZE) { + if (ui->packer.startptr + && (BUF_POS(ui) > UI_BUF_SIZE - EVENT_BUF_SIZE || ui->ncells_pending >= 500)) { ui_flush_buf(ui); } @@ -582,7 +580,7 @@ static void ui_flush_callback(PackerBuffer *packer) void remote_ui_grid_clear(RemoteUI *ui, Integer grid) { - Array args = ui->call_buf; + MAXSIZE_TEMP_ARRAY(args, 1); if (ui->ui_ext[kUILinegrid]) { ADD_C(args, INTEGER_OBJ(grid)); } @@ -592,7 +590,7 @@ void remote_ui_grid_clear(RemoteUI *ui, Integer grid) void remote_ui_grid_resize(RemoteUI *ui, Integer grid, Integer width, Integer height) { - Array args = ui->call_buf; + MAXSIZE_TEMP_ARRAY(args, 3); if (ui->ui_ext[kUILinegrid]) { ADD_C(args, INTEGER_OBJ(grid)); } else { @@ -608,7 +606,7 @@ void remote_ui_grid_scroll(RemoteUI *ui, Integer grid, Integer top, Integer bot, Integer right, Integer rows, Integer cols) { if (ui->ui_ext[kUILinegrid]) { - Array args = ui->call_buf; + MAXSIZE_TEMP_ARRAY(args, 7); ADD_C(args, INTEGER_OBJ(grid)); ADD_C(args, INTEGER_OBJ(top)); ADD_C(args, INTEGER_OBJ(bot)); @@ -618,20 +616,19 @@ void remote_ui_grid_scroll(RemoteUI *ui, Integer grid, Integer top, Integer bot, ADD_C(args, INTEGER_OBJ(cols)); push_call(ui, "grid_scroll", args); } else { - Array args = ui->call_buf; + MAXSIZE_TEMP_ARRAY(args, 4); ADD_C(args, INTEGER_OBJ(top)); ADD_C(args, INTEGER_OBJ(bot - 1)); ADD_C(args, INTEGER_OBJ(left)); ADD_C(args, INTEGER_OBJ(right - 1)); push_call(ui, "set_scroll_region", args); - args = ui->call_buf; + kv_size(args) = 0; ADD_C(args, INTEGER_OBJ(rows)); push_call(ui, "scroll", args); - // some clients have "clear" being affected by scroll region, - // so reset it. - args = ui->call_buf; + // some clients have "clear" being affected by scroll region, so reset it. + kv_size(args) = 0; ADD_C(args, INTEGER_OBJ(0)); ADD_C(args, INTEGER_OBJ(ui->height - 1)); ADD_C(args, INTEGER_OBJ(0)); @@ -646,7 +643,7 @@ void remote_ui_default_colors_set(RemoteUI *ui, Integer rgb_fg, Integer rgb_bg, if (!ui->ui_ext[kUITermColors]) { HL_SET_DEFAULT_COLORS(rgb_fg, rgb_bg, rgb_sp); } - Array args = ui->call_buf; + MAXSIZE_TEMP_ARRAY(args, 5); ADD_C(args, INTEGER_OBJ(rgb_fg)); ADD_C(args, INTEGER_OBJ(rgb_bg)); ADD_C(args, INTEGER_OBJ(rgb_sp)); @@ -656,15 +653,15 @@ void remote_ui_default_colors_set(RemoteUI *ui, Integer rgb_fg, Integer rgb_bg, // Deprecated if (!ui->ui_ext[kUILinegrid]) { - args = ui->call_buf; + kv_size(args) = 0; ADD_C(args, INTEGER_OBJ(ui->rgb ? rgb_fg : cterm_fg - 1)); push_call(ui, "update_fg", args); - args = ui->call_buf; + kv_size(args) = 0; ADD_C(args, INTEGER_OBJ(ui->rgb ? rgb_bg : cterm_bg - 1)); push_call(ui, "update_bg", args); - args = ui->call_buf; + kv_size(args) = 0; ADD_C(args, INTEGER_OBJ(ui->rgb ? rgb_sp : -1)); push_call(ui, "update_sp", args); } @@ -677,7 +674,7 @@ void remote_ui_hl_attr_define(RemoteUI *ui, Integer id, HlAttrs rgb_attrs, HlAtt return; } - Array args = ui->call_buf; + MAXSIZE_TEMP_ARRAY(args, 4); ADD_C(args, INTEGER_OBJ(id)); MAXSIZE_TEMP_DICT(rgb, HLATTRS_DICT_SIZE); MAXSIZE_TEMP_DICT(cterm, HLATTRS_DICT_SIZE); @@ -705,14 +702,14 @@ void remote_ui_hl_attr_define(RemoteUI *ui, Integer id, HlAttrs rgb_attrs, HlAtt void remote_ui_highlight_set(RemoteUI *ui, int id) { - Array args = ui->call_buf; - if (ui->hl_id == id) { return; } + ui->hl_id = id; MAXSIZE_TEMP_DICT(dict, HLATTRS_DICT_SIZE); hlattrs2dict(&dict, NULL, syn_attr2entry(id), ui->rgb, false); + MAXSIZE_TEMP_ARRAY(args, 1); ADD_C(args, DICTIONARY_OBJ(dict)); push_call(ui, "highlight_set", args); } @@ -721,7 +718,7 @@ void remote_ui_highlight_set(RemoteUI *ui, int id) void remote_ui_grid_cursor_goto(RemoteUI *ui, Integer grid, Integer row, Integer col) { if (ui->ui_ext[kUILinegrid]) { - Array args = ui->call_buf; + MAXSIZE_TEMP_ARRAY(args, 3); ADD_C(args, INTEGER_OBJ(grid)); ADD_C(args, INTEGER_OBJ(row)); ADD_C(args, INTEGER_OBJ(col)); @@ -741,7 +738,7 @@ void remote_ui_cursor_goto(RemoteUI *ui, Integer row, Integer col) } ui->client_row = row; ui->client_col = col; - Array args = ui->call_buf; + MAXSIZE_TEMP_ARRAY(args, 2); ADD_C(args, INTEGER_OBJ(row)); ADD_C(args, INTEGER_OBJ(col)); push_call(ui, "cursor_goto", args); @@ -750,7 +747,7 @@ void remote_ui_cursor_goto(RemoteUI *ui, Integer row, Integer col) void remote_ui_put(RemoteUI *ui, const char *cell) { ui->client_col++; - Array args = ui->call_buf; + MAXSIZE_TEMP_ARRAY(args, 1); ADD_C(args, CSTR_AS_OBJ(cell)); push_call(ui, "put", args); } @@ -781,11 +778,14 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco for (size_t i = 0; i < ncells; i++) { repeat++; if (i == ncells - 1 || attrs[i] != attrs[i + 1] || chunk[i] != chunk[i + 1]) { - if (UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + sizeof(schar_T) + 5 + 5) + 1) { + if (UI_BUF_SIZE - BUF_POS(ui) < 2 * (1 + 2 + MAX_SCHAR_SIZE + 5 + 5) + 1 + || ui->ncells_pending >= 500) { // close to overflowing the redraw buffer. finish this event, // flush, and start a new "grid_line" event at the current position. // For simplicity leave place for the final "clear" element // as well, hence the factor of 2 in the check. + // Also if there is a lot of packed cells, pass them of to the UI to + // let it start processing them mpack_w2(&lenpos, nelem); // We only ever set the wrap field on the final "grid_line" event for the line. @@ -831,11 +831,6 @@ void remote_ui_raw_line(RemoteUI *ui, Integer grid, Integer row, Integer startco } mpack_w2(&lenpos, nelem); mpack_bool(buf, flags & kLineFlagWrap); - - if (ui->ncells_pending > 500) { - // pass off cells to UI to let it start processing them - ui_flush_buf(ui); - } } else { for (int i = 0; i < endcol - startcol; i++) { remote_ui_cursor_goto(ui, row, startcol + i); @@ -951,12 +946,12 @@ void remote_ui_event(RemoteUI *ui, char *name, Array args) push_call(ui, name, new_args); goto free_ret; } else if (strequal(name, "cmdline_block_show")) { - Array new_args = ui->call_buf; Array block = args.items[0].data.array; Array new_block = arena_array(&arena, block.size); for (size_t i = 0; i < block.size; i++) { ADD_C(new_block, ARRAY_OBJ(translate_contents(ui, block.items[i].data.array, &arena))); } + MAXSIZE_TEMP_ARRAY(new_args, 1); ADD_C(new_args, ARRAY_OBJ(new_block)); push_call(ui, name, new_args); goto free_ret; @@ -973,18 +968,18 @@ void remote_ui_event(RemoteUI *ui, char *name, Array args) ui->wildmenu_active = (args.items[4].data.integer == -1) || !ui->ui_ext[kUIPopupmenu]; if (ui->wildmenu_active) { - Array new_args = ui->call_buf; Array items = args.items[0].data.array; Array new_items = arena_array(&arena, items.size); for (size_t i = 0; i < items.size; i++) { ADD_C(new_items, items.items[i].data.array.items[0]); } + MAXSIZE_TEMP_ARRAY(new_args, 1); ADD_C(new_args, ARRAY_OBJ(new_items)); push_call(ui, "wildmenu_show", new_args); if (args.items[1].data.integer != -1) { - Array new_args2 = ui->call_buf; - ADD_C(new_args2, args.items[1]); - push_call(ui, "wildmenu_select", new_args2); + kv_size(new_args) = 0; + ADD_C(new_args, args.items[1]); + push_call(ui, "wildmenu_select", new_args); } goto free_ret; } diff --git a/src/nvim/api/ui_events.in.h b/src/nvim/api/ui_events.in.h index c2f02c34f8..2bd8792d71 100644 --- a/src/nvim/api/ui_events.in.h +++ b/src/nvim/api/ui_events.in.h @@ -118,6 +118,10 @@ void win_viewport(Integer grid, Window win, Integer topline, Integer botline, In Integer curcol, Integer line_count, Integer scroll_delta) FUNC_API_SINCE(7) FUNC_API_CLIENT_IGNORE; +void win_viewport_margins(Integer grid, Window win, Integer top, Integer bottom, Integer left, + Integer right) + FUNC_API_SINCE(12) FUNC_API_CLIENT_IGNORE; + void win_extmark(Integer grid, Window win, Integer ns_id, Integer mark_id, Integer row, Integer col) FUNC_API_SINCE(10) FUNC_API_REMOTE_ONLY; diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 84a2f24dbc..fc780e1248 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -45,10 +45,12 @@ #include "nvim/keycodes.h" #include "nvim/log.h" #include "nvim/lua/executor.h" +#include "nvim/lua/treesitter.h" #include "nvim/macros_defs.h" #include "nvim/mapping.h" #include "nvim/mark.h" #include "nvim/mark_defs.h" +#include "nvim/math.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memory.h" @@ -167,7 +169,7 @@ Dictionary nvim_get_hl(Integer ns_id, Dict(get_highlight) *opts, Arena *arena, E /// @param[out] err Error details, if any /// // TODO(bfredl): val should take update vs reset flag -void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) +void nvim_set_hl(uint64_t channel_id, Integer ns_id, String name, Dict(highlight) *val, Error *err) FUNC_API_SINCE(7) { int hl_id = syn_check_group(name.data, name.size); @@ -184,7 +186,9 @@ void nvim_set_hl(Integer ns_id, String name, Dict(highlight) *val, Error *err) HlAttrs attrs = dict2hlattrs(val, true, &link_id, err); if (!ERROR_SET(err)) { - ns_hl_def((NS)ns_id, hl_id, attrs, link_id, val); + WITH_SCRIPT_CONTEXT(channel_id, { + ns_hl_def((NS)ns_id, hl_id, attrs, link_id, val); + }); } } @@ -275,6 +279,7 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) bool typed = false; bool execute = false; bool dangerous = false; + bool lowlevel = false; for (size_t i = 0; i < mode.size; i++) { switch (mode.data[i]) { @@ -290,6 +295,8 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) execute = true; break; case '!': dangerous = true; break; + case 'L': + lowlevel = true; break; } } @@ -305,10 +312,14 @@ void nvim_feedkeys(String keys, String mode, Boolean escape_ks) } else { keys_esc = keys.data; } - ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), - insert ? 0 : typebuf.tb_len, !typed, false); - if (vgetc_busy) { - typebuf_was_filled = true; + if (lowlevel) { + input_enqueue_raw(cstr_as_string(keys_esc)); + } else { + ins_typebuf(keys_esc, (remap ? REMAP_YES : REMAP_NONE), + insert ? 0 : typebuf.tb_len, !typed, false); + if (vgetc_busy) { + typebuf_was_filled = true; + } } if (escape_ks) { @@ -876,6 +887,11 @@ void nvim_set_current_buf(Buffer buffer, Error *err) return; } + if (curwin->w_p_wfb) { + api_set_error(err, kErrorTypeException, "%s", e_winfixbuf_cannot_go_to_buffer); + return; + } + try_start(); int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0); if (!try_end(err) && result == FAIL) { @@ -953,21 +969,21 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) FUNC_API_SINCE(6) { try_start(); + // Block autocommands for now so they don't mess with the buffer before we + // finish configuring it. + block_autocmds(); + buf_T *buf = buflist_new(NULL, NULL, 0, BLN_NOOPT | BLN_NEW | (listed ? BLN_LISTED : 0)); - try_end(err); if (buf == NULL) { + unblock_autocmds(); goto fail; } // Open the memline for the buffer. This will avoid spurious autocmds when // a later nvim_buf_set_lines call would have needed to "open" the buffer. - try_start(); - block_autocmds(); - int status = ml_open(buf); - unblock_autocmds(); - try_end(err); - if (status == FAIL) { + if (ml_open(buf) == FAIL) { + unblock_autocmds(); goto fail; } @@ -978,21 +994,39 @@ Buffer nvim_create_buf(Boolean listed, Boolean scratch, Error *err) buf->b_last_changedtick_pum = buf_get_changedtick(buf); // Only strictly needed for scratch, but could just as well be consistent - // and do this now. buffer is created NOW, not when it latter first happen + // and do this now. Buffer is created NOW, not when it later first happens // to reach a window or aucmd_prepbuf() .. buf_copy_options(buf, BCO_ENTER | BCO_NOHELP); if (scratch) { - set_string_option_direct_in_buf(buf, kOptBufhidden, "hide", OPT_LOCAL, 0); - set_string_option_direct_in_buf(buf, kOptBuftype, "nofile", OPT_LOCAL, 0); + set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("hide"), OPT_LOCAL, 0, kOptReqBuf, + buf); + set_option_direct_for(kOptBuftype, STATIC_CSTR_AS_OPTVAL("nofile"), OPT_LOCAL, 0, kOptReqBuf, + buf); assert(buf->b_ml.ml_mfp->mf_fd < 0); // ml_open() should not have opened swapfile already buf->b_p_swf = false; buf->b_p_ml = false; } + + unblock_autocmds(); + + bufref_T bufref; + set_bufref(&bufref, buf); + if (apply_autocmds(EVENT_BUFNEW, NULL, NULL, false, buf) + && !bufref_valid(&bufref)) { + goto fail; + } + if (listed + && apply_autocmds(EVENT_BUFADD, NULL, NULL, false, buf) + && !bufref_valid(&bufref)) { + goto fail; + } + + try_end(err); return buf->b_fnum; fail: - if (!ERROR_SET(err)) { + if (!try_end(err)) { api_set_error(err, kErrorTypeException, "Failed to create buffer"); } return 0; @@ -1300,36 +1334,6 @@ void nvim_put(ArrayOf(String) lines, String type, Boolean after, Boolean follow, }); } -/// Subscribes to event broadcasts. -/// -/// @param channel_id Channel id (passed automatically by the dispatcher) -/// @param event Event type string -void nvim_subscribe(uint64_t channel_id, String event) - FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY -{ - size_t length = (event.size < METHOD_MAXLEN ? event.size : METHOD_MAXLEN); - char e[METHOD_MAXLEN + 1]; - memcpy(e, event.data, length); - e[length] = NUL; - rpc_subscribe(channel_id, e); -} - -/// Unsubscribes to event broadcasts. -/// -/// @param channel_id Channel id (passed automatically by the dispatcher) -/// @param event Event type string -void nvim_unsubscribe(uint64_t channel_id, String event) - FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY -{ - size_t length = (event.size < METHOD_MAXLEN - ? event.size - : METHOD_MAXLEN); - char e[METHOD_MAXLEN + 1]; - memcpy(e, event.data, length); - e[length] = NUL; - rpc_unsubscribe(channel_id, e); -} - /// Returns the 24-bit RGB value of a |nvim_get_color_map()| color name or /// "#rrggbb" hexadecimal string. /// @@ -1666,90 +1670,6 @@ Array nvim_list_chans(Arena *arena) return channel_all_info(arena); } -/// Calls many API methods atomically. -/// -/// This has two main usages: -/// 1. To perform several requests from an async context atomically, i.e. -/// without interleaving redraws, RPC requests from other clients, or user -/// interactions (however API methods may trigger autocommands or event -/// processing which have such side effects, e.g. |:sleep| may wake timers). -/// 2. To minimize RPC overhead (roundtrips) of a sequence of many requests. -/// -/// @param channel_id -/// @param calls an array of calls, where each call is described by an array -/// with two elements: the request name, and an array of arguments. -/// @param[out] err Validation error details (malformed `calls` parameter), -/// if any. Errors from batched calls are given in the return value. -/// -/// @return Array of two elements. The first is an array of return -/// values. The second is NIL if all calls succeeded. If a call resulted in -/// an error, it is a three-element array with the zero-based index of the call -/// which resulted in an error, the error type and the error message. If an -/// error occurred, the values from all preceding calls will still be returned. -Array nvim_call_atomic(uint64_t channel_id, Array calls, Arena *arena, Error *err) - FUNC_API_SINCE(1) FUNC_API_REMOTE_ONLY -{ - Array rv = arena_array(arena, 2); - Array results = arena_array(arena, calls.size); - Error nested_error = ERROR_INIT; - - size_t i; // also used for freeing the variables - for (i = 0; i < calls.size; i++) { - VALIDATE_T("'calls' item", kObjectTypeArray, calls.items[i].type, { - goto theend; - }); - Array call = calls.items[i].data.array; - VALIDATE_EXP((call.size == 2), "'calls' item", "2-item Array", NULL, { - goto theend; - }); - VALIDATE_T("name", kObjectTypeString, call.items[0].type, { - goto theend; - }); - String name = call.items[0].data.string; - VALIDATE_T("call args", kObjectTypeArray, call.items[1].type, { - goto theend; - }); - Array args = call.items[1].data.array; - - MsgpackRpcRequestHandler handler = - msgpack_rpc_get_handler_for(name.data, - name.size, - &nested_error); - - if (ERROR_SET(&nested_error)) { - break; - } - - Object result = handler.fn(channel_id, args, arena, &nested_error); - if (ERROR_SET(&nested_error)) { - // error handled after loop - break; - } - // TODO(bfredl): wasteful copy. It could be avoided to encoding to msgpack - // directly here. But `result` might become invalid when next api function - // is called in the loop. - ADD_C(results, copy_object(result, arena)); - if (handler.ret_alloc) { - api_free_object(result); - } - } - - ADD_C(rv, ARRAY_OBJ(results)); - if (ERROR_SET(&nested_error)) { - Array errval = arena_array(arena, 3); - ADD_C(errval, INTEGER_OBJ((Integer)i)); - ADD_C(errval, INTEGER_OBJ(nested_error.type)); - ADD_C(errval, STRING_OBJ(copy_string(cstr_as_string(nested_error.msg), arena))); - ADD_C(rv, ARRAY_OBJ(errval)); - } else { - ADD_C(rv, NIL); - } - -theend: - api_clear_error(&nested_error); - return rv; -} - /// Writes a message to vim output or error buffer. The string is split /// and flushed after each newline. Incomplete lines are kept for writing /// later. @@ -1858,12 +1778,13 @@ Float nvim__id_float(Float flt) /// @return Map of various internal stats. Dictionary nvim__stats(Arena *arena) { - Dictionary rv = arena_dict(arena, 5); + Dictionary rv = arena_dict(arena, 6); PUT_C(rv, "fsync", INTEGER_OBJ(g_stats.fsync)); PUT_C(rv, "log_skip", INTEGER_OBJ(g_stats.log_skip)); PUT_C(rv, "lua_refcount", INTEGER_OBJ(nlua_get_global_ref_count())); PUT_C(rv, "redraw", INTEGER_OBJ(g_stats.redraw)); PUT_C(rv, "arena_alloc_count", INTEGER_OBJ((Integer)arena_alloc_count)); + PUT_C(rv, "ts_query_parse_count", INTEGER_OBJ((Integer)tslua_query_parse_count)); return rv; } @@ -2332,20 +2253,18 @@ void nvim_error_event(uint64_t channel_id, Integer lvl, String data) ELOG("async error on channel %" PRId64 ": %s", channel_id, data.size ? data.data : ""); } -/// Set info for the completion candidate index. -/// if the info was shown in a window, then the -/// window and buffer ids are returned for further -/// customization. If the text was not shown, an -/// empty dict is returned. +/// EXPERIMENTAL: this API may change in the future. /// -/// @param index the completion candidate index +/// Sets info for the completion item at the given index. If the info text was shown in a window, +/// returns the window and buffer ids, or empty dict if not shown. +/// +/// @param index Completion candidate index /// @param opts Optional parameters. /// - info: (string) info text. /// @return Dictionary containing these keys: /// - winid: (number) floating window id /// - bufnr: (number) buffer id in floating window -Dictionary nvim_complete_set(Integer index, Dict(complete_set) *opts, Arena *arena) - FUNC_API_SINCE(12) +Dictionary nvim__complete_set(Integer index, Dict(complete_set) *opts, Arena *arena) { Dictionary rv = arena_dict(arena, 2); if (HAS_KEY(opts, complete_set, info)) { @@ -2357,3 +2276,159 @@ Dictionary nvim_complete_set(Integer index, Dict(complete_set) *opts, Arena *are } return rv; } + +static void redraw_status(win_T *wp, Dict(redraw) *opts, bool *flush) +{ + if (opts->statuscolumn && *wp->w_p_stc != NUL) { + wp->w_nrwidth_line_count = 0; + changed_window_setting(wp); + } + win_grid_alloc(wp); + + // Flush later in case winbar was just hidden or shown for the first time, or + // statuscolumn is being drawn. + if (wp->w_lines_valid == 0) { + *flush = true; + } + + // Mark for redraw in case flush will happen, otherwise redraw now. + if (*flush && (opts->statusline || opts->winbar)) { + wp->w_redr_status = true; + } else if (opts->statusline || opts->winbar) { + win_check_ns_hl(wp); + if (opts->winbar) { + win_redr_winbar(wp); + } + if (opts->statusline) { + win_redr_status(wp); + } + win_check_ns_hl(NULL); + } +} + +/// EXPERIMENTAL: this API may change in the future. +/// +/// Instruct Nvim to redraw various components. +/// +/// @see |:redraw| +/// +/// @param opts Optional parameters. +/// - win: Target a specific |window-ID| as described below. +/// - buf: Target a specific buffer number as described below. +/// - flush: Update the screen with pending updates. +/// - valid: When present mark `win`, `buf`, or all windows for +/// redraw. When `true`, only redraw changed lines (useful for +/// decoration providers). When `false`, forcefully redraw. +/// - range: Redraw a range in `buf`, the buffer in `win` or the +/// current buffer (useful for decoration providers). Expects a +/// tuple `[first, last]` with the first and last line number +/// of the range, 0-based end-exclusive |api-indexing|. +/// - cursor: Immediately update cursor position on the screen in +/// `win` or the current window. +/// - statuscolumn: Redraw the 'statuscolumn' in `buf`, `win` or +/// all windows. +/// - statusline: Redraw the 'statusline' in `buf`, `win` or all +/// windows. +/// - winbar: Redraw the 'winbar' in `buf`, `win` or all windows. +/// - tabline: Redraw the 'tabline'. +void nvim__redraw(Dict(redraw) *opts, Error *err) + FUNC_API_SINCE(12) +{ + win_T *win = NULL; + buf_T *buf = NULL; + + if (HAS_KEY(opts, redraw, win)) { + win = find_window_by_handle(opts->win, err); + if (ERROR_SET(err)) { + return; + } + } + + if (HAS_KEY(opts, redraw, buf)) { + VALIDATE(win == NULL, "%s", "cannot use both 'buf' and 'win'", { + return; + }); + buf = find_buffer_by_handle(opts->buf, err); + if (ERROR_SET(err)) { + return; + } + } + + int count = (win != NULL) + (buf != NULL); + VALIDATE(popcount(opts->is_set__redraw_) > count, "%s", "at least one action required", { + return; + }); + + if (HAS_KEY(opts, redraw, valid)) { + // UPD_VALID redraw type does not actually do anything on it's own. Setting + // it here without scrolling or changing buffer text seems pointless but + // the expectation is that this may be called by decoration providers whose + // "on_win" callback may set "w_redr_top/bot". + int type = opts->valid ? UPD_VALID : UPD_NOT_VALID; + if (win != NULL) { + redraw_later(win, type); + } else if (buf != NULL) { + redraw_buf_later(buf, type); + } else { + redraw_all_later(type); + } + } + + if (HAS_KEY(opts, redraw, range)) { + VALIDATE(kv_size(opts->range) == 2 + && kv_A(opts->range, 0).type == kObjectTypeInteger + && kv_A(opts->range, 1).type == kObjectTypeInteger + && kv_A(opts->range, 0).data.integer >= 0 + && kv_A(opts->range, 1).data.integer >= -1, + "%s", "Invalid 'range': Expected 2-tuple of Integers", { + return; + }); + linenr_T first = (linenr_T)kv_A(opts->range, 0).data.integer + 1; + linenr_T last = (linenr_T)kv_A(opts->range, 1).data.integer; + buf_T *rbuf = win ? win->w_buffer : (buf ? buf : curbuf); + if (last == -1) { + last = rbuf->b_ml.ml_line_count; + } + redraw_buf_range_later(rbuf, first, last); + } + + if (opts->cursor) { + setcursor_mayforce(win ? win : curwin, true); + } + + bool flush = opts->flush; + if (opts->tabline) { + // Flush later in case tabline was just hidden or shown for the first time. + if (redraw_tabline && firstwin->w_lines_valid == 0) { + flush = true; + } else { + draw_tabline(); + } + } + + bool save_lz = p_lz; + int save_rd = RedrawingDisabled; + RedrawingDisabled = 0; + p_lz = false; + if (opts->statuscolumn || opts->statusline || opts->winbar) { + if (win == NULL) { + FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + if (buf == NULL || wp->w_buffer == buf) { + redraw_status(wp, opts, &flush); + } + } + } else { + redraw_status(win, opts, &flush); + } + } + + // Flush pending screen updates if "flush" or "clear" is true, or when + // redrawing a status component may have changed the grid dimensions. + if (flush && !cmdpreview) { + update_screen(); + } + ui_flush(); + + RedrawingDisabled = save_rd; + p_lz = save_lz; +} diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c index 543c7b8113..3a9986a7d1 100644 --- a/src/nvim/api/win_config.c +++ b/src/nvim/api/win_config.c @@ -12,6 +12,7 @@ #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" #include "nvim/autocmd_defs.h" +#include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/decoration.h" #include "nvim/decoration_defs.h" @@ -198,9 +199,8 @@ /// - footer_pos: Footer position. Must be set with `footer` option. /// Value can be one of "left", "center", or "right". /// Default is `"left"`. -/// - noautocmd: If true then no buffer-related autocommand events such as -/// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from -/// calling this function. +/// - noautocmd: If true then all autocommands are blocked for the duration of +/// the call. /// - fixed: If true when anchor is NW or SW, the float window /// would be kept fixed even if the window would be truncated. /// - hide: If true the floating window will be hidden. @@ -224,25 +224,33 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err } WinConfig fconfig = WIN_CONFIG_INIT; - if (!parse_float_config(config, &fconfig, false, true, err)) { + if (!parse_win_config(NULL, config, &fconfig, false, err)) { return 0; } bool is_split = HAS_KEY_X(config, split) || HAS_KEY_X(config, vertical); + Window rv = 0; + if (fconfig.noautocmd) { + block_autocmds(); + } win_T *wp = NULL; tabpage_T *tp = curtab; + win_T *parent = NULL; + if (config->win != -1) { + parent = find_window_by_handle(fconfig.window, err); + if (!parent) { + // find_window_by_handle has already set the error + goto cleanup; + } else if (is_split && parent->w_floating) { + api_set_error(err, kErrorTypeException, "Cannot split a floating window"); + goto cleanup; + } + tp = win_find_tabpage(parent); + } if (is_split) { - win_T *parent = NULL; - if (config->win != -1) { - parent = find_window_by_handle(fconfig.window, err); - if (!parent) { - // find_window_by_handle has already set the error - return 0; - } else if (parent->w_floating) { - api_set_error(err, kErrorTypeException, "Cannot split a floating window"); - return 0; - } + if (!check_split_disallowed_err(parent ? parent : curwin, err)) { + goto cleanup; // error already set } if (HAS_KEY_X(config, vertical) && !HAS_KEY_X(config, split)) { @@ -254,18 +262,20 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err } int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; - if (parent == NULL) { - wp = win_split_ins(0, flags, NULL, 0); - } else { - tp = win_find_tabpage(parent); - switchwin_T switchwin; - // `parent` is valid in `tp`, so switch_win should not fail. - const int result = switch_win(&switchwin, parent, tp, true); - (void)result; - assert(result == OK); - wp = win_split_ins(0, flags, NULL, 0); - restore_win(&switchwin, true); - } + TRY_WRAP(err, { + int size = (flags & WSP_VERT) ? fconfig.width : fconfig.height; + if (parent == NULL || parent == curwin) { + wp = win_split_ins(size, flags, NULL, 0, NULL); + } else { + switchwin_T switchwin; + // `parent` is valid in `tp`, so switch_win should not fail. + const int result = switch_win(&switchwin, parent, tp, true); + assert(result == OK); + (void)result; + wp = win_split_ins(size, flags, NULL, 0, NULL); + restore_win(&switchwin, true); + } + }); if (wp) { wp->w_config = fconfig; } @@ -273,30 +283,64 @@ Window nvim_open_win(Buffer buffer, Boolean enter, Dict(win_config) *config, Err wp = win_new_float(NULL, false, fconfig, err); } if (!wp) { - api_set_error(err, kErrorTypeException, "Failed to create window"); - return 0; + if (!ERROR_SET(err)) { + api_set_error(err, kErrorTypeException, "Failed to create window"); + } + goto cleanup; } - switchwin_T switchwin; - if (switch_win_noblock(&switchwin, wp, tp, true) == OK) { - apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf); + + // Autocommands may close `wp` or move it to another tabpage, so update and check `tp` after each + // event. In each case, `wp` should already be valid in `tp`, so switch_win should not fail. + // Also, autocommands may free the `buf` to switch to, so store a bufref to check. + bufref_T bufref; + set_bufref(&bufref, buf); + if (!fconfig.noautocmd) { + switchwin_T switchwin; + const int result = switch_win_noblock(&switchwin, wp, tp, true); + assert(result == OK); + (void)result; + if (apply_autocmds(EVENT_WINNEW, NULL, NULL, false, curbuf)) { + tp = win_find_tabpage(wp); + } + restore_win_noblock(&switchwin, true); } - restore_win_noblock(&switchwin, true); - if (enter) { + if (tp && enter) { goto_tabpage_win(tp, wp); + tp = win_find_tabpage(wp); } - if (win_valid_any_tab(wp) && buf != wp->w_buffer) { - win_set_buf(wp, buf, !enter || fconfig.noautocmd, err); + if (tp && bufref_valid(&bufref) && buf != wp->w_buffer) { + // win_set_buf temporarily makes `wp` the curwin to set the buffer. + // If not entering `wp`, block Enter and Leave events. (cringe) + const bool au_no_enter_leave = curwin != wp && !fconfig.noautocmd; + if (au_no_enter_leave) { + autocmd_no_enter++; + autocmd_no_leave++; + } + win_set_buf(wp, buf, err); + if (!fconfig.noautocmd) { + tp = win_find_tabpage(wp); + } + if (au_no_enter_leave) { + autocmd_no_enter--; + autocmd_no_leave--; + } } - if (!win_valid_any_tab(wp)) { + if (!tp) { api_set_error(err, kErrorTypeException, "Window was closed immediately"); - return 0; + goto cleanup; } if (fconfig.style == kWinStyleMinimal) { win_set_minimal_style(wp); didset_window_options(wp, true); } - return wp->handle; + rv = wp->handle; + +cleanup: + if (fconfig.noautocmd) { + unblock_autocmds(); + } + return rv; #undef HAS_KEY_X } @@ -330,11 +374,11 @@ static int win_split_flags(WinSplit split, bool toplevel) return flags; } -/// Configures window layout. Currently only for floating and external windows -/// (including changing a split window to those layouts). +/// Configures window layout. Cannot be used to move the last window in a +/// tabpage to a different one. /// -/// When reconfiguring a floating window, absent option keys will not be -/// changed. `row`/`col` and `relative` must be reconfigured together. +/// When reconfiguring a window, absent option keys will not be changed. +/// `row`/`col` and `relative` must be reconfigured together. /// /// @see |nvim_open_win()| /// @@ -350,6 +394,7 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) if (!win) { return; } + tabpage_T *win_tp = win_find_tabpage(win); bool was_split = !win->w_floating; bool has_split = HAS_KEY_X(config, split); @@ -361,26 +406,31 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) && !(HAS_KEY_X(config, external) ? config->external : fconfig.external) && (has_split || has_vertical || was_split); - if (!parse_float_config(config, &fconfig, !was_split || to_split, false, err)) { + if (!parse_win_config(win, config, &fconfig, !was_split || to_split, err)) { return; } + win_T *parent = NULL; + if (config->win != -1) { + parent = find_window_by_handle(fconfig.window, err); + if (!parent) { + return; + } else if (to_split && parent->w_floating) { + api_set_error(err, kErrorTypeException, "Cannot split a floating window"); + return; + } + + // Prevent autocmd window from being moved into another tabpage + if (is_aucmd_win(win) && win_find_tabpage(win) != win_find_tabpage(parent)) { + api_set_error(err, kErrorTypeException, "Cannot move autocmd win to another tabpage"); + return; + } + } if (was_split && !to_split) { if (!win_new_float(win, false, fconfig, err)) { return; } redraw_later(win, UPD_NOT_VALID); } else if (to_split) { - win_T *parent = NULL; - if (config->win != -1) { - parent = find_window_by_handle(fconfig.window, err); - if (!parent) { - return; - } else if (parent->w_floating) { - api_set_error(err, kErrorTypeException, "Cannot split a floating window"); - return; - } - } - WinSplit old_split = win_split_dir(win); if (has_vertical && !has_split) { if (config->vertical) { @@ -413,17 +463,59 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) return; } - if (was_split) { - win_T *new_curwin = NULL; + if (!check_split_disallowed_err(win, err)) { + return; // error already set + } + // Can't move the cmdwin or its old curwin to a different tabpage. + if ((win == cmdwin_win || win == cmdwin_old_curwin) && parent != NULL + && win_find_tabpage(parent) != win_tp) { + api_set_error(err, kErrorTypeException, "%s", e_cmdwin); + return; + } + + bool to_split_ok = false; + // If we are moving curwin to another tabpage, switch windows *before* we remove it from the + // window list or remove its frame (if non-floating), so it's valid for autocommands. + const bool curwin_moving_tp + = win == curwin && parent != NULL && win_tp != win_find_tabpage(parent); + if (curwin_moving_tp) { + if (was_split) { + int dir; + win_goto(winframe_find_altwin(win, &dir, NULL, NULL)); + } else { + win_goto(win_float_find_altwin(win, NULL)); + } + + // Autocommands may have been a real nuisance and messed things up... + if (curwin == win) { + api_set_error(err, kErrorTypeException, "Failed to switch away from window %d", + win->handle); + return; + } + win_tp = win_find_tabpage(win); + if (!win_tp || !win_valid_any_tab(parent)) { + api_set_error(err, kErrorTypeException, "Windows to split were closed"); + goto restore_curwin; + } + if (was_split == win->w_floating || parent->w_floating) { + api_set_error(err, kErrorTypeException, "Floating state of windows to split changed"); + goto restore_curwin; + } + } + int dir = 0; + frame_T *unflat_altfr = NULL; + win_T *altwin = NULL; + + if (was_split) { // If the window is the last in the tabpage or `fconfig.win` is // a handle to itself, we can't split it. if (win->w_frame->fr_parent == NULL) { // FIXME(willothy): if the window is the last in the tabpage but there is another tabpage // and the target window is in that other tabpage, should we move the window to that // tabpage and close the previous one, or just error? - api_set_error(err, kErrorTypeValidation, "Cannot move last window"); - return; + api_set_error(err, kErrorTypeException, "Cannot move last window"); + goto restore_curwin; } else if (parent != NULL && parent->handle == win->handle) { int n_frames = 0; for (frame_T *fr = win->w_frame->fr_parent->fr_child; fr != NULL; fr = fr->fr_next) { @@ -459,83 +551,82 @@ void nvim_win_set_config(Window window, Dict(win_config) *config, Error *err) } // If the frame doesn't have a parent, the old frame // was the root frame and we need to create a top-level split. - int dir; - new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp); + altwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); } else if (n_frames == 2) { // There are two windows in the frame, we can just rotate it. - int dir; - neighbor = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp); - new_curwin = neighbor; + altwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); + neighbor = altwin; } else { // There is only one window in the frame, we can't split it. - api_set_error(err, kErrorTypeValidation, "Cannot split window into itself"); - return; + api_set_error(err, kErrorTypeException, "Cannot split window into itself"); + goto restore_curwin; } - // Set the parent to whatever the correct - // neighbor window was determined to be. + // Set the parent to whatever the correct neighbor window was determined to be. parent = neighbor; } else { - int dir; - new_curwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp); - } - // move to neighboring window if we're moving the current window to a new tabpage - if (curwin == win && parent != NULL && new_curwin != NULL - && win_tp != win_find_tabpage(parent)) { - win_enter(new_curwin, true); + altwin = winframe_remove(win, &dir, win_tp == curtab ? NULL : win_tp, &unflat_altfr); } - win_remove(win, win_tp == curtab ? NULL : win_tp); } else { - win_remove(win, win_tp == curtab ? NULL : win_tp); - ui_comp_remove_grid(&win->w_grid_alloc); - if (win->w_config.external) { - for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next) { - if (tp == curtab) { - continue; - } - if (tp->tp_curwin == win) { - tp->tp_curwin = tp->tp_firstwin; - } - } - } - win->w_pos_changed = true; + altwin = win_float_find_altwin(win, win_tp == curtab ? NULL : win_tp); } - int flags = win_split_flags(fconfig.split, parent == NULL); + win_remove(win, win_tp == curtab ? NULL : win_tp); + if (win_tp == curtab) { + last_status(false); // may need to remove last status line + win_comp_pos(); // recompute window positions + } - if (parent == NULL) { - if (!win_split_ins(0, flags, win, 0)) { - // TODO(willothy): What should this error message say? - api_set_error(err, kErrorTypeException, "Failed to split window"); - return; - } - } else { - win_execute_T args; + int flags = win_split_flags(fconfig.split, parent == NULL) | WSP_NOENTER; + tabpage_T *const parent_tp = parent ? win_find_tabpage(parent) : curtab; - tabpage_T *tp = win_find_tabpage(parent); - if (!win_execute_before(&args, parent, tp)) { - // TODO(willothy): how should we handle this / what should the message be? - api_set_error(err, kErrorTypeException, "Failed to switch to tabpage %d", tp->handle); - win_execute_after(&args); - return; + TRY_WRAP(err, { + const bool need_switch = parent != NULL && parent != curwin; + switchwin_T switchwin; + if (need_switch) { + // `parent` is valid in its tabpage, so switch_win should not fail. + const int result = switch_win(&switchwin, parent, parent_tp, true); + (void)result; + assert(result == OK); } - // This should return the same ptr to `win`, but we check for - // NULL to detect errors. - win_T *res = win_split_ins(0, flags, win, 0); - win_execute_after(&args); - if (!res) { - // TODO(willothy): What should this error message say? - api_set_error(err, kErrorTypeException, "Failed to split window"); - return; + to_split_ok = win_split_ins(0, flags, win, 0, unflat_altfr) != NULL; + if (!to_split_ok) { + // Restore `win` to the window list now, so it's valid for restore_win (if used). + win_append(win->w_prev, win, win_tp == curtab ? NULL : win_tp); + } + if (need_switch) { + restore_win(&switchwin, true); + } + }); + if (!to_split_ok) { + if (was_split) { + // win_split_ins doesn't change sizes or layout if it fails to insert an existing window, so + // just undo winframe_remove. + winframe_restore(win, dir, unflat_altfr); + } + if (!ERROR_SET(err)) { + api_set_error(err, kErrorTypeException, "Failed to move window %d into split", win->handle); + } + +restore_curwin: + // If `win` was the original curwin, and autocommands didn't move it outside of curtab, be a + // good citizen and try to return to it. + if (curwin_moving_tp && win_valid(win)) { + win_goto(win); } + return; + } + + // If `win` moved tabpages and was the curwin of its old one, select a new curwin for it. + if (win_tp != parent_tp && win_tp->tp_curwin == win) { + win_tp->tp_curwin = altwin; } + if (HAS_KEY_X(config, width)) { win_setwidth_win(fconfig.width, win); } if (HAS_KEY_X(config, height)) { win_setheight_win(fconfig.height, win); } - redraw_later(win, UPD_NOT_VALID); - return; } else { win_config_float(win, fconfig); win->w_pos_changed = true; @@ -947,8 +1038,19 @@ static void parse_border_style(Object style, WinConfig *fconfig, Error *err) } } -static bool parse_float_config(Dict(win_config) *config, WinConfig *fconfig, bool reconf, - bool new_win, Error *err) +static void generate_api_error(win_T *wp, const char *attribute, Error *err) +{ + if (wp->w_floating) { + api_set_error(err, kErrorTypeValidation, + "Missing 'relative' field when reconfiguring floating window %d", + wp->handle); + } else { + api_set_error(err, kErrorTypeValidation, "non-float cannot have '%s'", attribute); + } +} + +static bool parse_win_config(win_T *wp, Dict(win_config) *config, WinConfig *fconfig, bool reconf, + Error *err) { #define HAS_KEY_X(d, key) HAS_KEY(d, win_config, key) bool has_relative = false, relative_is_win = false, is_split = false; @@ -973,7 +1075,7 @@ static bool parse_float_config(Dict(win_config) *config, WinConfig *fconfig, boo } else if (!config->external) { if (HAS_KEY_X(config, vertical) || HAS_KEY_X(config, split)) { is_split = true; - } else if (new_win) { + } else if (wp == NULL) { // new win api_set_error(err, kErrorTypeValidation, "Must specify 'relative' or 'external' when creating a float"); return false; @@ -1007,7 +1109,7 @@ static bool parse_float_config(Dict(win_config) *config, WinConfig *fconfig, boo if (HAS_KEY_X(config, row)) { if (!has_relative || is_split) { - api_set_error(err, kErrorTypeValidation, "non-float cannot have 'row'"); + generate_api_error(wp, "row", err); return false; } fconfig->row = config->row; @@ -1015,7 +1117,7 @@ static bool parse_float_config(Dict(win_config) *config, WinConfig *fconfig, boo if (HAS_KEY_X(config, col)) { if (!has_relative || is_split) { - api_set_error(err, kErrorTypeValidation, "non-float cannot have 'col'"); + generate_api_error(wp, "col", err); return false; } fconfig->col = config->col; @@ -1023,7 +1125,7 @@ static bool parse_float_config(Dict(win_config) *config, WinConfig *fconfig, boo if (HAS_KEY_X(config, bufpos)) { if (!has_relative || is_split) { - api_set_error(err, kErrorTypeValidation, "non-float cannot have 'bufpos'"); + generate_api_error(wp, "bufpos", err); return false; } else { if (!parse_float_bufpos(config->bufpos, &fconfig->bufpos)) { @@ -1065,17 +1167,32 @@ static bool parse_float_config(Dict(win_config) *config, WinConfig *fconfig, boo } if (relative_is_win || is_split) { + if (reconf && relative_is_win) { + win_T *target_win = find_window_by_handle(config->win, err); + if (!target_win) { + return false; + } + + if (target_win == wp) { + api_set_error(err, kErrorTypeException, "floating window cannot be relative to itself"); + return false; + } + } fconfig->window = curwin->handle; if (HAS_KEY_X(config, win)) { if (config->win > 0) { fconfig->window = config->win; } } - } else if (has_relative) { - if (HAS_KEY_X(config, win)) { + } else if (HAS_KEY_X(config, win)) { + if (has_relative) { api_set_error(err, kErrorTypeValidation, "'win' key is only valid with relative='win' and relative=''"); return false; + } else if (!is_split) { + api_set_error(err, kErrorTypeValidation, + "non-float with 'win' requires at least 'split' or 'vertical'"); + return false; } } @@ -1186,8 +1303,8 @@ static bool parse_float_config(Dict(win_config) *config, WinConfig *fconfig, boo } if (HAS_KEY_X(config, noautocmd)) { - if (!new_win) { - api_set_error(err, kErrorTypeValidation, "Invalid key: 'noautocmd'"); + if (wp) { + api_set_error(err, kErrorTypeValidation, "'noautocmd' cannot be used with existing windows"); return false; } fconfig->noautocmd = config->noautocmd; diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index ed51eedf1b..54a19513db 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -61,11 +61,17 @@ void nvim_win_set_buf(Window window, Buffer buffer, Error *err) if (!win || !buf) { return; } + + if (win->w_p_wfb) { + api_set_error(err, kErrorTypeException, "%s", e_winfixbuf_cannot_go_to_buffer); + return; + } + if (win == cmdwin_win || win == cmdwin_old_curwin || buf == cmdwin_buf) { api_set_error(err, kErrorTypeException, "%s", e_cmdwin); return; } - win_set_buf(win, buf, false, err); + win_set_buf(win, buf, err); } /// Gets the (1,0)-indexed, buffer-relative cursor position for a given window @@ -132,7 +138,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) win->w_cursor.col = (colnr_T)col; win->w_cursor.coladd = 0; // When column is out of range silently correct it. - check_cursor_col_win(win); + check_cursor_col(win); // Make sure we stick in this column. win->w_set_curswant = true; @@ -142,7 +148,7 @@ void nvim_win_set_cursor(Window window, ArrayOf(Integer, 2) pos, Error *err) switchwin_T switchwin; switch_win(&switchwin, win, NULL, true); update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); restore_win(&switchwin, true); redraw_later(win, UPD_VALID); diff --git a/src/nvim/arglist.c b/src/nvim/arglist.c index a02c22deae..4d493c9d03 100644 --- a/src/nvim/arglist.c +++ b/src/nvim/arglist.c @@ -623,6 +623,8 @@ void ex_argument(exarg_T *eap) /// Edit file "argn" of the argument lists. void do_argfile(exarg_T *eap, int argn) { + bool is_split_cmd = *eap->cmd == 's'; + int old_arg_idx = curwin->w_arg_idx; if (argn < 0 || argn >= ARGCOUNT) { @@ -637,10 +639,16 @@ void do_argfile(exarg_T *eap, int argn) return; } + if (!is_split_cmd + && (&ARGLIST[argn])->ae_fnum != curbuf->b_fnum + && !check_can_set_curbuf_forceit(eap->forceit)) { + return; + } + setpcmark(); // split window or create new tab page first - if (*eap->cmd == 's' || cmdmod.cmod_tab != 0) { + if (is_split_cmd || cmdmod.cmod_tab != 0) { if (win_split(0, 0) == FAIL) { return; } diff --git a/src/nvim/auevents.lua b/src/nvim/auevents.lua index ca438e87b4..94c5080f8d 100644 --- a/src/nvim/auevents.lua +++ b/src/nvim/auevents.lua @@ -88,6 +88,7 @@ return { 'SafeState', -- going to wait for a character 'SearchWrapped', -- after the search wrapped around 'SessionLoadPost', -- after loading a session file + 'SessionWritePost', -- after writing a session file 'ShellCmdPost', -- after ":!cmd" 'ShellFilterPost', -- after ":1,2!cmd", ":w !cmd", ":r !cmd". 'Signal', -- after nvim process received a signal diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index 3f93906942..c5d81d4cd2 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -712,7 +712,7 @@ char *au_event_disable(char *what) } else { STRCAT(new_ei, what); } - set_string_option_direct(kOptEventignore, new_ei, 0, SID_NONE); + set_option_direct(kOptEventignore, CSTR_AS_OPTVAL(new_ei), 0, SID_NONE); xfree(new_ei); return save_ei; } @@ -720,7 +720,7 @@ char *au_event_disable(char *what) void au_event_restore(char *old_ei) { if (old_ei != NULL) { - set_string_option_direct(kOptEventignore, old_ei, 0, SID_NONE); + set_option_direct(kOptEventignore, CSTR_AS_OPTVAL(old_ei), 0, SID_NONE); xfree(old_ei); } } @@ -1325,20 +1325,22 @@ void aucmd_prepbuf(aco_save_T *aco, buf_T *buf) buf->b_nwindows++; win_init_empty(auc_win); // set cursor and topline to safe values - // Make sure w_localdir and globaldir are NULL to avoid a chdir() in - // win_enter_ext(). + // Make sure w_localdir, tp_localdir and globaldir are NULL to avoid a + // chdir() in win_enter_ext(). XFREE_CLEAR(auc_win->w_localdir); + aco->tp_localdir = curtab->tp_localdir; + curtab->tp_localdir = NULL; aco->globaldir = globaldir; globaldir = NULL; block_autocmds(); // We don't want BufEnter/WinEnter autocommands. if (need_append) { - win_append(lastwin, auc_win); + win_append(lastwin, auc_win, NULL); pmap_put(int)(&window_handles, auc_win->handle, auc_win); win_config_float(auc_win, auc_win->w_config); } // Prevent chdir() call in win_enter_ext(), through do_autochdir() - int save_acd = p_acd; + const int save_acd = p_acd; p_acd = false; // no redrawing and don't set the window title RedrawingDisabled++; @@ -1427,12 +1429,19 @@ win_found: vars_clear(&awp->w_vars->dv_hashtab); // free all w: variables hash_init(&awp->w_vars->dv_hashtab); // re-use the hashtab + // If :lcd has been used in the autocommand window, correct current + // directory before restoring tp_localdir and globaldir. + if (awp->w_localdir != NULL) { + win_fix_current_dir(); + } + xfree(curtab->tp_localdir); + curtab->tp_localdir = aco->tp_localdir; xfree(globaldir); globaldir = aco->globaldir; // the buffer contents may have changed VIsual_active = aco->save_VIsual_active; - check_cursor(); + check_cursor(curwin); if (curwin->w_topline > curbuf->b_ml.ml_line_count) { curwin->w_topline = curbuf->b_ml.ml_line_count; curwin->w_topfill = 0; @@ -1464,12 +1473,12 @@ win_found: // In case the autocommand moves the cursor to a position that does not // exist in curbuf VIsual_active = aco->save_VIsual_active; - check_cursor(); + check_cursor(curwin); } } VIsual_active = aco->save_VIsual_active; - check_cursor(); // just in case lines got deleted + check_cursor(curwin); // just in case lines got deleted if (VIsual_active) { check_pos(curbuf, &VIsual); } @@ -1750,7 +1759,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force saveRedobuff(&save_redo); did_save_redobuff = true; } - did_filetype = keep_filetype; + curbuf->b_did_filetype = curbuf->b_keep_filetype; } // Note that we are applying autocmds. Some commands need to know. @@ -1760,7 +1769,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force // Remember that FileType was triggered. Used for did_filetype(). if (event == EVENT_FILETYPE) { - did_filetype = true; + curbuf->b_did_filetype = true; } char *tail = path_tail(fname); @@ -1864,7 +1873,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force if (did_save_redobuff) { restoreRedobuff(&save_redo); } - did_filetype = false; + curbuf->b_did_filetype = false; while (au_pending_free_buf != NULL) { buf_T *b = au_pending_free_buf->b_next; @@ -1901,7 +1910,7 @@ BYPASS_AU: } if (retval == OK && event == EVENT_FILETYPE) { - au_did_filetype = true; + curbuf->b_au_did_filetype = true; } return retval; @@ -2645,7 +2654,7 @@ void do_filetype_autocmd(buf_T *buf, bool force) secure = 0; ft_recursive++; - did_filetype = true; + buf->b_did_filetype = true; // Only pass true for "force" when it is true or // used recursively, to avoid endless recurrence. apply_autocmds(EVENT_FILETYPE, buf->b_p_ft, buf->b_fname, force || ft_recursive == 1, buf); diff --git a/src/nvim/autocmd.h b/src/nvim/autocmd.h index 8019cb7145..b298fbb6a1 100644 --- a/src/nvim/autocmd.h +++ b/src/nvim/autocmd.h @@ -15,14 +15,6 @@ #include "nvim/pos_defs.h" #include "nvim/types_defs.h" -// Set by the apply_autocmds_group function if the given event is equal to -// EVENT_FILETYPE. Used by the readfile function in order to determine if -// EVENT_BUFREADPOST triggered the EVENT_FILETYPE. -// -// Relying on this value requires one to reset it prior calling -// apply_autocmds_group. -EXTERN bool au_did_filetype INIT( = false); - /// For CursorMoved event EXTERN win_T *last_cursormoved_win INIT( = NULL); /// For CursorMoved event, only used when last_cursormoved_win == curwin @@ -31,9 +23,6 @@ EXTERN pos_T last_cursormoved INIT( = { 0, 0, 0 }); EXTERN bool autocmd_busy INIT( = false); ///< Is apply_autocmds() busy? EXTERN int autocmd_no_enter INIT( = false); ///< Buf/WinEnter autocmds disabled EXTERN int autocmd_no_leave INIT( = false); ///< Buf/WinLeave autocmds disabled -EXTERN bool did_filetype INIT( = false); ///< FileType event found -/// value for did_filetype when starting to execute autocommands -EXTERN bool keep_filetype INIT( = false); /// When deleting the current buffer, another one must be loaded. /// If we know which one is preferred, au_new_curbuf is set to it. diff --git a/src/nvim/autocmd_defs.h b/src/nvim/autocmd_defs.h index 6535f8a7ea..490782b209 100644 --- a/src/nvim/autocmd_defs.h +++ b/src/nvim/autocmd_defs.h @@ -19,6 +19,7 @@ typedef struct { handle_T new_curwin_handle; ///< ID of new curwin handle_T save_prevwin_handle; ///< ID of saved prevwin bufref_T new_curbuf; ///< new curbuf + char *tp_localdir; ///< saved value of tp_localdir char *globaldir; ///< saved value of globaldir bool save_VIsual_active; ///< saved VIsual_active int save_State; ///< saved State diff --git a/src/nvim/base64.c b/src/nvim/base64.c index d461b7e3ff..a645c64fe3 100644 --- a/src/nvim/base64.c +++ b/src/nvim/base64.c @@ -132,12 +132,18 @@ char *base64_encode(const char *src, size_t src_len) /// Decode a Base64 encoded string. /// +/// The returned string is NOT null-terminated, because the decoded string may +/// contain embedded NULLs. Use the output parameter out_lenp to determine the +/// length of the returned string. +/// /// @param src Base64 encoded string /// @param src_len Length of {src} +/// @param [out] out_lenp Returns the length of the decoded string /// @return Decoded string -char *base64_decode(const char *src, size_t src_len) +char *base64_decode(const char *src, size_t src_len, size_t *out_lenp) { assert(src != NULL); + assert(out_lenp != NULL); char *dest = NULL; @@ -155,7 +161,7 @@ char *base64_decode(const char *src, size_t src_len) const uint8_t *s = (const uint8_t *)src; - dest = xmalloc(out_len + 1); + dest = xmalloc(out_len); int acc = 0; int acc_len = 0; @@ -203,7 +209,7 @@ char *base64_decode(const char *src, size_t src_len) } } - dest[out_len] = '\0'; + *out_lenp = out_len; return dest; @@ -212,5 +218,7 @@ invalid: xfree((void *)dest); } + *out_lenp = 0; + return NULL; } diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index f6c7229485..39d0d24d47 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -117,7 +117,6 @@ # include "buffer.c.generated.h" #endif -static const char *e_auabort = N_("E855: Autocommands caused command to abort"); static const char e_attempt_to_delete_buffer_that_is_in_use_str[] = N_("E937: Attempt to delete a buffer that is in use: %s"); @@ -268,7 +267,7 @@ int open_buffer(bool read_stdin, exarg_T *eap, int flags_arg) // The autocommands in readfile() may change the buffer, but only AFTER // reading the file. set_bufref(&old_curbuf, curbuf); - modified_was_set = false; + curbuf->b_modified_was_set = false; // mark cursor position as being invalid curwin->w_valid = 0; @@ -351,7 +350,7 @@ int open_buffer(bool read_stdin, exarg_T *eap, int flags_arg) // the changed flag. Unless in readonly mode: "ls | nvim -R -". // When interrupted and 'cpoptions' contains 'i' set changed flag. if ((got_int && vim_strchr(p_cpo, CPO_INTMOD) != NULL) - || modified_was_set // ":set modified" used in autocmd + || curbuf->b_modified_was_set // autocmd did ":set modified" || (aborting() && vim_strchr(p_cpo, CPO_INTMOD) != NULL)) { changed(curbuf); } else if (retval != FAIL && !read_stdin && !read_fifo) { @@ -569,7 +568,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i } buf->b_locked--; buf->b_locked_split--; - if (abort_if_last && last_nonfloat(win)) { + if (abort_if_last && one_window(win)) { // Autocommands made this the only window. emsg(_(e_auabort)); return false; @@ -588,7 +587,7 @@ bool close_buffer(win_T *win, buf_T *buf, int action, bool abort_if_last, bool i } buf->b_locked--; buf->b_locked_split--; - if (abort_if_last && last_nonfloat(win)) { + if (abort_if_last && one_window(win)) { // Autocommands made this the only window. emsg(_(e_auabort)); return false; @@ -1306,6 +1305,12 @@ int do_buffer(int action, int start, int dir, int count, int forceit) } return FAIL; } + + if (action == DOBUF_GOTO && buf != curbuf && !check_can_set_curbuf_forceit(forceit)) { + // disallow navigating to another buffer when 'winfixbuf' is applied + return FAIL; + } + if ((action == DOBUF_GOTO || action == DOBUF_SPLIT) && (buf->b_flags & BF_DUMMY)) { // disallow navigating to the dummy buffer semsg(_(e_nobufnr), count); @@ -1720,7 +1725,7 @@ void enter_buffer(buf_T *buf) // ":ball" used in an autocommand. If there already is a filetype we // might prefer to keep it. if (*curbuf->b_p_ft == NUL) { - did_filetype = false; + curbuf->b_did_filetype = false; } open_buffer(false, NULL, 0); @@ -1747,7 +1752,7 @@ void enter_buffer(buf_T *buf) maketitle(); // when autocmds didn't change it if (curwin->w_topline == 1 && !curwin->w_topline_was_set) { - scroll_cursor_halfway(false, false); // redisplay at correct position + scroll_cursor_halfway(curwin, false, false); // redisplay at correct position } // Change directories when the 'acd' option is set. @@ -2167,7 +2172,7 @@ int buflist_getfile(int n, linenr_T lnum, int options, int forceit) // cursor is at to BOL and w_cursor.lnum is checked due to getfile() if (!p_sol && col != 0) { curwin->w_cursor.col = col; - check_cursor_col(); + check_cursor_col(curwin); curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; } @@ -2192,7 +2197,7 @@ void buflist_getfpos(void) curwin->w_cursor.col = 0; } else { curwin->w_cursor.col = fpos->col; - check_cursor_col(); + check_cursor_col(curwin); curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; } @@ -3252,7 +3257,7 @@ void fileinfo(int fullname, int shorthelp, bool dont_truncate) (int64_t)curwin->w_cursor.lnum, (int64_t)curbuf->b_ml.ml_line_count, n); - validate_virtcol(); + validate_virtcol(curwin); size_t len = strlen(buffer); col_print(buffer + len, IOSIZE - len, (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); diff --git a/src/nvim/buffer_defs.h b/src/nvim/buffer_defs.h index 9653b5e09c..8f5f2c44f7 100644 --- a/src/nvim/buffer_defs.h +++ b/src/nvim/buffer_defs.h @@ -47,8 +47,8 @@ typedef struct { #define VALID_VIRTCOL 0x04 // w_virtcol (file col) is valid #define VALID_CHEIGHT 0x08 // w_cline_height and w_cline_folded valid #define VALID_CROW 0x10 // w_cline_row is valid -#define VALID_BOTLINE 0x20 // w_botine and w_empty_rows are valid -#define VALID_BOTLINE_AP 0x40 // w_botine is approximated +#define VALID_BOTLINE 0x20 // w_botline and w_empty_rows are valid +#define VALID_BOTLINE_AP 0x40 // w_botline is approximated #define VALID_TOPLINE 0x80 // w_topline is valid (for cursor position) // flags for b_flags @@ -139,6 +139,8 @@ typedef struct { #define w_ve_flags w_onebuf_opt.wo_ve_flags // flags for 'virtualedit' OptInt wo_nuw; #define w_p_nuw w_onebuf_opt.wo_nuw // 'numberwidth' + int wo_wfb; +#define w_p_wfb w_onebuf_opt.wo_wfb // 'winfixbuf' int wo_wfh; #define w_p_wfh w_onebuf_opt.wo_wfh // 'winfixheight' int wo_wfw; @@ -459,6 +461,19 @@ struct file_buffer { bool b_marks_read; // Have we read ShaDa marks yet? + bool b_modified_was_set; ///< did ":set modified" + bool b_did_filetype; ///< FileType event found + bool b_keep_filetype; ///< value for did_filetype when starting + ///< to execute autocommands + + /// Set by the apply_autocmds_group function if the given event is equal to + /// EVENT_FILETYPE. Used by the readfile function in order to determine if + /// EVENT_BUFREADPOST triggered the EVENT_FILETYPE. + /// + /// Relying on this value requires one to reset it prior calling + /// apply_autocmds_group(). + bool b_au_did_filetype; + // The following only used in undo.c. u_header_T *b_u_oldhead; // pointer to oldest header u_header_T *b_u_newhead; // pointer to newest header; may not be valid diff --git a/src/nvim/bufwrite.c b/src/nvim/bufwrite.c index 94a6604fc1..27de03954a 100644 --- a/src/nvim/bufwrite.c +++ b/src/nvim/bufwrite.c @@ -900,38 +900,31 @@ static int buf_write_make_backup(char *fname, bool append, FileInfo *file_info_o // remove old backup, if present os_remove(*backupp); + // copy the file + if (os_copy(fname, *backupp, UV_FS_COPYFILE_FICLONE) != 0) { + *err = set_err(_("E509: Cannot create backup file (add ! to override)")); + XFREE_CLEAR(*backupp); + *backupp = NULL; + continue; + } + // set file protection same as original file, but // strip s-bit. os_setperm(*backupp, perm & 0777); #ifdef UNIX - // // Try to set the group of the backup same as the original file. If // this fails, set the protection bits for the group same as the // protection bits for others. - // if (file_info_new.stat.st_gid != file_info_old->stat.st_gid && os_chown(*backupp, (uv_uid_t)-1, (uv_gid_t)file_info_old->stat.st_gid) != 0) { os_setperm(*backupp, (perm & 0707) | ((perm & 07) << 3)); } -# ifdef HAVE_XATTR - os_copy_xattr(fname, *backupp); -# endif -#endif - - // copy the file - if (os_copy(fname, *backupp, UV_FS_COPYFILE_FICLONE) != 0) { - *err = set_err(_("E509: Cannot create backup file (add ! to override)")); - XFREE_CLEAR(*backupp); - *backupp = NULL; - continue; - } - -#ifdef UNIX os_file_settime(*backupp, (double)file_info_old->stat.st_atim.tv_sec, (double)file_info_old->stat.st_mtim.tv_sec); #endif + os_set_acl(*backupp, acl); #ifdef HAVE_XATTR os_copy_xattr(fname, *backupp); diff --git a/src/nvim/change.c b/src/nvim/change.c index 1c7724f010..05772d39e9 100644 --- a/src/nvim/change.c +++ b/src/nvim/change.c @@ -221,7 +221,7 @@ static void changed_lines_invalidate_win(win_T *wp, linenr_T lnum, colnr_T col, void changed_lines_invalidate_buf(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnume, linenr_T xtra) { - FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { + FOR_ALL_TAB_WINDOWS(tp, wp) { if (wp->w_buffer == buf) { changed_lines_invalidate_win(wp, lnum, col, lnume, xtra); } @@ -342,9 +342,8 @@ static void changed_common(buf_T *buf, linenr_T lnum, colnr_T col, linenr_T lnum && (last < wp->w_topline || (wp->w_topline >= lnum && wp->w_topline < lnume - && win_linetabsize(wp, wp->w_topline, ml_get(wp->w_topline), MAXCOL) - <= (wp->w_skipcol - + sms_marker_overlap(wp, win_col_off(wp) - win_col_off2(wp)))))) { + && win_linetabsize(wp, wp->w_topline, ml_get_buf(buf, wp->w_topline), MAXCOL) + <= (wp->w_skipcol + sms_marker_overlap(wp, -1))))) { wp->w_skipcol = 0; } @@ -707,14 +706,14 @@ void ins_char(int c) void ins_char_bytes(char *buf, size_t charlen) { // Break tabs if needed. - if (virtual_active() && curwin->w_cursor.coladd > 0) { + if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) { coladvance_force(getviscol()); } size_t col = (size_t)curwin->w_cursor.col; linenr_T lnum = curwin->w_cursor.lnum; char *oldp = ml_get(lnum); - size_t linelen = strlen(oldp) + 1; // length of old line including NUL + size_t linelen = (size_t)ml_get_len(lnum) + 1; // length of old line including NUL // The lengths default to the values for when not replacing. size_t oldlen = 0; // nr of bytes inserted @@ -815,13 +814,13 @@ void ins_str(char *s) int newlen = (int)strlen(s); linenr_T lnum = curwin->w_cursor.lnum; - if (virtual_active() && curwin->w_cursor.coladd > 0) { + if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) { coladvance_force(getviscol()); } colnr_T col = curwin->w_cursor.col; char *oldp = ml_get(lnum); - int oldlen = (int)strlen(oldp); + int oldlen = ml_get_len(lnum); char *newp = xmalloc((size_t)oldlen + (size_t)newlen + 1); if (col > 0) { @@ -879,7 +878,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) colnr_T col = curwin->w_cursor.col; bool fixpos = fixpos_arg; char *oldp = ml_get(lnum); - colnr_T oldlen = (colnr_T)strlen(oldp); + colnr_T oldlen = ml_get_len(lnum); // Can't do anything when the cursor is on the NUL after the line. if (col >= oldlen) { @@ -918,7 +917,7 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) // fixpos is true, we don't want to end up positioned at the NUL, // unless "restart_edit" is set or 'virtualedit' contains "onemore". if (col > 0 && fixpos && restart_edit == 0 - && (get_ve_flags() & VE_ONEMORE) == 0) { + && (get_ve_flags(curwin) & VE_ONEMORE) == 0) { curwin->w_cursor.col--; curwin->w_cursor.coladd = 0; curwin->w_cursor.col -= utf_head_off(oldp, oldp + curwin->w_cursor.col); @@ -926,21 +925,24 @@ int del_bytes(colnr_T count, bool fixpos_arg, bool use_delcombine) count = oldlen - col; movelen = 1; } + colnr_T newlen = oldlen - count; // If the old line has been allocated the deletion can be done in the // existing line. Otherwise a new line has to be allocated. - bool was_alloced = ml_line_alloced(); // check if oldp was allocated + bool alloc_newp = !ml_line_alloced(); // check if oldp was allocated char *newp; - if (was_alloced) { + if (!alloc_newp) { ml_add_deleted_len(curbuf->b_ml.ml_line_ptr, oldlen); newp = oldp; // use same allocated memory } else { // need to allocate a new line - newp = xmalloc((size_t)(oldlen + 1 - count)); + newp = xmalloc((size_t)newlen + 1); memmove(newp, oldp, (size_t)col); } memmove(newp + col, oldp + col + count, (size_t)movelen); - if (!was_alloced) { + if (alloc_newp) { ml_replace(lnum, newp, false); + } else { + curbuf->b_ml.ml_line_len -= count; } // mark the buffer as changed and prepare for displaying @@ -1041,7 +1043,7 @@ bool copy_indent(int size, char *src) if (p == NULL) { // Allocate memory for the result: the copied indent, new indent // and the rest of the line. - line_len = (int)strlen(get_cursor_line_ptr()) + 1; + line_len = get_cursor_line_len() + 1; assert(ind_len + line_len >= 0); size_t line_size; STRICT_ADD(ind_len, line_len, &line_size, size_t); @@ -1114,7 +1116,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) colnr_T mincol = curwin->w_cursor.col + 1; // make a copy of the current line so we can mess with it - char *saved_line = xstrdup(get_cursor_line_ptr()); + char *saved_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); if (State & VREPLACE_FLAG) { // With MODE_VREPLACE we make a copy of the next line, which we will be @@ -1125,7 +1127,8 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // the line, replacing what was there before and pushing the right // stuff onto the replace stack. -- webb. if (curwin->w_cursor.lnum < orig_line_count) { - next_line = xstrdup(ml_get(curwin->w_cursor.lnum + 1)); + next_line = xstrnsave(ml_get(curwin->w_cursor.lnum + 1), + (size_t)ml_get_len(curwin->w_cursor.lnum + 1)); } else { next_line = xstrdup(""); } @@ -1487,7 +1490,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) leader = xmalloc((size_t)bytes); allocated = leader; // remember to free it later - xstrlcpy(leader, saved_line, (size_t)lead_len + 1); + xmemcpyz(leader, saved_line, (size_t)lead_len); // TODO(vim): handle multi-byte and double width chars for (int li = 0; li < comment_start; li++) { @@ -1834,6 +1837,13 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) saved_line = NULL; if (did_append) { + // Always move extmarks - Here we move only the line where the cursor is, + // the previous mark_adjust() took care of the lines after. + int cols_added = mincol - 1 + less_cols_off - less_cols; + extmark_splice(curbuf, (int)lnum - 1, mincol - 1 - cols_spliced, + 0, less_cols_off, less_cols_off, + 1, cols_added, 1 + cols_added, kExtmarkUndo); + changed_lines(curbuf, curwin->w_cursor.lnum, curwin->w_cursor.col, curwin->w_cursor.lnum + 1, 1, true); did_append = false; @@ -1844,12 +1854,6 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) curwin->w_cursor.col + less_cols_off, 1, -less_cols, 0); } - // Always move extmarks - Here we move only the line where the - // cursor is, the previous mark_adjust takes care of the lines after - int cols_added = mincol - 1 + less_cols_off - less_cols; - extmark_splice(curbuf, (int)lnum - 1, mincol - 1 - cols_spliced, - 0, less_cols_off, less_cols_off, - 1, cols_added, 1 + cols_added, kExtmarkUndo); } else { changed_bytes(curwin->w_cursor.lnum, curwin->w_cursor.col); } @@ -1861,7 +1865,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) } if (did_append) { // bail out and just get the final length of the line we just manipulated - bcount_t extra = (bcount_t)strlen(ml_get(curwin->w_cursor.lnum)); + bcount_t extra = ml_get_len(curwin->w_cursor.lnum); extmark_splice(curbuf, (int)curwin->w_cursor.lnum - 1, 0, 0, 0, 0, 1, 0, 1 + extra, kExtmarkUndo); changed_lines(curbuf, curwin->w_cursor.lnum, 0, curwin->w_cursor.lnum, 1, true); @@ -1905,7 +1909,7 @@ bool open_line(int dir, int flags, int second_line_indent, bool *did_do_comment) // stuff onto the replace stack (via ins_char()). if (State & VREPLACE_FLAG) { // Put new line in p_extra - p_extra = xstrdup(get_cursor_line_ptr()); + p_extra = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); // Put back original line ml_replace(curwin->w_cursor.lnum, next_line, false); @@ -1932,19 +1936,16 @@ theend: /// If "fixpos" is true fix the cursor position when done. void truncate_line(int fixpos) { - char *newp; linenr_T lnum = curwin->w_cursor.lnum; colnr_T col = curwin->w_cursor.col; + char *old_line = ml_get(lnum); + char *newp = col == 0 ? xstrdup("") : xstrnsave(old_line, (size_t)col); + int deleted = ml_get_len(lnum) - col; - if (col == 0) { - newp = xstrdup(""); - } else { - newp = xstrnsave(ml_get(lnum), (size_t)col); - } ml_replace(lnum, newp, false); // mark the buffer as changed and prepare for displaying - changed_bytes(lnum, curwin->w_cursor.col); + inserted_bytes(lnum, curwin->w_cursor.col, deleted, 0); // If "fixpos" is true we don't want to end up positioned at the NUL. if (fixpos && curwin->w_cursor.col > 0) { diff --git a/src/nvim/channel.c b/src/nvim/channel.c index ebeaffe5a1..41635747f8 100644 --- a/src/nvim/channel.c +++ b/src/nvim/channel.c @@ -29,6 +29,7 @@ #include "nvim/log.h" #include "nvim/lua/executor.h" #include "nvim/main.h" +#include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/msgpack_rpc/channel.h" @@ -543,8 +544,11 @@ uint64_t channel_from_stdio(bool rpc, CallbackReader on_output, const char **err } #else if (embedded_mode) { - stdin_dup_fd = dup(STDIN_FILENO); - stdout_dup_fd = dup(STDOUT_FILENO); + // Redirect stdout/stdin (the UI channel) to stderr. Use fnctl(F_DUPFD_CLOEXEC) instead of dup() + // to prevent child processes from inheriting the file descriptors, which are used by UIs to + // detect when Nvim exits. + stdin_dup_fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, STDERR_FILENO + 1); + stdout_dup_fd = fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, STDERR_FILENO + 1); dup2(STDERR_FILENO, STDOUT_FILENO); dup2(STDERR_FILENO, STDIN_FILENO); } @@ -646,35 +650,52 @@ static inline list_T *buffer_to_tv_list(const char *const buf, const size_t len) void on_channel_data(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) { Channel *chan = data; - on_channel_output(stream, chan, buf, count, eof, &chan->on_data); + on_channel_output(stream, chan, buf, eof, &chan->on_data); } void on_job_stderr(Stream *stream, RBuffer *buf, size_t count, void *data, bool eof) { Channel *chan = data; - on_channel_output(stream, chan, buf, count, eof, &chan->on_stderr); + on_channel_output(stream, chan, buf, eof, &chan->on_stderr); } -static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, size_t count, bool eof, +static void on_channel_output(Stream *stream, Channel *chan, RBuffer *buf, bool eof, CallbackReader *reader) { - // stub variable, to keep reading consistent with the order of events, only - // consider the count parameter. - size_t r; - char *ptr = rbuffer_read_ptr(buf, &r); + size_t count; + char *output = rbuffer_read_ptr(buf, &count); - if (eof) { - reader->eof = true; - } else { - if (chan->term) { - terminal_receive(chan->term, ptr, count); + if (chan->term) { + if (!eof) { + char *p = output; + char *end = output + count; + while (p < end) { + // Don't pass incomplete UTF-8 sequences to libvterm. #16245 + // Composing chars can be passed separately, so utf_ptr2len_len() is enough. + int clen = utf_ptr2len_len(p, (int)(end - p)); + if (clen > end - p) { + count = (size_t)(p - output); + break; + } + p += clen; + } } + terminal_receive(chan->term, output, count); + } + + if (count) { rbuffer_consumed(buf, count); + } + // Move remaining data to start of buffer, so the buffer can never wrap around. + rbuffer_reset(buf); - if (callback_reader_set(*reader)) { - ga_concat_len(&reader->buffer, ptr, count); - } + if (callback_reader_set(*reader)) { + ga_concat_len(&reader->buffer, output, count); + } + + if (eof) { + reader->eof = true; } if (callback_reader_set(*reader)) { diff --git a/src/nvim/charset.c b/src/nvim/charset.c index 20bd364c7e..c611d4cfd6 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -1051,7 +1051,7 @@ char *skiptowhite(const char *p) /// /// @return Pointer to the next whitespace character. char *skiptowhite_esc(const char *p) - FUNC_ATTR_PURE + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE { while (*p != ' ' && *p != '\t' && *p != NUL) { if (((*p == '\\') || (*p == Ctrl_V)) && (*(p + 1) != NUL)) { @@ -1457,10 +1457,20 @@ bool rem_backslash(const char *str) /// @param p void backslash_halve(char *p) { - for (; *p; p++) { - if (rem_backslash(p)) { - STRMOVE(p, p + 1); + for (; *p && !rem_backslash(p); p++) {} + if (*p != NUL) { + char *dst = p; + goto start; + while (*p != NUL) { + if (rem_backslash(p)) { +start: + *dst++ = *(p + 1); + p += 2; + } else { + *dst++ = *p++; + } } + *dst = '\0'; } } @@ -1472,8 +1482,16 @@ void backslash_halve(char *p) char *backslash_halve_save(const char *p) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET { - // TODO(philix): simplify and improve backslash_halve_save algorithm - char *res = xstrdup(p); - backslash_halve(res); + char *res = xmalloc(strlen(p) + 1); + char *dst = res; + while (*p != NUL) { + if (rem_backslash(p)) { + *dst++ = *(p + 1); + p += 2; + } else { + *dst++ = *p++; + } + } + *dst = '\0'; return res; } diff --git a/src/nvim/cmdexpand.c b/src/nvim/cmdexpand.c index f172646edf..808df44941 100644 --- a/src/nvim/cmdexpand.c +++ b/src/nvim/cmdexpand.c @@ -1294,7 +1294,7 @@ char *addstar(char *fname, size_t len, int context) } } else { retval = xmalloc(len + 4); - xstrlcpy(retval, fname, len + 1); + xmemcpyz(retval, fname, len); // Don't add a star to *, ~, ~user, $var or `cmd`. // * would become **, which walks the whole tree. @@ -2598,7 +2598,8 @@ static char *get_healthcheck_names(expand_T *xp FUNC_ATTR_UNUSED, int idx) last_gen = get_cmdline_last_prompt_id(); } - if (names.type == kObjectTypeArray && idx < (int)names.data.array.size) { + if (names.type == kObjectTypeArray && idx < (int)names.data.array.size + && names.data.array.items[idx].type == kObjectTypeString) { return names.data.array.items[idx].data.string.data; } return NULL; @@ -2938,7 +2939,7 @@ void ExpandGeneric(const char *const pat, expand_T *xp, regmatch_T *regmatch, ch static void expand_shellcmd_onedir(char *buf, char *s, size_t l, char *pat, char ***matches, int *numMatches, int flags, hashtab_T *ht, garray_T *gap) { - xstrlcpy(buf, s, l + 1); + xmemcpyz(buf, s, l); add_pathsep(buf); l = strlen(buf); xstrlcpy(buf + l, pat, MAXPATHL - l); @@ -2986,7 +2987,6 @@ static void expand_shellcmd(char *filepat, char ***matches, int *numMatches, int char *path = NULL; garray_T ga; char *buf = xmalloc(MAXPATHL); - char *e; int flags = flagsarg; bool did_curdir = false; @@ -3022,7 +3022,7 @@ static void expand_shellcmd(char *filepat, char ***matches, int *numMatches, int ga_init(&ga, (int)sizeof(char *), 10); hashtab_T found_ht; hash_init(&found_ht); - for (char *s = path;; s = e) { + for (char *s = path, *e;; s = e) { e = vim_strchr(s, ENV_SEPCHAR); if (e == NULL) { e = s + strlen(s); @@ -3047,6 +3047,7 @@ static void expand_shellcmd(char *filepat, char ***matches, int *numMatches, int if (l > MAXPATHL - 5) { break; } + assert(l <= strlen(s)); expand_shellcmd_onedir(buf, s, l, pat, matches, numMatches, flags, &found_ht, &ga); if (*e != NUL) { e++; @@ -3241,6 +3242,7 @@ static int ExpandUserLua(expand_T *xp, int *num_file, char ***file) /// Adds matches to `ga`. /// If "dirs" is true only expand directory names. void globpath(char *path, char *file, garray_T *ga, int expand_options, bool dirs) + FUNC_ATTR_NONNULL_ALL { expand_T xpc; ExpandInit(&xpc); diff --git a/src/nvim/cmdhist.c b/src/nvim/cmdhist.c index 6a9290270a..983ab8b59b 100644 --- a/src/nvim/cmdhist.c +++ b/src/nvim/cmdhist.c @@ -294,7 +294,7 @@ static int last_maptick = -1; // last seen maptick /// @param histype may be one of the HIST_ values. /// @param in_map consider maptick when inside a mapping /// @param sep separator character used (search hist) -void add_to_history(int histype, const char *new_entry, int in_map, int sep) +void add_to_history(int histype, const char *new_entry, size_t new_entrylen, bool in_map, int sep) { histentry_T *hisptr; @@ -334,11 +334,10 @@ void add_to_history(int histype, const char *new_entry, int in_map, int sep) hist_free_entry(hisptr); // Store the separator after the NUL of the string. - size_t len = strlen(new_entry); - hisptr->hisstr = xstrnsave(new_entry, len + 2); + hisptr->hisstr = xstrnsave(new_entry, new_entrylen + 2); hisptr->timestamp = os_time(); hisptr->additional_elements = NULL; - hisptr->hisstr[len + 1] = (char)sep; + hisptr->hisstr[new_entrylen + 1] = (char)sep; hisptr->hisnum = ++hisnum[histype]; if (histype == HIST_SEARCH && in_map) { @@ -536,7 +535,7 @@ void f_histadd(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } init_history(); - add_to_history(histype, str, false, NUL); + add_to_history(histype, str, strlen(str), false, NUL); rettv->vval.v_number = true; } @@ -663,7 +662,8 @@ void ex_history(exarg_T *eap) i = 0; } if (hist[i].hisstr != NULL - && hist[i].hisnum >= j && hist[i].hisnum <= k) { + && hist[i].hisnum >= j && hist[i].hisnum <= k + && !message_filtered(hist[i].hisstr)) { msg_putchar('\n'); snprintf(IObuff, IOSIZE, "%c%6d ", i == idx ? '>' : ' ', hist[i].hisnum); diff --git a/src/nvim/cursor.c b/src/nvim/cursor.c index e93e658f1e..2e9e68843a 100644 --- a/src/nvim/cursor.c +++ b/src/nvim/cursor.c @@ -57,7 +57,7 @@ int getviscol2(colnr_T col, colnr_T coladd) /// The caller must have saved the cursor line for undo! int coladvance_force(colnr_T wcol) { - int rc = coladvance2(&curwin->w_cursor, true, false, wcol); + int rc = coladvance2(curwin, &curwin->w_cursor, true, false, wcol); if (wcol == MAXCOL) { curwin->w_valid &= ~VALID_VIRTCOL; @@ -76,25 +76,26 @@ int coladvance_force(colnr_T wcol) /// beginning at coladd 0. /// /// @return OK if desired column is reached, FAIL if not -int coladvance(colnr_T wcol) +int coladvance(win_T *wp, colnr_T wcol) { - int rc = getvpos(&curwin->w_cursor, wcol); + int rc = getvpos(wp, &wp->w_cursor, wcol); if (wcol == MAXCOL || rc == FAIL) { - curwin->w_valid &= ~VALID_VIRTCOL; - } else if (*get_cursor_pos_ptr() != TAB) { + wp->w_valid &= ~VALID_VIRTCOL; + } else if (*(ml_get_buf(wp->w_buffer, wp->w_cursor.lnum) + wp->w_cursor.col) != TAB) { // Virtcol is valid when not on a TAB - curwin->w_valid |= VALID_VIRTCOL; - curwin->w_virtcol = wcol; + wp->w_valid |= VALID_VIRTCOL; + wp->w_virtcol = wcol; } return rc; } -/// @param addspaces change the text to achieve our goal? +/// @param addspaces change the text to achieve our goal? only for wp=curwin! /// @param finetune change char offset for the exact column /// @param wcol_arg column to move to (can be negative) -static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_arg) +static int coladvance2(win_T *wp, pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_arg) { + assert(wp == curwin || !addspaces); colnr_T wcol = wcol_arg; int idx; colnr_T col = 0; @@ -104,30 +105,31 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a || (State & MODE_TERMINAL) || restart_edit != NUL || (VIsual_active && *p_sel != 'o') - || ((get_ve_flags() & VE_ONEMORE) && wcol < MAXCOL); + || ((get_ve_flags(wp) & VE_ONEMORE) && wcol < MAXCOL); - char *line = ml_get_buf(curbuf, pos->lnum); + char *line = ml_get_buf(wp->w_buffer, pos->lnum); + int linelen = ml_get_buf_len(wp->w_buffer, pos->lnum); if (wcol >= MAXCOL) { - idx = (int)strlen(line) - 1 + one_more; + idx = linelen - 1 + one_more; col = wcol; if ((addspaces || finetune) && !VIsual_active) { - curwin->w_curswant = linetabsize(curwin, pos->lnum) + one_more; - if (curwin->w_curswant > 0) { - curwin->w_curswant--; + wp->w_curswant = linetabsize(wp, pos->lnum) + one_more; + if (wp->w_curswant > 0) { + wp->w_curswant--; } } } else { - int width = curwin->w_width_inner - win_col_off(curwin); + int width = wp->w_width_inner - win_col_off(wp); int csize = 0; if (finetune - && curwin->w_p_wrap - && curwin->w_width_inner != 0 + && wp->w_p_wrap + && wp->w_width_inner != 0 && wcol >= (colnr_T)width && width > 0) { - csize = linetabsize(curwin, pos->lnum); + csize = linetabsize(wp, pos->lnum); if (csize > 0) { csize--; } @@ -143,7 +145,7 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a } CharsizeArg csarg; - CSType cstype = init_charsize_arg(&csarg, curwin, pos->lnum, line); + CSType cstype = init_charsize_arg(&csarg, wp, pos->lnum, line); StrCharInfo ci = utf_ptr2StrCharInfo(line); col = 0; while (col <= wcol && *ci.ptr != NUL) { @@ -159,14 +161,14 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a // is needed to ensure that a virtual position off the end of // a line has the correct indexing. The one_more comparison // replaces an explicit add of one_more later on. - if (col > wcol || (!virtual_active() && one_more == 0)) { + if (col > wcol || (!virtual_active(wp) && one_more == 0)) { idx -= 1; // Don't count the chars from 'showbreak'. csize -= head; col -= csize; } - if (virtual_active() + if (virtual_active(wp) && addspaces && wcol >= 0 && ((col != wcol && col != wcol + 1) || csize > 1)) { @@ -187,7 +189,6 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a col = wcol; } else { // Break a tab - int linelen = (int)strlen(line); int correct = wcol - col - csize + 1; // negative!! char *newline; @@ -229,14 +230,14 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a if (!one_more) { colnr_T scol, ecol; - getvcol(curwin, pos, &scol, NULL, &ecol); + getvcol(wp, pos, &scol, NULL, &ecol); pos->coladd = ecol - scol; } } else { int b = (int)wcol - (int)col; // The difference between wcol and col is used to set coladd. - if (b > 0 && b < (MAXCOL - 2 * curwin->w_width_inner)) { + if (b > 0 && b < (MAXCOL - 2 * wp->w_width_inner)) { pos->coladd = b; } @@ -245,7 +246,7 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a } // Prevent from moving onto a trail byte. - mark_mb_adjustpos(curbuf, pos); + mark_mb_adjustpos(wp->w_buffer, pos); if (wcol < 0 || col < wcol) { return FAIL; @@ -256,9 +257,9 @@ static int coladvance2(pos_T *pos, bool addspaces, bool finetune, colnr_T wcol_a /// Return in "pos" the position of the cursor advanced to screen column "wcol". /// /// @return OK if desired column is reached, FAIL if not -int getvpos(pos_T *pos, colnr_T wcol) +int getvpos(win_T *wp, pos_T *pos, colnr_T wcol) { - return coladvance2(pos, false, virtual_active(), wcol); + return coladvance2(wp, pos, false, virtual_active(wp), wcol); } /// Increment the cursor position. See inc() for return values. @@ -294,7 +295,7 @@ linenr_T get_cursor_rel_lnum(win_T *wp, linenr_T lnum) // Loop until we reach to_line, skipping folds. for (; from_line < to_line; from_line++, retval++) { // If from_line is in a fold, set it to the last line of that fold. - hasFoldingWin(wp, from_line, NULL, &from_line, true, NULL); + hasFolding(wp, from_line, NULL, &from_line); } // If to_line is in a closed fold, the line count is off by +1. Correct it. @@ -314,8 +315,7 @@ void check_pos(buf_T *buf, pos_T *pos) } if (pos->col > 0) { - char *line = ml_get_buf(buf, pos->lnum); - colnr_T len = (colnr_T)strlen(line); + colnr_T len = ml_get_buf_len(buf, pos->lnum); if (pos->col > len) { pos->col = len; } @@ -329,7 +329,7 @@ void check_cursor_lnum(win_T *win) if (win->w_cursor.lnum > buf->b_ml.ml_line_count) { // If there is a closed fold at the end of the file, put the cursor in // its first line. Otherwise in the last line. - if (!hasFolding(buf->b_ml.ml_line_count, &win->w_cursor.lnum, NULL)) { + if (!hasFolding(win, buf->b_ml.ml_line_count, &win->w_cursor.lnum, NULL)) { win->w_cursor.lnum = buf->b_ml.ml_line_count; } } @@ -338,32 +338,26 @@ void check_cursor_lnum(win_T *win) } } -/// Make sure curwin->w_cursor.col is valid. -void check_cursor_col(void) -{ - check_cursor_col_win(curwin); -} - /// Make sure win->w_cursor.col is valid. Special handling of insert-mode. /// @see mb_check_adjust_col -void check_cursor_col_win(win_T *win) +void check_cursor_col(win_T *win) { colnr_T oldcol = win->w_cursor.col; colnr_T oldcoladd = win->w_cursor.col + win->w_cursor.coladd; - unsigned cur_ve_flags = get_ve_flags(); + unsigned cur_ve_flags = get_ve_flags(win); - colnr_T len = (colnr_T)strlen(ml_get_buf(win->w_buffer, win->w_cursor.lnum)); + colnr_T len = ml_get_buf_len(win->w_buffer, win->w_cursor.lnum); if (len == 0) { win->w_cursor.col = 0; } else if (win->w_cursor.col >= len) { // Allow cursor past end-of-line when: // - in Insert mode or restarting Insert mode // - in Visual mode and 'selection' isn't "old" - // - 'virtualedit' is set */ + // - 'virtualedit' is set if ((State & MODE_INSERT) || restart_edit || (VIsual_active && *p_sel != 'o') || (cur_ve_flags & VE_ONEMORE) - || virtual_active()) { + || virtual_active(win)) { win->w_cursor.col = len; } else { win->w_cursor.col = len - 1; @@ -403,10 +397,10 @@ void check_cursor_col_win(win_T *win) } /// Make sure curwin->w_cursor in on a valid character -void check_cursor(void) +void check_cursor(win_T *wp) { - check_cursor_lnum(curwin); - check_cursor_col(); + check_cursor_lnum(wp); + check_cursor_col(wp); } /// Check if VIsual position is valid, correct it if not. @@ -418,7 +412,7 @@ void check_visual_pos(void) VIsual.col = 0; VIsual.coladd = 0; } else { - int len = (int)strlen(ml_get(VIsual.lnum)); + int len = ml_get_len(VIsual.lnum); if (VIsual.col > len) { VIsual.col = len; @@ -453,8 +447,8 @@ bool set_leftcol(colnr_T leftcol) changed_cline_bef_curs(curwin); // TODO(hinidu): I think it should be colnr_T or int, but p_siso is long. // Perhaps we can change p_siso to int. - int64_t lastcol = curwin->w_leftcol + curwin->w_width_inner - curwin_col_off() - 1; - validate_virtcol(); + int64_t lastcol = curwin->w_leftcol + curwin->w_width_inner - win_col_off(curwin) - 1; + validate_virtcol(curwin); bool retval = false; // If the cursor is right or left of the screen, move it to last or first @@ -462,10 +456,10 @@ bool set_leftcol(colnr_T leftcol) int siso = get_sidescrolloff_value(curwin); if (curwin->w_virtcol > (colnr_T)(lastcol - siso)) { retval = true; - coladvance((colnr_T)(lastcol - siso)); + coladvance(curwin, (colnr_T)(lastcol - siso)); } else if (curwin->w_virtcol < curwin->w_leftcol + siso) { retval = true; - coladvance((colnr_T)(curwin->w_leftcol + siso)); + coladvance(curwin, (colnr_T)(curwin->w_leftcol + siso)); } // If the start of the character under the cursor is not on the screen, @@ -475,10 +469,10 @@ bool set_leftcol(colnr_T leftcol) getvvcol(curwin, &curwin->w_cursor, &s, NULL, &e); if (e > (colnr_T)lastcol) { retval = true; - coladvance(s - 1); + coladvance(curwin, s - 1); } else if (s < curwin->w_leftcol) { retval = true; - if (coladvance(e + 1) == FAIL) { // there isn't another character + if (coladvance(curwin, e + 1) == FAIL) { // there isn't another character curwin->w_leftcol = s; // adjust w_leftcol instead changed_cline_bef_curs(curwin); } @@ -514,3 +508,15 @@ char *get_cursor_pos_ptr(void) { return ml_get_buf(curbuf, curwin->w_cursor.lnum) + curwin->w_cursor.col; } + +/// @return length (excluding the NUL) of the cursor line. +colnr_T get_cursor_line_len(void) +{ + return ml_get_buf_len(curbuf, curwin->w_cursor.lnum); +} + +/// @return length (excluding the NUL) of the cursor position. +colnr_T get_cursor_pos_len(void) +{ + return ml_get_buf_len(curbuf, curwin->w_cursor.lnum) - curwin->w_cursor.col; +} diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 51d5d08f78..303d0318b5 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -346,7 +346,12 @@ char *next_virt_text_chunk(VirtText vt, size_t *pos, int *attr) for (; text == NULL && *pos < kv_size(vt); (*pos)++) { text = kv_A(vt, *pos).text; int hl_id = kv_A(vt, *pos).hl_id; - *attr = hl_combine_attr(*attr, hl_id > 0 ? syn_id2attr(hl_id) : 0); + if (hl_id >= 0) { + *attr = MAX(*attr, 0); + if (hl_id > 0) { + *attr = hl_combine_attr(*attr, syn_id2attr(hl_id)); + } + } } return text; } @@ -454,21 +459,18 @@ static void decor_range_add_from_inline(DecorState *state, int start_row, int st if (decor.ext) { DecorVirtText *vt = decor.data.ext.vt; while (vt) { - decor_range_add_virt(state, start_row, start_col, end_row, end_col, vt, owned, - DECOR_PRIORITY_BASE); + decor_range_add_virt(state, start_row, start_col, end_row, end_col, vt, owned); vt = vt->next; } uint32_t idx = decor.data.ext.sh_idx; while (idx != DECOR_ID_INVALID) { DecorSignHighlight *sh = &kv_A(decor_items, idx); - decor_range_add_sh(state, start_row, start_col, end_row, end_col, sh, owned, ns, mark_id, - DECOR_PRIORITY_BASE); + decor_range_add_sh(state, start_row, start_col, end_row, end_col, sh, owned, ns, mark_id); idx = sh->next; } } else { DecorSignHighlight sh = decor_sh_from_inline(decor.data.hl); - decor_range_add_sh(state, start_row, start_col, end_row, end_col, &sh, owned, ns, mark_id, - DECOR_PRIORITY_BASE); + decor_range_add_sh(state, start_row, start_col, end_row, end_col, &sh, owned, ns, mark_id); } } @@ -478,8 +480,7 @@ static void decor_range_insert(DecorState *state, DecorRange range) size_t index; for (index = kv_size(state->active) - 1; index > 0; index--) { DecorRange item = kv_A(state->active, index - 1); - if ((item.priority < range.priority) - || ((item.priority == range.priority) && (item.subpriority <= range.subpriority))) { + if (item.priority <= range.priority) { break; } kv_A(state->active, index) = kv_A(state->active, index - 1); @@ -488,7 +489,7 @@ static void decor_range_insert(DecorState *state, DecorRange range) } void decor_range_add_virt(DecorState *state, int start_row, int start_col, int end_row, int end_col, - DecorVirtText *vt, bool owned, DecorPriority subpriority) + DecorVirtText *vt, bool owned) { bool is_lines = vt->flags & kVTIsLines; DecorRange range = { @@ -498,15 +499,13 @@ void decor_range_add_virt(DecorState *state, int start_row, int start_col, int e .attr_id = 0, .owned = owned, .priority = vt->priority, - .subpriority = subpriority, .draw_col = -10, }; decor_range_insert(state, range); } void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end_row, int end_col, - DecorSignHighlight *sh, bool owned, uint32_t ns, uint32_t mark_id, - DecorPriority subpriority) + DecorSignHighlight *sh, bool owned, uint32_t ns, uint32_t mark_id) { if (sh->flags & kSHIsSign) { return; @@ -519,7 +518,6 @@ void decor_range_add_sh(DecorState *state, int start_row, int start_col, int end .attr_id = 0, .owned = owned, .priority = sh->priority, - .subpriority = subpriority, .draw_col = -10, }; @@ -742,14 +740,15 @@ void decor_redraw_signs(win_T *wp, buf_T *buf, int row, SignTextAttrs sattrs[], if (kv_size(signs)) { int width = wp->w_minscwidth == SCL_NUM ? 1 : wp->w_scwidth; - int idx = MIN(width, num_text) - 1; + int len = MIN(width, num_text); + int idx = 0; qsort((void *)&kv_A(signs, 0), kv_size(signs), sizeof(kv_A(signs, 0)), sign_item_cmp); for (size_t i = 0; i < kv_size(signs); i++) { DecorSignHighlight *sh = kv_A(signs, i).sh; - if (idx >= 0 && sh->text[0]) { + if (idx < len && sh->text[0]) { memcpy(sattrs[idx].text, sh->text, SIGN_WIDTH * sizeof(sattr_T)); - sattrs[idx--].hl_id = sh->hl_id; + sattrs[idx++].hl_id = sh->hl_id; } if (*num_id == 0) { *num_id = sh->number_hl_id; @@ -792,13 +791,12 @@ static const uint32_t signtext_filter[4] = {[kMTMetaSignText] = kMTFilterSelect /// @param clear kFalse, kTrue or kNone for an, added/deleted, cleared, or initialized range. void buf_signcols_count_range(buf_T *buf, int row1, int row2, int add, TriState clear) { - if (!buf->b_signcols.autom || !buf_meta_total(buf, kMTMetaSignText)) { + if (!buf->b_signcols.autom || row2 < row1 || !buf_meta_total(buf, kMTMetaSignText)) { return; } // Allocate an array of integers holding the number of signs in the range. - assert(row2 >= row1); - int *count = xcalloc(sizeof(int), (size_t)(row2 + 1 - row1)); + int *count = xcalloc((size_t)(row2 + 1 - row1), sizeof(int)); MarkTreeIter itr[1]; MTPair pair = { 0 }; @@ -890,9 +888,9 @@ int decor_virt_lines(win_T *wp, linenr_T lnum, VirtLines *lines, TriState has_fo } assert(lnum > 0); - bool below_fold = lnum > 1 && hasFoldingWin(wp, lnum - 1, NULL, NULL, true, NULL); + bool below_fold = lnum > 1 && hasFolding(wp, lnum - 1, NULL, NULL); if (has_fold == kNone) { - has_fold = hasFoldingWin(wp, lnum, NULL, NULL, true, NULL); + has_fold = hasFolding(wp, lnum, NULL, NULL); } const int row = lnum - 1; diff --git a/src/nvim/decoration.h b/src/nvim/decoration.h index a63cc7afc0..86d4de79f0 100644 --- a/src/nvim/decoration.h +++ b/src/nvim/decoration.h @@ -48,8 +48,6 @@ typedef struct { int attr_id; ///< cached lookup of inl.hl_id if it was a highlight bool owned; ///< ephemeral decoration, free memory immediately DecorPriority priority; - DecorPriority subpriority; ///< Secondary priority value used for ordering (#27131). - ///< Reflects the order of patterns/captures in the query file. DecorRangeKind kind; /// Screen column to draw the virtual text. /// When -1, it should be drawn on the current screen line after deciding where. diff --git a/src/nvim/decoration_defs.h b/src/nvim/decoration_defs.h index 8d0075b169..c9475257b1 100644 --- a/src/nvim/decoration_defs.h +++ b/src/nvim/decoration_defs.h @@ -10,7 +10,7 @@ typedef struct { char *text; - int hl_id; + int hl_id; ///< -1 if not specified } VirtTextChunk; typedef kvec_t(VirtTextChunk) VirtText; diff --git a/src/nvim/decoration_provider.c b/src/nvim/decoration_provider.c index 2417c14f7f..74f444d8e8 100644 --- a/src/nvim/decoration_provider.c +++ b/src/nvim/decoration_provider.c @@ -35,7 +35,7 @@ static kvec_t(DecorProvider) decor_providers = KV_INITIAL_VALUE; static void decor_provider_error(DecorProvider *provider, const char *name, const char *msg) { const char *ns_name = describe_ns(provider->ns_id, "(UNKNOWN PLUGIN)"); - ELOG("error in provider %s.%s: %s", ns_name, name, msg); + ILOG("error in provider %s.%s: %s", ns_name, name, msg); msg_schedule_semsg_multiline("Error in decoration provider %s.%s:\n%s", ns_name, name, msg); } diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 2b3010e063..ea846b46ec 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -756,7 +756,7 @@ static int diff_write_buffer(buf_T *buf, mmfile_t *m, linenr_T start, linenr_T e // xdiff requires one big block of memory with all the text. for (linenr_T lnum = start; lnum <= end; lnum++) { - len += strlen(ml_get_buf(buf, lnum)) + 1; + len += (size_t)ml_get_buf_len(buf, lnum) + 1; } char *ptr = try_malloc(len); if (ptr == NULL) { @@ -1347,7 +1347,7 @@ void ex_diffsplit(exarg_T *eap) set_bufref(&old_curbuf, curbuf); // Need to compute w_fraction when no redraw happened yet. - validate_cursor(); + validate_cursor(curwin); set_fraction(curwin); // don't use a new tab page, each tab page has its own diffs @@ -1429,6 +1429,7 @@ void diff_win_options(win_T *wp, bool addbuf) wp->w_p_wrap_save = wp->w_p_wrap; } wp->w_p_wrap = false; + wp->w_skipcol = 0; } if (!wp->w_p_diff) { @@ -1437,7 +1438,8 @@ void diff_win_options(win_T *wp, bool addbuf) } wp->w_p_fdm_save = xstrdup(wp->w_p_fdm); } - set_string_option_direct_in_win(wp, kOptFoldmethod, "diff", OPT_LOCAL, 0); + set_option_direct_for(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("diff"), OPT_LOCAL, 0, kOptReqWin, + wp); if (!wp->w_p_diff) { wp->w_p_fen_save = wp->w_p_fen; @@ -1457,7 +1459,7 @@ void diff_win_options(win_T *wp, bool addbuf) foldUpdateAll(wp); // make sure topline is not halfway through a fold - changed_window_setting_win(wp); + changed_window_setting(wp); if (vim_strchr(p_sbo, 'h') == NULL) { do_cmdline_cmd("set sbo+=hor"); } @@ -1497,8 +1499,9 @@ void ex_diffoff(exarg_T *eap) wp->w_p_crb = wp->w_p_crb_save; } if (!(diff_flags & DIFF_FOLLOWWRAP)) { - if (!wp->w_p_wrap) { - wp->w_p_wrap = wp->w_p_wrap_save; + if (!wp->w_p_wrap && wp->w_p_wrap_save) { + wp->w_p_wrap = true; + wp->w_leftcol = 0; } } free_string_option(wp->w_p_fdm); @@ -1522,7 +1525,7 @@ void ex_diffoff(exarg_T *eap) // make sure topline is not halfway a fold and cursor is // invalidated - changed_window_setting_win(wp); + changed_window_setting(wp); // Note: 'sbo' is not restored, it's a global option. diff_buf_adjust(wp); @@ -2137,7 +2140,7 @@ int diff_check_with_linestatus(win_T *wp, linenr_T lnum, int *linestatus) } // A closed fold never has filler lines. - if (hasFoldingWin(wp, lnum, NULL, NULL, true, NULL)) { + if (hasFolding(wp, lnum, NULL, NULL)) { return 0; } @@ -2451,8 +2454,7 @@ void diff_set_topline(win_T *fromwin, win_T *towin) changed_line_abv_curs_win(towin); check_topfill(towin, false); - hasFoldingWin(towin, towin->w_topline, &towin->w_topline, - NULL, true, NULL); + hasFolding(towin, towin->w_topline, &towin->w_topline, NULL); } /// This is called when 'diffopt' is changed. @@ -2988,7 +2990,7 @@ theend: // Check that the cursor is on a valid character and update its // position. When there were filler lines the topline has become // invalid. - check_cursor(); + check_cursor(curwin); changed_line_abv_curs(); if (diff_need_update) { diff --git a/src/nvim/digraph.c b/src/nvim/digraph.c index f91ff9274b..a358a1723a 100644 --- a/src/nvim/digraph.c +++ b/src/nvim/digraph.c @@ -2078,7 +2078,7 @@ void ex_loadkeymap(exarg_T *eap) char buf[KMAP_LLEN + 11]; char *save_cpo = p_cpo; - if (!getline_equal(eap->getline, eap->cookie, getsourceline)) { + if (!getline_equal(eap->ea_getline, eap->cookie, getsourceline)) { emsg(_("E105: Using :loadkeymap not in a sourced file")); return; } @@ -2094,7 +2094,7 @@ void ex_loadkeymap(exarg_T *eap) // Get each line of the sourced file, break at the end. while (true) { - char *line = eap->getline(0, eap->cookie, 0, true); + char *line = eap->ea_getline(0, eap->cookie, 0, true); if (line == NULL) { break; diff --git a/src/nvim/drawline.c b/src/nvim/drawline.c index 4281cdff33..07944081da 100644 --- a/src/nvim/drawline.c +++ b/src/nvim/drawline.c @@ -73,7 +73,7 @@ typedef struct { int col; ///< visual column on screen, after wrapping int boguscols; ///< nonexistent columns added to "col" to force wrapping int old_boguscols; ///< bogus boguscols - int vcol_off; ///< offset for concealed characters + int vcol_off_co; ///< offset for concealed characters int off; ///< offset relative start of line @@ -288,26 +288,23 @@ static void draw_virt_text(win_T *wp, buf_T *buf, int col_off, int *end_col, int if (item->draw_col < 0) { continue; } - int col = 0; if (item->kind == kDecorKindUIWatched) { // send mark position to UI - col = item->draw_col; - WinExtmark m = { (NS)item->data.ui.ns_id, item->data.ui.mark_id, win_row, col }; + WinExtmark m = { (NS)item->data.ui.ns_id, item->data.ui.mark_id, win_row, item->draw_col }; kv_push(win_extmark_arr, m); } if (vt) { int vcol = item->draw_col - col_off; - col = draw_virt_text_item(buf, item->draw_col, vt->data.virt_text, - vt->hl_mode, max_col, vcol); + int col = draw_virt_text_item(buf, item->draw_col, vt->data.virt_text, + vt->hl_mode, max_col, vcol); if (vt->pos == kVPosEndOfLine && do_eol) { state->eol_col = col + 1; } + *end_col = MAX(*end_col, col); } if (!vt || !(vt->flags & kVTRepeatLinebreak)) { item->draw_col = INT_MIN; // deactivate } - - *end_col = MAX(*end_col, col); } } @@ -853,43 +850,6 @@ static void handle_inline_virtual_text(win_T *wp, winlinevars_T *wlv, ptrdiff_t } } -static colnr_T get_trailcol(win_T *wp, const char *ptr, const char *line) -{ - colnr_T trailcol = MAXCOL; - // find start of trailing whitespace - if (wp->w_p_lcs_chars.trail) { - trailcol = (colnr_T)strlen(ptr); - while (trailcol > 0 && ascii_iswhite(ptr[trailcol - 1])) { - trailcol--; - } - trailcol += (colnr_T)(ptr - line); - } - - return trailcol; -} - -static colnr_T get_leadcol(win_T *wp, const char *ptr, const char *line) -{ - colnr_T leadcol = 0; - - // find end of leading whitespace - if (wp->w_p_lcs_chars.lead || wp->w_p_lcs_chars.leadmultispace != NULL) { - leadcol = 0; - while (ascii_iswhite(ptr[leadcol])) { - leadcol++; - } - if (ptr[leadcol] == NUL) { - // in a line full of spaces all of them are treated as trailing - leadcol = 0; - } else { - // keep track of the first column not filled with spaces - leadcol += (colnr_T)(ptr - line + 1); - } - } - - return leadcol; -} - /// Start a screen line at column zero. static void win_line_start(win_T *wp, winlinevars_T *wlv) { @@ -898,16 +858,16 @@ static void win_line_start(win_T *wp, winlinevars_T *wlv) wlv->need_lbr = false; for (int i = 0; i < wp->w_grid.cols; i++) { linebuf_char[i] = schar_from_ascii(' '); - linebuf_attr[i] = -1; + linebuf_attr[i] = 0; linebuf_vcol[i] = -1; } } static void fix_for_boguscols(winlinevars_T *wlv) { - wlv->n_extra += wlv->vcol_off; - wlv->vcol -= wlv->vcol_off; - wlv->vcol_off = 0; + wlv->n_extra += wlv->vcol_off_co; + wlv->vcol -= wlv->vcol_off_co; + wlv->vcol_off_co = 0; wlv->col -= wlv->boguscols; wlv->old_boguscols = wlv->boguscols; wlv->boguscols = 0; @@ -1027,7 +987,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s int conceal_attr = win_hl_attr(wp, HLF_CONCEAL); bool is_concealing = false; bool did_wcol = false; -#define vcol_hlc(wlv) ((wlv).vcol - (wlv).vcol_off) +#define vcol_hlc(wlv) ((wlv).vcol - (wlv).vcol_off_co) assert(startrow < endrow); @@ -1070,7 +1030,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s has_decor = decor_redraw_line(wp, lnum - 1, &decor_state); - decor_providers_invoke_line(wp, lnum - 1, &has_decor); + if (!end_fill) { + decor_providers_invoke_line(wp, lnum - 1, &has_decor); + } if (has_decor) { extra_check = true; @@ -1301,17 +1263,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s nextlinecol = MAXCOL; nextline_idx = 0; } else { - const size_t line_len = strlen(line); + const colnr_T line_len = ml_get_buf_len(wp->w_buffer, lnum); if (line_len < SPWORDLEN) { // Short line, use it completely and append the start of the // next line. nextlinecol = 0; - memmove(nextline, line, line_len); + memmove(nextline, line, (size_t)line_len); STRMOVE(nextline + line_len, nextline + SPWORDLEN); - nextline_idx = (int)line_len + 1; + nextline_idx = line_len + 1; } else { // Long line, use only the last SPWORDLEN bytes. - nextlinecol = (int)line_len - SPWORDLEN; + nextlinecol = line_len - SPWORDLEN; memmove(nextline, line + nextlinecol, SPWORDLEN); nextline_idx = SPWORDLEN + 1; } @@ -1339,8 +1301,28 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s || wp->w_p_lcs_chars.nbsp) { extra_check = true; } - trailcol = get_trailcol(wp, ptr, line); - leadcol = get_leadcol(wp, ptr, line); + // find start of trailing whitespace + if (wp->w_p_lcs_chars.trail) { + trailcol = ml_get_buf_len(wp->w_buffer, lnum); + while (trailcol > 0 && ascii_iswhite(ptr[trailcol - 1])) { + trailcol--; + } + trailcol += (colnr_T)(ptr - line); + } + // find end of leading whitespace + if (wp->w_p_lcs_chars.lead || wp->w_p_lcs_chars.leadmultispace != NULL) { + leadcol = 0; + while (ascii_iswhite(ptr[leadcol])) { + leadcol++; + } + if (ptr[leadcol] == NUL) { + // in a line full of spaces all of them are treated as trailing + leadcol = 0; + } else { + // keep track of the first column not filled with spaces + leadcol += (colnr_T)(ptr - line + 1); + } + } } // 'nowrap' or 'wrap' and a single line that doesn't fit: Advance to the @@ -1396,7 +1378,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // the end of the line may be before the start of the displayed part. if (wlv.vcol < start_col && (wp->w_p_cuc || wlv.color_cols - || virtual_active() + || virtual_active(wp) || (VIsual_active && wp->w_buffer == curwin->w_buffer))) { wlv.vcol = start_col; } @@ -1433,7 +1415,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s pos_T pos = wp->w_cursor; wp->w_cursor.lnum = lnum; wp->w_cursor.col = linecol; - size_t len = spell_move_to(wp, FORWARD, true, true, &spell_hlf); + size_t len = spell_move_to(wp, FORWARD, SMT_ALL, true, &spell_hlf); // spell_move_to() may call ml_get() and make "line" invalid line = ml_get_buf(wp->w_buffer, lnum); @@ -1569,7 +1551,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // When only updating the columns and that's done, stop here. if (col_rows > 0) { - win_put_linebuf(wp, wlv.row, 0, wlv.off, wlv.off, bg_attr, false); + wlv_put_linebuf(wp, &wlv, wlv.off, false, bg_attr, 0); // Need to update more screen lines if: // - 'statuscolumn' needs to be drawn, or // - LineNrAbove or LineNrBelow is used, or @@ -1616,7 +1598,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } } - if (cul_screenline && wlv.vcol >= left_curline_col && wlv.vcol < right_curline_col) { + if (cul_screenline && wlv.filler_todo <= 0 + && wlv.vcol >= left_curline_col && wlv.vcol < right_curline_col) { apply_cursorline_highlight(wp, &wlv); } @@ -1625,7 +1608,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s && lnum == wp->w_cursor.lnum && wlv.vcol >= wp->w_virtcol) { draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row); // don't clear anything after wlv.col - win_put_linebuf(wp, wlv.row, 0, wlv.col, wlv.col, bg_attr, false); + wlv_put_linebuf(wp, &wlv, wlv.col, false, bg_attr, 0); // Pretend we have finished updating the window. Except when // 'cursorcolumn' is set. if (wp->w_p_cuc) { @@ -1643,7 +1626,8 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } int extmark_attr = 0; - if (area_highlighting || spv->spv_has_spell || extra_check) { + if (wlv.filler_todo <= 0 + && (area_highlighting || spv->spv_has_spell || extra_check)) { if (wlv.n_extra == 0 || !wlv.extra_for_extmark) { wlv.reset_extra_attr = false; } @@ -1674,11 +1658,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } decor_need_recheck = false; } - if (wlv.filler_todo <= 0) { - extmark_attr = decor_redraw_col(wp, (colnr_T)(ptr - line), - may_have_inline_virt ? -3 : wlv.off, - selected, &decor_state); - } + extmark_attr = decor_redraw_col(wp, (colnr_T)(ptr - line), + may_have_inline_virt ? -3 : wlv.off, + selected, &decor_state); if (may_have_inline_virt) { handle_inline_virtual_text(wp, &wlv, ptr - line, selected); if (wlv.n_extra > 0 && wlv.virt_inline_hl_mode <= kHlModeReplace) { @@ -2236,9 +2218,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } else { int saved_nextra = wlv.n_extra; - if (wlv.vcol_off > 0) { + if (wlv.vcol_off_co > 0) { // there are characters to conceal - tab_len += wlv.vcol_off; + tab_len += wlv.vcol_off_co; } // boguscols before fix_for_boguscols() from above. if (wp->w_p_lcs_chars.tab1 && wlv.old_boguscols > 0 @@ -2280,27 +2262,27 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } // n_extra will be increased by fix_for_boguscols() - // macro below, so need to adjust for that here - if (wlv.vcol_off > 0) { - wlv.n_extra -= wlv.vcol_off; + // below, so need to adjust for that here + if (wlv.vcol_off_co > 0) { + wlv.n_extra -= wlv.vcol_off_co; } } } { - int vc_saved = wlv.vcol_off; + int vc_saved = wlv.vcol_off_co; // Tab alignment should be identical regardless of // 'conceallevel' value. So tab compensates of all // previous concealed characters, and thus resets - // vcol_off and boguscols accumulated so far in the + // vcol_off_co and boguscols accumulated so far in the // line. Note that the tab can be longer than // 'tabstop' when there are concealed characters. fix_for_boguscols(&wlv); // Make sure, the highlighting for the tab char will be // correctly set further below (effectively reverts the - // FIX_FOR_BOGSUCOLS macro). + // fix_for_boguscols() call). if (wlv.n_extra == tab_len + vc_saved && wp->w_p_list && wp->w_p_lcs_chars.tab1) { tab_len += vc_saved; @@ -2342,7 +2324,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s && wlv.line_attr == 0 && wlv.line_attr_lowprio == 0) { // In virtualedit, visual selections may extend beyond end of line - if (!(area_highlighting && virtual_active() + if (!(area_highlighting && virtual_active(wp) && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol)) { wlv.p_extra = ""; } @@ -2385,7 +2367,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s mb_schar = schar_from_ascii(mb_c); } else if (VIsual_active && (VIsual_mode == Ctrl_V || VIsual_mode == 'v') - && virtual_active() + && virtual_active(wp) && wlv.tocol != MAXCOL && wlv.vcol < wlv.tocol && wlv.col < grid->cols) { @@ -2423,12 +2405,19 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } else { mb_schar = schar_from_ascii(' '); } + + if (utf_char2cells(mb_c) > 1) { + // When the first char to be concealed is double-width, + // need to advance one more virtual column. + wlv.n_extra++; + } + mb_c = schar_get_first_codepoint(mb_schar); prev_syntax_id = syntax_seqnr; if (wlv.n_extra > 0) { - wlv.vcol_off += wlv.n_extra; + wlv.vcol_off_co += wlv.n_extra; } wlv.vcol += wlv.n_extra; if (is_wrapped && wlv.n_extra > 0) { @@ -2454,11 +2443,17 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s // In the cursor line and we may be concealing characters: correct // the cursor column when we reach its position. - if (!did_wcol + // With 'virtualedit' we may never reach cursor position, but we still + // need to correct the cursor column, so do that at end of line. + if (!did_wcol && wlv.filler_todo <= 0 && wp == curwin && lnum == wp->w_cursor.lnum && conceal_cursor_line(wp) - && (int)wp->w_virtcol <= wlv.vcol + wlv.skip_cells) { + && (wlv.vcol + wlv.skip_cells >= wp->w_virtcol || mb_schar == NUL)) { wp->w_wcol = wlv.col - wlv.boguscols; + if (wlv.vcol + wlv.skip_cells < wp->w_virtcol) { + // Cursor beyond end of the line with 'virtualedit'. + wp->w_wcol += wp->w_virtcol - wlv.vcol - wlv.skip_cells; + } wp->w_wrow = wlv.row; did_wcol = true; wp->w_valid |= VALID_WCOL|VALID_WROW|VALID_VIRTCOL; @@ -2546,7 +2541,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s : wlv.char_attr; linebuf_attr[wlv.off] = eol_attr; - linebuf_vcol[wlv.off] = MAXCOL; + linebuf_vcol[wlv.off] = wlv.vcol; wlv.col++; wlv.off++; wlv.vcol++; @@ -2569,13 +2564,16 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s advance_color_col(&wlv, vcol_hlc(wlv)); - bool has_virttext = false; // Make sure alignment is the same regardless // if listchars=eol:X is used or not. const int eol_skip = (lcs_eol_todo && eol_hl_off == 0 ? 1 : 0); if (has_decor) { - has_virttext = decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip); + decor_redraw_eol(wp, &decor_state, &wlv.line_attr, wlv.col + eol_skip); + } + + for (int i = wlv.col; i < grid->cols; i++) { + linebuf_vcol[wlv.off + (i - wlv.col)] = wlv.vcol + (i - wlv.col); } if (((wp->w_p_cuc @@ -2583,7 +2581,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s && wp->w_virtcol < grid->cols * (ptrdiff_t)(wlv.row - startrow + 1) + start_col && lnum != wp->w_cursor.lnum) || wlv.color_cols || wlv.line_attr_lowprio || wlv.line_attr - || wlv.diff_hlf != 0 || has_virttext)) { + || wlv.diff_hlf != 0 || wp->w_buffer->terminal)) { int rightmost_vcol = get_rightmost_vcol(wp, wlv.color_cols); const int cuc_attr = win_hl_attr(wp, HLF_CUC); const int mc_attr = win_hl_attr(wp, HLF_MC); @@ -2597,47 +2595,39 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s : 0; const int base_attr = hl_combine_attr(wlv.line_attr_lowprio, diff_attr); - if (base_attr || wlv.line_attr || has_virttext) { + if (base_attr || wlv.line_attr || wp->w_buffer->terminal) { rightmost_vcol = INT_MAX; } while (wlv.col < grid->cols) { linebuf_char[wlv.off] = schar_from_ascii(' '); - linebuf_vcol[wlv.off] = MAXCOL; - wlv.col++; + advance_color_col(&wlv, vcol_hlc(wlv)); int col_attr = base_attr; - if (wp->w_p_cuc && vcol_hlc(wlv) == wp->w_virtcol) { - col_attr = cuc_attr; + if (wp->w_p_cuc && vcol_hlc(wlv) == wp->w_virtcol + && lnum != wp->w_cursor.lnum) { + col_attr = hl_combine_attr(col_attr, cuc_attr); } else if (wlv.color_cols && vcol_hlc(wlv) == *wlv.color_cols) { - col_attr = hl_combine_attr(wlv.line_attr_lowprio, mc_attr); + col_attr = hl_combine_attr(col_attr, mc_attr); + } + + if (wp->w_buffer->terminal && wlv.vcol < TERM_ATTRS_MAX) { + col_attr = hl_combine_attr(col_attr, term_attrs[wlv.vcol]); } col_attr = hl_combine_attr(col_attr, wlv.line_attr); linebuf_attr[wlv.off] = col_attr; + // linebuf_vcol[] already filled by the for loop above wlv.off++; + wlv.col++; + wlv.vcol++; - if (vcol_hlc(wlv) >= rightmost_vcol) { + if (vcol_hlc(wlv) > rightmost_vcol) { break; } - - wlv.vcol += 1; - } - } - - // TODO(bfredl): integrate with the common beyond-the-end-loop - if (wp->w_buffer->terminal) { - // terminal buffers may need to highlight beyond the end of the logical line - while (wlv.col >= 0 && wlv.col < grid->cols) { - linebuf_char[wlv.off] = schar_from_ascii(' '); - linebuf_attr[wlv.off] = wlv.vcol >= TERM_ATTRS_MAX ? 0 : term_attrs[wlv.vcol]; - linebuf_vcol[wlv.off] = wlv.vcol; - wlv.off++; - wlv.vcol++; - wlv.col++; } } @@ -2645,7 +2635,9 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s draw_virt_text_item(buf, win_col_offset, fold_vt, kHlModeCombine, grid->cols, 0); } draw_virt_text(wp, buf, win_col_offset, &wlv.col, wlv.row); - win_put_linebuf(wp, wlv.row, 0, wlv.col, grid->cols, bg_attr, false); + // Set increasing virtual columns in grid->vcols[] to set correct curswant + // (or "coladd" for 'virtualedit') when clicking after end of line. + wlv_put_linebuf(wp, &wlv, wlv.col, true, bg_attr, SLF_INC_VCOL); wlv.row++; // Update w_cline_height and w_cline_folded if the cursor line was @@ -2712,10 +2704,14 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } } - // Apply lowest-priority line attr now, so everything can override it. - wlv.char_attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.char_attr); + if (wlv.filler_todo <= 0) { + // Apply lowest-priority line attr now, so everything can override it. + wlv.char_attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.char_attr); + } - vcol_prev = wlv.vcol; + if (wlv.filler_todo <= 0) { + vcol_prev = wlv.vcol; + } // Store character to be displayed. // Skip characters that are left of the screen for 'nowrap'. @@ -2753,11 +2749,21 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.off++; wlv.col++; } else if (wp->w_p_cole > 0 && is_concealing) { + bool concealed_wide = utf_char2cells(mb_c) > 1; + wlv.skip_cells--; - wlv.vcol_off++; + wlv.vcol_off_co++; + if (concealed_wide) { + // When a double-width char is concealed, + // need to advance one more virtual column. + wlv.vcol++; + wlv.vcol_off_co++; + } + if (wlv.n_extra > 0) { - wlv.vcol_off += wlv.n_extra; + wlv.vcol_off_co += wlv.n_extra; } + if (is_wrapped) { // Special voodoo required if 'wrap' is on. // @@ -2778,7 +2784,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.n_attr = 0; } - if (utf_char2cells(mb_c) > 1) { + if (concealed_wide) { // Need to fill two screen columns. wlv.boguscols++; wlv.col++; @@ -2813,7 +2819,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s wlv.char_attr = vcol_save_attr; } - // restore attributes after "predeces" in 'listchars' + // restore attributes after "precedes" in 'listchars' if (n_attr3 > 0 && --n_attr3 == 0) { wlv.char_attr = saved_attr3; } @@ -2855,6 +2861,23 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s && !wp->w_p_rl; // Not right-to-left. int draw_col = wlv.col - wlv.boguscols; + + for (int i = draw_col; i < grid->cols; i++) { + linebuf_vcol[wlv.off + (i - draw_col)] = wlv.vcol - 1; + } + + // Apply 'cursorline' highlight. + if (wlv.boguscols != 0 && (wlv.line_attr_lowprio != 0 || wlv.line_attr != 0)) { + int attr = hl_combine_attr(wlv.line_attr_lowprio, wlv.line_attr); + while (draw_col < grid->cols) { + linebuf_char[wlv.off] = schar_from_char(' '); + linebuf_attr[wlv.off] = attr; + // linebuf_vcol[] already filled by the for loop above + wlv.off++; + draw_col++; + } + } + 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); @@ -2862,7 +2885,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s draw_virt_text(wp, buf, win_col_offset, &draw_col, wlv.row); } - win_put_linebuf(wp, wlv.row, 0, draw_col, grid->cols, bg_attr, wrap); + wlv_put_linebuf(wp, &wlv, draw_col, true, bg_attr, wrap ? SLF_WRAP : 0); if (wrap) { ScreenGrid *current_grid = grid; int current_row = wlv.row; @@ -2874,7 +2897,7 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s } wlv.boguscols = 0; - wlv.vcol_off = 0; + wlv.vcol_off_co = 0; wlv.row++; // When not wrapping and finished diff lines, break here. @@ -2922,19 +2945,28 @@ int win_line(win_T *wp, linenr_T lnum, int startrow, int endrow, int col_rows, s return wlv.row; } -static void win_put_linebuf(win_T *wp, int row, int coloff, int endcol, int clear_width, - int bg_attr, bool wrap) +/// Call grid_put_linebuf() using values from "wlv". +/// Also takes care of putting "<<<" on the first line for 'smoothscroll' +/// when 'showbreak' is not set. +/// +/// @param clear_end clear until the end of the screen line. +/// @param flags for grid_put_linebuf(), but shouldn't contain SLF_RIGHTLEFT. +static void wlv_put_linebuf(win_T *wp, const winlinevars_T *wlv, int endcol, bool clear_end, + int bg_attr, int flags) { ScreenGrid *grid = &wp->w_grid; - int start_col = 0; + int startcol = 0; + int clear_width = clear_end ? grid->cols : endcol; + assert(!(flags & SLF_RIGHTLEFT)); if (wp->w_p_rl) { - linebuf_mirror(&start_col, &endcol, &clear_width, grid->cols); + linebuf_mirror(&startcol, &endcol, &clear_width, grid->cols); + flags |= SLF_RIGHTLEFT; } // Take care of putting "<<<" on the first line for 'smoothscroll'. - if (row == 0 && wp->w_skipcol > 0 + if (wlv->row == 0 && wp->w_skipcol > 0 // do not overwrite the 'showbreak' text with "<<<" && *get_showbreak_value(wp) == NUL // do not overwrite the 'listchars' "precedes" text with "<<<" @@ -2959,6 +2991,8 @@ static void win_put_linebuf(win_T *wp, int row, int coloff, int endcol, int clea } } + int row = wlv->row; + int coloff = 0; grid_adjust(&grid, &row, &coloff); - grid_put_linebuf(grid, row, coloff, start_col, endcol, clear_width, wp->w_p_rl, bg_attr, wrap); + grid_put_linebuf(grid, row, coloff, startcol, endcol, clear_width, bg_attr, wlv->vcol - 1, flags); } diff --git a/src/nvim/drawscreen.c b/src/nvim/drawscreen.c index 145229bacc..bda0ccc870 100644 --- a/src/nvim/drawscreen.c +++ b/src/nvim/drawscreen.c @@ -59,6 +59,7 @@ #include <stdlib.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/ascii_defs.h" #include "nvim/autocmd.h" @@ -119,8 +120,6 @@ #include "nvim/vim_defs.h" #include "nvim/window.h" -#include "klib/kvec.h" - /// corner value flags for hsep_connected and vsep_connected typedef enum { WC_TOP_LEFT = 0, @@ -180,8 +179,12 @@ bool default_grid_alloc(void) // Allocation of the screen buffers is done only when the size changes and // when Rows and Columns have been set and we have started doing full // screen stuff. - if ((default_grid.chars != NULL && Rows == default_grid.rows && Columns == default_grid.cols) - || Rows == 0 || Columns == 0 || (!full_screen && default_grid.chars == NULL)) { + if ((default_grid.chars != NULL + && Rows == default_grid.rows + && Columns == default_grid.cols) + || Rows == 0 + || Columns == 0 + || (!full_screen && default_grid.chars == NULL)) { resizing = false; return false; } @@ -199,8 +202,8 @@ bool default_grid_alloc(void) grid_alloc(&default_grid, Rows, Columns, true, true); stl_clear_click_defs(tab_page_click_defs, tab_page_click_defs_size); - tab_page_click_defs - = stl_alloc_click_defs(tab_page_click_defs, Columns, &tab_page_click_defs_size); + tab_page_click_defs = stl_alloc_click_defs(tab_page_click_defs, Columns, + &tab_page_click_defs_size); default_grid.comp_height = Rows; default_grid.comp_width = Columns; @@ -223,7 +226,8 @@ void screenclear(void) // blank out the default grid for (int i = 0; i < default_grid.rows; i++) { - grid_clear_line(&default_grid, default_grid.line_offset[i], default_grid.cols, true); + grid_clear_line(&default_grid, default_grid.line_offset[i], + default_grid.cols, true); } ui_call_grid_clear(1); // clear the display @@ -270,7 +274,7 @@ void screen_resize(int width, int height) return; } - if (width < 0 || height < 0) { // just checking... + if (width < 0 || height < 0) { // just checking... return; } @@ -311,9 +315,9 @@ void screen_resize(int width, int height) RedrawingDisabled++; - win_new_screensize(); // fit the windows in the new sized screen + win_new_screensize(); // fit the windows in the new sized screen - comp_col(); // recompute columns for shown command and ruler + comp_col(); // recompute columns for shown command and ruler RedrawingDisabled--; @@ -407,7 +411,8 @@ void check_screensize(void) /// Return true if redrawing should currently be done. bool redrawing(void) { - return !RedrawingDisabled && !(p_lz && char_avail() && !KeyTyped && !do_redraw); + return !RedrawingDisabled + && !(p_lz && char_avail() && !KeyTyped && !do_redraw); } /// Redraw the parts of the screen that is marked for redraw. @@ -416,7 +421,14 @@ bool redrawing(void) /// and redraw_all_later() to mark parts of the screen as needing a redraw. int update_screen(void) { - static bool did_intro = false; + static bool still_may_intro = true; + if (still_may_intro) { + if (!may_show_intro()) { + redraw_later(firstwin, UPD_NOT_VALID); + still_may_intro = false; + } + } + bool is_stl_global = global_stl_height() > 0; // Don't do anything if the screen structures are (not yet) valid. @@ -478,7 +490,8 @@ int update_screen(void) if (msg_grid.chars) { // non-displayed part of msg_grid is considered invalid. for (int i = 0; i < MIN(msg_scrollsize(), msg_grid.rows); i++) { - grid_clear_line(&msg_grid, msg_grid.line_offset[i], msg_grid.cols, i < p_ch); + grid_clear_line(&msg_grid, msg_grid.line_offset[i], + msg_grid.cols, i < p_ch); } } msg_grid.throttled = false; @@ -488,7 +501,8 @@ int update_screen(void) if (type == UPD_NOT_VALID && !ui_has(kUIMultigrid) && msg_scrolled) { was_invalidated = ui_comp_set_screen_valid(false); for (int i = valid; i < Rows - p_ch; i++) { - grid_clear_line(&default_grid, default_grid.line_offset[i], Columns, false); + grid_clear_line(&default_grid, default_grid.line_offset[i], + Columns, false); } FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_floating) { @@ -534,10 +548,10 @@ int update_screen(void) hl_changed = true; } - if (type == UPD_CLEAR) { // first clear screen - screenclear(); // will reset clear_cmdline - // and set UPD_NOT_VALID for each window - cmdline_screen_cleared(); // clear external cmdline state + if (type == UPD_CLEAR) { // first clear screen + screenclear(); // will reset clear_cmdline + // and set UPD_NOT_VALID for each window + cmdline_screen_cleared(); // clear external cmdline state type = UPD_NOT_VALID; // must_redraw may be set indirectly, avoid another redraw later must_redraw = 0; @@ -561,7 +575,7 @@ int update_screen(void) redraw_tabline = true; } - if (clear_cmdline) { // going to clear cmdline (done below) + if (clear_cmdline) { // going to clear cmdline (done below) msg_check_for_delay(false); } @@ -570,9 +584,8 @@ int update_screen(void) // TODO(bfredl): special casing curwin here is SÅ JÄVLA BULL. // Either this should be done for all windows or not at all. if (curwin->w_redr_type < UPD_NOT_VALID - && curwin->w_nrwidth - != ((curwin->w_p_nu || curwin->w_p_rnu || *curwin->w_p_stc) ? number_width(curwin) - : 0)) { + && curwin->w_nrwidth != ((curwin->w_p_nu || curwin->w_p_rnu || *curwin->w_p_stc) + ? number_width(curwin) : 0)) { curwin->w_redr_type = UPD_NOT_VALID; } @@ -594,7 +607,8 @@ int update_screen(void) buf_T *buf = wp->w_buffer; if (buf->b_mod_set) { - if (buf->b_mod_tick_syn < display_tick && syntax_present(wp)) { + if (buf->b_mod_tick_syn < display_tick + && syntax_present(wp)) { syn_stack_apply_changes(buf); buf->b_mod_tick_syn = display_tick; } @@ -666,10 +680,9 @@ int update_screen(void) } // May put up an introductory message when not editing a file - if (!did_intro) { - maybe_intro_message(); + if (still_may_intro) { + intro_message(false); } - did_intro = true; decor_providers_invoke_end(); @@ -758,8 +771,8 @@ static void win_redr_border(win_T *wp) } if (wp->w_config.title) { - int title_col - = win_get_bordertext_col(icol, wp->w_config.title_width, wp->w_config.title_pos); + int title_col = win_get_bordertext_col(icol, wp->w_config.title_width, + wp->w_config.title_pos); win_redr_bordertext(wp, wp->w_config.title_chunks, title_col); } if (adj[1]) { @@ -794,8 +807,8 @@ static void win_redr_border(win_T *wp) } if (wp->w_config.footer) { - int footer_col - = win_get_bordertext_col(icol, wp->w_config.footer_width, wp->w_config.footer_pos); + int footer_col = win_get_bordertext_col(icol, wp->w_config.footer_width, + wp->w_config.footer_pos); win_redr_bordertext(wp, wp->w_config.footer_chunks, footer_col); } if (adj[1]) { @@ -808,24 +821,25 @@ static void win_redr_border(win_T *wp) /// Set cursor to its position in the current window. void setcursor(void) { - setcursor_mayforce(false); + setcursor_mayforce(curwin, false); } /// Set cursor to its position in the current window. /// @param force when true, also when not redrawing. -void setcursor_mayforce(bool force) +void setcursor_mayforce(win_T *wp, bool force) { if (force || redrawing()) { - validate_cursor(); + validate_cursor(wp); - ScreenGrid *grid = &curwin->w_grid; - int row = curwin->w_wrow; - int col = curwin->w_wcol; - if (curwin->w_p_rl) { + ScreenGrid *grid = &wp->w_grid; + int row = wp->w_wrow; + int col = wp->w_wcol; + if (wp->w_p_rl) { // With 'rightleft' set and the cursor on a double-wide character, // position it on the leftmost column. - col = curwin->w_width_inner - curwin->w_wcol - - ((utf_ptr2cells(get_cursor_pos_ptr()) == 2 && vim_isprintc(gchar_cursor())) ? 2 : 1); + char *cursor = ml_get_buf(wp->w_buffer, wp->w_cursor.lnum) + wp->w_cursor.col; + col = wp->w_width_inner - wp->w_wcol - ((utf_ptr2cells(cursor) == 2 + && vim_isprintc(utf_ptr2char(cursor))) ? 2 : 1); } grid_adjust(&grid, &row, &col); @@ -839,19 +853,22 @@ void setcursor_mayforce(bool force) void show_cursor_info_later(bool force) { int state = get_real_state(); - int empty_line - = (State & MODE_INSERT) == 0 && *ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum) == NUL; + int empty_line = (State & MODE_INSERT) == 0 + && *ml_get_buf(curwin->w_buffer, curwin->w_cursor.lnum) == NUL; // Only draw when something changed. - validate_virtcol_win(curwin); - if (force || curwin->w_cursor.lnum != curwin->w_stl_cursor.lnum + validate_virtcol(curwin); + if (force + || curwin->w_cursor.lnum != curwin->w_stl_cursor.lnum || curwin->w_cursor.col != curwin->w_stl_cursor.col || curwin->w_virtcol != curwin->w_stl_virtcol || curwin->w_cursor.coladd != curwin->w_stl_cursor.coladd || curwin->w_topline != curwin->w_stl_topline || curwin->w_buffer->b_ml.ml_line_count != curwin->w_stl_line_count - || curwin->w_topfill != curwin->w_stl_topfill || empty_line != curwin->w_stl_empty - || reg_recording != curwin->w_stl_recording || state != curwin->w_stl_state + || curwin->w_topfill != curwin->w_stl_topfill + || empty_line != curwin->w_stl_empty + || reg_recording != curwin->w_stl_recording + || state != curwin->w_stl_state || (VIsual_active && VIsual_mode != curwin->w_stl_visual_mode)) { if (curwin->w_status_height || global_stl_height()) { curwin->w_redr_status = true; @@ -863,7 +880,8 @@ void show_cursor_info_later(bool force) curwin->w_redr_status = true; } - if ((p_icon && (stl_syntax & STL_IN_ICON)) || (p_title && (stl_syntax & STL_IN_TITLE))) { + if ((p_icon && (stl_syntax & STL_IN_ICON)) + || (p_title && (stl_syntax & STL_IN_TITLE))) { need_maketitle = true; } } @@ -909,13 +927,21 @@ int showmode(void) msg_ext_clear(true); } - // don't make non-flushed message part of the showmode + // Don't make non-flushed message part of the showmode and reset global + // variables before flushing to to avoid recursiveness. + bool draw_mode = redraw_mode; + bool clear_cmd = clear_cmdline; + redraw_cmdline = false; + redraw_mode = false; + clear_cmdline = false; msg_ext_ui_flush(); msg_grid_validate(); bool do_mode = ((p_smd && msg_silent == 0) - && ((State & MODE_TERMINAL) || (State & MODE_INSERT) || restart_edit != NUL + && ((State & MODE_TERMINAL) + || (State & MODE_INSERT) + || restart_edit != NUL || VIsual_active)); bool can_show_mode = (p_ch != 0 || ui_has(kUIMessages)); @@ -930,14 +956,14 @@ int showmode(void) msg_check_for_delay(false); // if the cmdline is more than one line high, erase top lines - bool need_clear = clear_cmdline; - if (clear_cmdline && cmdline_row < Rows - 1) { + bool need_clear = clear_cmd; + if (clear_cmd && cmdline_row < Rows - 1) { msg_clr_cmdline(); // will reset clear_cmdline } // Position on the last line in the window, column 0 msg_pos_mode(); - int attr = HL_ATTR(HLF_CM); // Highlight mode + int attr = HL_ATTR(HLF_CM); // Highlight mode // When the screen is too narrow to show the entire mode message, // avoid scrolling and truncate instead. @@ -993,8 +1019,8 @@ int showmode(void) msg_puts_attr(_(" REVERSE"), attr); } msg_puts_attr(_(" INSERT"), attr); - } else if (restart_edit == 'I' || restart_edit == 'i' || restart_edit == 'a' - || restart_edit == 'A') { + } else if (restart_edit == 'I' || restart_edit == 'i' + || restart_edit == 'a' || restart_edit == 'A') { if (curbuf->terminal) { msg_puts_attr(_(" (terminal)"), attr); } else { @@ -1008,7 +1034,8 @@ int showmode(void) if (State & MODE_LANGMAP) { if (curwin->w_p_arab) { msg_puts_attr(_(" Arabic"), attr); - } else if (get_keymap_str(curwin, " (%s)", NameBuff, MAXPATHL)) { + } else if (get_keymap_str(curwin, " (%s)", + NameBuff, MAXPATHL)) { msg_puts_attr(NameBuff, attr); } } @@ -1021,25 +1048,21 @@ int showmode(void) // Don't concatenate separate words to avoid translation // problems. - switch ((VIsual_select ? 4 : 0) + (VIsual_mode == Ctrl_V) * 2 + (VIsual_mode == 'V')) { + switch ((VIsual_select ? 4 : 0) + + (VIsual_mode == Ctrl_V) * 2 + + (VIsual_mode == 'V')) { case 0: - p = N_(" VISUAL"); - break; + p = N_(" VISUAL"); break; case 1: - p = N_(" VISUAL LINE"); - break; + p = N_(" VISUAL LINE"); break; case 2: - p = N_(" VISUAL BLOCK"); - break; + p = N_(" VISUAL BLOCK"); break; case 4: - p = N_(" SELECT"); - break; + p = N_(" SELECT"); break; case 5: - p = N_(" SELECT LINE"); - break; + p = N_(" SELECT LINE"); break; default: - p = N_(" SELECT BLOCK"); - break; + p = N_(" SELECT BLOCK"); break; } msg_puts_attr(_(p), attr); } @@ -1048,26 +1071,27 @@ int showmode(void) need_clear = true; } - if (reg_recording != 0 && edit_submode == NULL // otherwise it gets too long - ) { + if (reg_recording != 0 + && edit_submode == NULL // otherwise it gets too long + ) { recording_mode(attr); need_clear = true; } mode_displayed = true; - if (need_clear || clear_cmdline || redraw_mode) { + if (need_clear || clear_cmd || draw_mode) { msg_clr_eos(); } - msg_didout = false; // overwrite this message + msg_didout = false; // overwrite this message length = msg_col; msg_col = 0; msg_no_more = false; lines_left = save_lines_left; - need_wait_return = nwr_save; // never ask for hit-return for this - } else if (clear_cmdline && msg_silent == 0) { + need_wait_return = nwr_save; // never ask for hit-return for this + } else if (clear_cmd && msg_silent == 0) { // Clear the whole command line. Will reset "clear_cmdline". msg_clr_cmdline(); - } else if (redraw_mode) { + } else if (draw_mode) { msg_pos_mode(); msg_clr_eos(); } @@ -1090,10 +1114,6 @@ int showmode(void) grid_line_flush(); } - redraw_cmdline = false; - redraw_mode = false; - clear_cmdline = false; - return length; } @@ -1142,14 +1162,12 @@ static void recording_mode(int attr) } msg_puts_attr(_("recording"), attr); - char reg_str[8]; - reg_str[utf_char2bytes(reg_recording, reg_str)] = 0; - char s[16]; - snprintf(s, ARRAY_SIZE(s), " @%s", reg_str); + char s[4]; + snprintf(s, ARRAY_SIZE(s), " @%c", reg_recording); msg_puts_attr(s, attr); } -#define COL_RULER 17 // columns needed by standard ruler +#define COL_RULER 17 // columns needed by standard ruler /// Compute columns for ruler and shown command. 'sc_col' is also used to /// decide what the maximum length of a message on the status line can be. @@ -1170,15 +1188,17 @@ void comp_col(void) } if (p_sc && *p_sloc == 'l') { sc_col += SHOWCMD_COLS; - if (!p_ru || last_has_status) { // no need for separating space + if (!p_ru || last_has_status) { // no need for separating space sc_col++; } } - assert(sc_col >= 0 && INT_MIN + sc_col <= Columns); + assert(sc_col >= 0 + && INT_MIN + sc_col <= Columns); sc_col = Columns - sc_col; - assert(ru_col >= 0 && INT_MIN + ru_col <= Columns); + assert(ru_col >= 0 + && INT_MIN + ru_col <= Columns); ru_col = Columns - ru_col; - if (sc_col <= 0) { // screen too narrow, will become a mess + if (sc_col <= 0) { // screen too narrow, will become a mess sc_col = 1; } if (ru_col <= 0) { @@ -1223,7 +1243,8 @@ static bool win_redraw_signcols(win_T *wp) static bool hsep_connected(win_T *wp, WindowCorner corner) { bool before = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT); - int sep_row = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) ? wp->w_winrow - 1 : W_ENDROW(wp); + int sep_row = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT) + ? wp->w_winrow - 1 : W_ENDROW(wp); frame_T *fr = wp->w_frame; while (fr->fr_parent != NULL) { @@ -1257,8 +1278,8 @@ static bool hsep_connected(win_T *wp, WindowCorner corner) static bool vsep_connected(win_T *wp, WindowCorner corner) { bool before = (corner == WC_TOP_LEFT || corner == WC_TOP_RIGHT); - int sep_col - = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) ? wp->w_wincol - 1 : W_ENDCOL(wp); + int sep_col = (corner == WC_TOP_LEFT || corner == WC_BOTTOM_LEFT) + ? wp->w_wincol - 1 : W_ENDCOL(wp); frame_T *fr = wp->w_frame; while (fr->fr_parent != NULL) { @@ -1423,19 +1444,19 @@ static void draw_sep_connectors_win(win_T *wp) /// bot: from bot_start to last row (when scrolled up) static void win_update(win_T *wp) { - int top_end = 0; // Below last row of the top area that needs - // updating. 0 when no top area updating. - int mid_start = 999; // first row of the mid area that needs - // updating. 999 when no mid area updating. - int mid_end = 0; // Below last row of the mid area that needs - // updating. 0 when no mid area updating. - int bot_start = 999; // first row of the bot area that needs - // updating. 999 when no bot area updating - bool scrolled_down = false; // true when scrolled down when w_topline got smaller a bit - bool top_to_mod = false; // redraw above mod_top - - int bot_scroll_start = 999; // first line that needs to be redrawn due to - // scrolling. only used for EOB + int top_end = 0; // Below last row of the top area that needs + // updating. 0 when no top area updating. + int mid_start = 999; // first row of the mid area that needs + // updating. 999 when no mid area updating. + int mid_end = 0; // Below last row of the mid area that needs + // updating. 0 when no mid area updating. + int bot_start = 999; // first row of the bot area that needs + // updating. 999 when no bot area updating + bool scrolled_down = false; // true when scrolled down when w_topline got smaller a bit + bool top_to_mod = false; // redraw above mod_top + + int bot_scroll_start = 999; // first line that needs to be redrawn due to + // scrolling. only used for EOB static bool recursive = false; // being called recursively @@ -1444,10 +1465,9 @@ static void win_update(win_T *wp) DID_NONE = 1, // didn't update a line DID_LINE = 2, // updated a normal line DID_FOLD = 3, // updated a folded line - } did_update - = DID_NONE; + } did_update = DID_NONE; - linenr_T syntax_last_parsed = 0; // last parsed text line + linenr_T syntax_last_parsed = 0; // last parsed text line linenr_T mod_top = 0; linenr_T mod_bot = 0; @@ -1501,7 +1521,7 @@ static void win_update(win_T *wp) // Make sure skipcol is valid, it depends on various options and the window // width. - if (wp->w_skipcol > 0) { + if (wp->w_skipcol > 0 && wp->w_width_inner > win_col_off(wp)) { int w = 0; int width1 = wp->w_width_inner - win_col_off(wp); int width2 = width1 + win_col_off2(wp); @@ -1555,12 +1575,14 @@ static void win_update(win_T *wp) // previous line invalid. Simple solution: redraw all visible // lines above the change. // Same for a match pattern. - if (screen_search_hl.rm.regprog != NULL && re_multiline(screen_search_hl.rm.regprog)) { + if (screen_search_hl.rm.regprog != NULL + && re_multiline(screen_search_hl.rm.regprog)) { top_to_mod = true; } else { const matchitem_T *cur = wp->w_match_head; while (cur != NULL) { - if (cur->mit_match.regprog != NULL && re_multiline(cur->mit_match.regprog)) { + if (cur->mit_match.regprog != NULL + && re_multiline(cur->mit_match.regprog)) { top_to_mod = true; break; } @@ -1597,14 +1619,14 @@ static void win_update(win_T *wp) } } - hasFoldingWin(wp, mod_top, &mod_top, NULL, true, NULL); + hasFolding(wp, mod_top, &mod_top, NULL); if (mod_top > lnumt) { mod_top = lnumt; } // Now do the same for the bottom line (one above mod_bot). mod_bot--; - hasFoldingWin(wp, mod_bot, NULL, &mod_bot, true, NULL); + hasFolding(wp, mod_bot, NULL, &mod_bot); mod_bot++; if (mod_bot < lnumb) { mod_bot = lnumb; @@ -1653,11 +1675,13 @@ static void win_update(win_T *wp) // 2: wp->w_topline is below wp->w_lines[0].wl_lnum: may scroll up // 3: wp->w_topline is wp->w_lines[0].wl_lnum: find first entry in // w_lines[] that needs updating. - if ((type == UPD_VALID || type == UPD_SOME_VALID || type == UPD_INVERTED - || type == UPD_INVERTED_ALL) + if ((type == UPD_VALID || type == UPD_SOME_VALID + || type == UPD_INVERTED || type == UPD_INVERTED_ALL) && !wp->w_botfill && !wp->w_old_botfill) { - if (mod_top != 0 && wp->w_topline == mod_top - && (!wp->w_lines[0].wl_valid || wp->w_topline == wp->w_lines[0].wl_lnum)) { + if (mod_top != 0 + && wp->w_topline == mod_top + && (!wp->w_lines[0].wl_valid + || wp->w_topline == wp->w_lines[0].wl_lnum)) { // w_topline is the first changed line and window is not scrolled, // the scrolling from changed lines will be done further down. } else if (wp->w_lines[0].wl_valid @@ -1675,13 +1699,13 @@ static void win_update(win_T *wp) if (j >= wp->w_grid.rows - 2) { break; } - hasFoldingWin(wp, ln, NULL, &ln, true, NULL); + hasFolding(wp, ln, NULL, &ln); } } else { j = wp->w_lines[0].wl_lnum - wp->w_topline; } - if (j < wp->w_grid.rows - 2) { // not too far off - int i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1, true); + if (j < wp->w_grid.rows - 2) { // not too far off + int i = plines_m_win(wp, wp->w_topline, wp->w_lines[0].wl_lnum - 1, wp->w_height_inner); // insert extra lines for previously invisible filler lines if (wp->w_lines[0].wl_lnum != wp->w_topline) { i += win_get_fill(wp, wp->w_lines[0].wl_lnum) - wp->w_old_topfill; @@ -1726,7 +1750,8 @@ static void win_update(win_T *wp) int j = -1; int row = 0; for (int i = 0; i < wp->w_lines_valid; i++) { - if (wp->w_lines[i].wl_valid && wp->w_lines[i].wl_lnum == wp->w_topline) { + if (wp->w_lines[i].wl_valid + && wp->w_lines[i].wl_lnum == wp->w_topline) { j = i; break; } @@ -1765,7 +1790,8 @@ static void win_update(win_T *wp) wp->w_lines[idx] = wp->w_lines[j]; // stop at line that didn't fit, unless it is still // valid (no lines deleted) - if (row > 0 && bot_start + row + (int)wp->w_lines[j].wl_size > wp->w_grid.rows) { + if (row > 0 && bot_start + row + + (int)wp->w_lines[j].wl_size > wp->w_grid.rows) { wp->w_lines_valid = idx + 1; break; } @@ -1781,8 +1807,8 @@ static void win_update(win_T *wp) // Correct the first entry for filler lines at the top // when it won't get updated below. if (win_may_fill(wp) && bot_start > 0) { - wp->w_lines[0].wl_size - = (uint16_t)(plines_win_nofill(wp, wp->w_topline, true) + wp->w_topfill); + wp->w_lines[0].wl_size = (uint16_t)(plines_win_nofill(wp, wp->w_topline, true) + + wp->w_topfill); } } } @@ -1845,13 +1871,15 @@ static void win_update(win_T *wp) } else { from = wp->w_old_cursor_lnum; to = curwin->w_cursor.lnum; - if (from == 0) { // Visual mode just started + if (from == 0) { // Visual mode just started from = to; } } - if (VIsual.lnum != wp->w_old_visual_lnum || VIsual.col != wp->w_old_visual_col) { - if (wp->w_old_visual_lnum < from && wp->w_old_visual_lnum != 0) { + if (VIsual.lnum != wp->w_old_visual_lnum + || VIsual.col != wp->w_old_visual_col) { + if (wp->w_old_visual_lnum < from + && wp->w_old_visual_lnum != 0) { from = wp->w_old_visual_lnum; } if (wp->w_old_visual_lnum > to) { @@ -1883,7 +1911,7 @@ static void win_update(win_T *wp) // Highlight to the end of the line, unless 'virtualedit' has // "block". if (curwin->w_curswant == MAXCOL) { - if (get_ve_flags() & VE_BLOCK) { + if (get_ve_flags(curwin) & VE_BLOCK) { pos_T pos; int cursor_above = curwin->w_cursor.lnum < VIsual.lnum; @@ -1907,7 +1935,8 @@ static void win_update(win_T *wp) } } - if (fromc != wp->w_old_cursor_fcol || toc != wp->w_old_cursor_lcol) { + if (fromc != wp->w_old_cursor_fcol + || toc != wp->w_old_cursor_lcol) { if (from > VIsual.lnum) { from = VIsual.lnum; } @@ -1961,7 +1990,7 @@ static void win_update(win_T *wp) } else { mid_start = 0; } - while (lnum < from && idx < wp->w_lines_valid) { // find start + while (lnum < from && idx < wp->w_lines_valid) { // find start if (wp->w_lines[idx].wl_valid) { mid_start += wp->w_lines[idx].wl_size; } else if (!scrolled_down) { @@ -1976,8 +2005,9 @@ static void win_update(win_T *wp) } srow += mid_start; mid_end = wp->w_grid.rows; - for (; idx < wp->w_lines_valid; idx++) { // find end - if (wp->w_lines[idx].wl_valid && wp->w_lines[idx].wl_lnum >= to + 1) { + for (; idx < wp->w_lines_valid; idx++) { // find end + if (wp->w_lines[idx].wl_valid + && wp->w_lines[idx].wl_lnum >= to + 1) { // Only update until first row of this line mid_end = srow; break; @@ -2021,12 +2051,12 @@ static void win_update(win_T *wp) } // Update all the window rows. - int idx = 0; // first entry in w_lines[].wl_size - int row = 0; // current window row to display - int srow = 0; // starting row of the current line + int idx = 0; // first entry in w_lines[].wl_size + int row = 0; // current window row to display + int srow = 0; // starting row of the current line - bool eof = false; // if true, we hit the end of the file - bool didline = false; // if true, we finished the last line + bool eof = false; // if true, we hit the end of the file + bool didline = false; // if true, we finished the last line while (true) { // stop updating when reached the end of the window (check for _past_ // the end of the window is at the end of the loop) @@ -2052,19 +2082,27 @@ static void win_update(win_T *wp) // When syntax folding is being used, the saved syntax states will // already have been updated, we can't see where the syntax state is // the same again, just update until the end of the window. - if (row < top_end || (row >= mid_start && row < mid_end) || top_to_mod - || idx >= wp->w_lines_valid || (row + wp->w_lines[idx].wl_size > bot_start) + if (row < top_end + || (row >= mid_start && row < mid_end) + || top_to_mod + || idx >= wp->w_lines_valid + || (row + wp->w_lines[idx].wl_size > bot_start) || (mod_top != 0 && (lnum == mod_top || (lnum >= mod_top - && (lnum < mod_bot || did_update == DID_FOLD - || (did_update == DID_LINE && syntax_present(wp) - && ((foldmethodIsSyntax(wp) && hasAnyFolding(wp)) + && (lnum < mod_bot + || did_update == DID_FOLD + || (did_update == DID_LINE + && syntax_present(wp) + && ((foldmethodIsSyntax(wp) + && hasAnyFolding(wp)) || syntax_check_changed(lnum))) // match in fixed position might need redraw // if lines were inserted or deleted - || (wp->w_match_head != NULL && buf->b_mod_xlines != 0))))) - || lnum == wp->w_cursorline || lnum == wp->w_last_cursorline) { + || (wp->w_match_head != NULL + && buf->b_mod_xlines != 0))))) + || lnum == wp->w_cursorline + || lnum == wp->w_last_cursorline) { if (lnum == mod_top) { top_to_mod = false; } @@ -2074,7 +2112,9 @@ static void win_update(win_T *wp) // Don't do this when the change continues until the end. // Don't scroll when dollar_vcol >= 0, keep the "$". // Don't scroll when redrawing the top, scrolled already above. - if (lnum == mod_top && mod_bot != MAXLNUM && !(dollar_vcol >= 0 && mod_bot == mod_top + 1) + if (lnum == mod_top + && mod_bot != MAXLNUM + && !(dollar_vcol >= 0 && mod_bot == mod_top + 1) && row >= top_end) { int old_rows = 0; linenr_T l; @@ -2086,15 +2126,18 @@ static void win_update(win_T *wp) for (i = idx; i < wp->w_lines_valid; i++) { // Only valid lines have a meaningful wl_lnum. Invalid // lines are part of the changed area. - if (wp->w_lines[i].wl_valid && wp->w_lines[i].wl_lnum == mod_bot) { + if (wp->w_lines[i].wl_valid + && wp->w_lines[i].wl_lnum == mod_bot) { break; } old_rows += wp->w_lines[i].wl_size; - if (wp->w_lines[i].wl_valid && wp->w_lines[i].wl_lastlnum + 1 == mod_bot) { + if (wp->w_lines[i].wl_valid + && wp->w_lines[i].wl_lastlnum + 1 == mod_bot) { // Must have found the last valid entry above mod_bot. // Add following invalid entries. i++; - while (i < wp->w_lines_valid && !wp->w_lines[i].wl_valid) { + while (i < wp->w_lines_valid + && !wp->w_lines[i].wl_valid) { old_rows += wp->w_lines[i++].wl_size; } break; @@ -2113,7 +2156,7 @@ static void win_update(win_T *wp) // rows, and may insert/delete lines int j = idx; for (l = lnum; l < mod_bot; l++) { - if (hasFoldingWin(wp, l, NULL, &l, true, NULL)) { + if (hasFolding(wp, l, NULL, &l)) { new_rows++; } else if (l == wp->w_topline) { int n = plines_win_nofill(wp, l, false) + wp->w_topfill; @@ -2177,7 +2220,8 @@ static void win_update(win_T *wp) } wp->w_lines[j] = wp->w_lines[i]; // stop at a line that won't fit - if (x + (int)wp->w_lines[j].wl_size > wp->w_grid.rows) { + if (x + (int)wp->w_lines[j].wl_size + > wp->w_grid.rows) { wp->w_lines_valid = j + 1; break; } @@ -2187,8 +2231,8 @@ static void win_update(win_T *wp) if (bot_start > x) { bot_start = x; } - } else { // j > i - // move entries in w_lines[] downwards + } else { // j > i + // move entries in w_lines[] downwards j -= i; wp->w_lines_valid += (linenr_T)j; if (wp->w_lines_valid > wp->w_grid.rows) { @@ -2213,20 +2257,25 @@ static void win_update(win_T *wp) // When lines are folded, display one line for all of them. // Otherwise, display normally (can be several display lines when // 'wrap' is on). - foldinfo_T foldinfo - = wp->w_p_cul && lnum == wp->w_cursor.lnum ? cursorline_fi : fold_info(wp, lnum); - - if (foldinfo.fi_lines == 0 && idx < wp->w_lines_valid && wp->w_lines[idx].wl_valid - && wp->w_lines[idx].wl_lnum == lnum && lnum > wp->w_topline + foldinfo_T foldinfo = wp->w_p_cul && lnum == wp->w_cursor.lnum + ? cursorline_fi : fold_info(wp, lnum); + + if (foldinfo.fi_lines == 0 + && idx < wp->w_lines_valid + && wp->w_lines[idx].wl_valid + && wp->w_lines[idx].wl_lnum == lnum + && lnum > wp->w_topline && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) - && srow + wp->w_lines[idx].wl_size > wp->w_grid.rows && win_get_fill(wp, lnum) == 0) { + && srow + wp->w_lines[idx].wl_size > wp->w_grid.rows + && win_get_fill(wp, lnum) == 0) { // This line is not going to fit. Don't draw anything here, // will draw "@ " lines below. row = wp->w_grid.rows + 1; } else { prepare_search_hl(wp, &screen_search_hl, lnum); // Let the syntax stuff know we skipped a few lines. - if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum && syntax_present(wp)) { + if (syntax_last_parsed != 0 && syntax_last_parsed + 1 < lnum + && syntax_present(wp)) { syntax_end_parsing(wp, syntax_last_parsed + 1); } @@ -2234,8 +2283,8 @@ static void win_update(win_T *wp) // Display one line spellvars_T zero_spv = { 0 }; - row = win_line(wp, lnum, srow, wp->w_grid.rows, 0, display_buf_line ? &spv : &zero_spv, - foldinfo); + row = win_line(wp, lnum, srow, wp->w_grid.rows, 0, + display_buf_line ? &spv : &zero_spv, foldinfo); if (display_buf_line) { syntax_last_parsed = lnum; @@ -2258,7 +2307,7 @@ static void win_update(win_T *wp) wp->w_lines[idx].wl_lnum = lnum; wp->w_lines[idx].wl_valid = true; - if (row > wp->w_grid.rows) { // past end of grid + if (row > wp->w_grid.rows) { // past end of grid // we may need the size of that too long line later on if (dollar_vcol == -1) { wp->w_lines[idx].wl_size = (uint16_t)plines_win(wp, lnum, true); @@ -2278,8 +2327,8 @@ static void win_update(win_T *wp) // the text doesn't need to be redrawn, but the number column does. if ((wp->w_p_nu && mod_top != 0 && lnum >= mod_bot && buf->b_mod_xlines != 0) || (wp->w_p_rnu && wp->w_last_cursor_lnum_rnu != wp->w_cursor.lnum)) { - foldinfo_T info - = wp->w_p_cul && lnum == wp->w_cursor.lnum ? cursorline_fi : fold_info(wp, lnum); + foldinfo_T info = wp->w_p_cul && lnum == wp->w_cursor.lnum + ? cursorline_fi : fold_info(wp, lnum); win_line(wp, lnum, srow, wp->w_grid.rows, wp->w_lines[idx].wl_size, &spv, info); } @@ -2295,7 +2344,7 @@ static void win_update(win_T *wp) // 'statuscolumn' width has changed or errored, start from the top. if (wp->w_redr_statuscol) { - redr_statuscol: +redr_statuscol: wp->w_redr_statuscol = false; idx = 0; row = 0; @@ -2345,7 +2394,7 @@ static void win_update(win_T *wp) // Window ends in filler lines. wp->w_botline = lnum; wp->w_filler_rows = wp->w_grid.rows - srow; - } else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate" + } else if (dy_flags & DY_TRUNCATE) { // 'display' has "truncate" // Last line isn't finished: Display "@@@" in the last screen line. grid_line_start(&wp->w_grid, wp->w_grid.rows - 1); grid_line_fill(0, MIN(wp->w_grid.cols, 3), wp->w_p_fcs_chars.lastline, at_attr); @@ -2353,18 +2402,19 @@ static void win_update(win_T *wp) grid_line_flush(); set_empty_rows(wp, srow); wp->w_botline = lnum; - } else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline" + } else if (dy_flags & DY_LASTLINE) { // 'display' has "lastline" // Last line isn't finished: Display "@@@" at the end. // If this would split a doublewidth char in two, we need to display "@@@@" instead grid_line_start(&wp->w_grid, wp->w_grid.rows - 1); int width = grid_line_getchar(MAX(wp->w_grid.cols - 3, 0), NULL) == NUL ? 4 : 3; - grid_line_fill(MAX(wp->w_grid.cols - width, 0), wp->w_grid.cols, wp->w_p_fcs_chars.lastline, - at_attr); + grid_line_fill(MAX(wp->w_grid.cols - width, 0), wp->w_grid.cols, + wp->w_p_fcs_chars.lastline, at_attr); grid_line_flush(); set_empty_rows(wp, srow); wp->w_botline = lnum; } else { - win_draw_end(wp, wp->w_p_fcs_chars.lastline, true, srow, wp->w_grid.rows, HLF_AT); + win_draw_end(wp, wp->w_p_fcs_chars.lastline, true, srow, + wp->w_grid.rows, HLF_AT); set_empty_rows(wp, srow); wp->w_botline = lnum; } @@ -2400,7 +2450,9 @@ static void win_update(win_T *wp) lastline = 0; } - win_draw_end(wp, wp->w_p_fcs_chars.eob, false, MAX(lastline, row), wp->w_grid.rows, HLF_EOB); + win_draw_end(wp, wp->w_p_fcs_chars.eob, false, MAX(lastline, row), + wp->w_grid.rows, + HLF_EOB); set_empty_rows(wp, row); } @@ -2418,9 +2470,9 @@ static void win_update(win_T *wp) // Send win_extmarks if needed for (size_t n = 0; n < kv_size(win_extmark_arr); n++) { - ui_call_win_extmark(wp->w_grid_alloc.handle, wp->handle, kv_A(win_extmark_arr, n).ns_id, - (Integer)kv_A(win_extmark_arr, n).mark_id, kv_A(win_extmark_arr, n).win_row, - kv_A(win_extmark_arr, n).win_col); + ui_call_win_extmark(wp->w_grid_alloc.handle, wp->handle, + kv_A(win_extmark_arr, n).ns_id, (Integer)kv_A(win_extmark_arr, n).mark_id, + kv_A(win_extmark_arr, n).win_row, kv_A(win_extmark_arr, n).win_col); } if (dollar_vcol == -1) { @@ -2478,9 +2530,11 @@ void win_scroll_lines(win_T *wp, int row, int line_count) } if (line_count < 0) { - grid_del_lines(&wp->w_grid, row, -line_count, wp->w_grid.rows, 0, wp->w_grid.cols); + grid_del_lines(&wp->w_grid, row, -line_count, + wp->w_grid.rows, 0, wp->w_grid.cols); } else { - grid_ins_lines(&wp->w_grid, row, line_count, wp->w_grid.rows, 0, wp->w_grid.cols); + grid_ins_lines(&wp->w_grid, row, line_count, + wp->w_grid.rows, 0, wp->w_grid.cols); } } @@ -2599,7 +2653,7 @@ void redraw_later(win_T *wp, int type) if (type >= UPD_NOT_VALID) { wp->w_lines_valid = 0; } - if (must_redraw < type) { // must_redraw is the maximum of all windows + if (must_redraw < type) { // must_redraw is the maximum of all windows must_redraw = type; } } @@ -2662,7 +2716,8 @@ void redraw_buf_line_later(buf_T *buf, linenr_T line, bool force) void redraw_buf_range_later(buf_T *buf, linenr_T firstline, linenr_T lastline) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == buf && lastline >= wp->w_topline && firstline < wp->w_botline) { + if (wp->w_buffer == buf + && lastline >= wp->w_topline && firstline < wp->w_botline) { if (wp->w_redraw_top == 0 || wp->w_redraw_top > firstline) { wp->w_redraw_top = firstline; } @@ -2679,7 +2734,9 @@ void redraw_buf_status_later(buf_T *buf) { FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp->w_buffer == buf - && (wp->w_status_height || (wp == curwin && global_stl_height()) || wp->w_winbar_height)) { + && (wp->w_status_height + || (wp == curwin && global_stl_height()) + || wp->w_winbar_height)) { wp->w_redr_status = true; set_must_redraw(UPD_VALID); } @@ -2692,7 +2749,8 @@ void status_redraw_all(void) bool is_stl_global = global_stl_height() != 0; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if ((!is_stl_global && wp->w_status_height) || wp == curwin || wp->w_winbar_height) { + if ((!is_stl_global && wp->w_status_height) || wp == curwin + || wp->w_winbar_height) { wp->w_redr_status = true; redraw_later(wp, UPD_VALID); } @@ -2711,9 +2769,8 @@ void status_redraw_buf(buf_T *buf) bool is_stl_global = global_stl_height() != 0; FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - if (wp->w_buffer == buf - && ((!is_stl_global && wp->w_status_height) || (is_stl_global && wp == curwin) - || wp->w_winbar_height)) { + if (wp->w_buffer == buf && ((!is_stl_global && wp->w_status_height) + || (is_stl_global && wp == curwin) || wp->w_winbar_height)) { wp->w_redr_status = true; redraw_later(wp, UPD_VALID); } @@ -2743,7 +2800,8 @@ void redraw_statuslines(void) } /// Redraw all status lines at the bottom of frame "frp". -void win_redraw_last_status(const frame_T *frp) FUNC_ATTR_NONNULL_ARG(1) +void win_redraw_last_status(const frame_T *frp) + FUNC_ATTR_NONNULL_ARG(1) { if (frp->fr_layout == FR_LEAF) { frp->fr_win->w_redr_status = true; @@ -2767,9 +2825,11 @@ void win_redraw_last_status(const frame_T *frp) FUNC_ATTR_NONNULL_ARG(1) /// Used to remove the "$" from a change command. /// Note that when also inserting/deleting lines w_redraw_top and w_redraw_bot /// may become invalid and the whole window will have to be redrawn. -void redrawWinline(win_T *wp, linenr_T lnum) FUNC_ATTR_NONNULL_ALL +void redrawWinline(win_T *wp, linenr_T lnum) + FUNC_ATTR_NONNULL_ALL { - if (lnum >= wp->w_topline && lnum < wp->w_botline) { + if (lnum >= wp->w_topline + && lnum < wp->w_botline) { if (wp->w_redraw_top == 0 || wp->w_redraw_top > lnum) { wp->w_redraw_top = lnum; } @@ -2782,7 +2842,8 @@ void redrawWinline(win_T *wp, linenr_T lnum) FUNC_ATTR_NONNULL_ALL /// Return true if the cursor line in window "wp" may be concealed, according /// to the 'concealcursor' option. -bool conceal_cursor_line(const win_T *wp) FUNC_ATTR_NONNULL_ALL +bool conceal_cursor_line(const win_T *wp) + FUNC_ATTR_NONNULL_ALL { int c; @@ -2806,7 +2867,8 @@ bool conceal_cursor_line(const win_T *wp) FUNC_ATTR_NONNULL_ALL /// Whether cursorline is drawn in a special way /// /// If true, both old and new cursorline will need to be redrawn when moving cursor within windows. -bool win_cursorline_standout(const win_T *wp) FUNC_ATTR_NONNULL_ALL +bool win_cursorline_standout(const win_T *wp) + FUNC_ATTR_NONNULL_ALL { return wp->w_p_cul || (wp->w_p_cole > 0 && !conceal_cursor_line(wp)); } diff --git a/src/nvim/edit.c b/src/nvim/edit.c index b7b32883c2..220b92d099 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -185,7 +185,7 @@ static void insert_enter(InsertState *s) curwin->w_cursor = save_cursor; State = MODE_INSERT; - check_cursor_col(); + check_cursor_col(curwin); State = save_state; } } @@ -282,7 +282,7 @@ static void insert_enter(InsertState *s) // correct in very rare cases). // Also do this if curswant is greater than the current virtual // column. Eg after "^O$" or "^O80|". - validate_virtcol(); + validate_virtcol(curwin); update_curswant(); if (((ins_at_eol && curwin->w_cursor.lnum == o_lnum) || curwin->w_curswant > curwin->w_virtcol) @@ -365,9 +365,10 @@ static void insert_enter(InsertState *s) did_cursorhold = false; // ins_redraw() triggers TextChangedI only when no characters - // are in the typeahead buffer, so only reset curbuf->b_last_changedtick + // are in the typeahead buffer, so reset curbuf->b_last_changedtick // if the TextChangedI was not blocked by char_avail() (e.g. using :norm!) - if (!char_avail()) { + // and the TextChangedI autocommand has been triggered. + if (!char_avail() && curbuf->b_last_changedtick_i == buf_get_changedtick(curbuf)) { curbuf->b_last_changedtick = buf_get_changedtick(curbuf); } } @@ -468,7 +469,7 @@ static int insert_check(VimState *state) && curwin->w_topline == s->old_topline && curwin->w_topfill == s->old_topfill) { s->mincol = curwin->w_wcol; - validate_cursor_col(); + validate_cursor_col(curwin); if (curwin->w_wcol < s->mincol - tabstop_at(get_nolist_virtcol(), curbuf->b_p_ts, @@ -478,7 +479,7 @@ static int insert_check(VimState *state) || curwin->w_topfill > 0)) { if (curwin->w_topfill > 0) { curwin->w_topfill--; - } else if (hasFolding(curwin->w_topline, NULL, &s->old_topline)) { + } else if (hasFolding(curwin, curwin->w_topline, NULL, &s->old_topline)) { set_topline(curwin, s->old_topline + 1); } else { set_topline(curwin, curwin->w_topline + 1); @@ -491,7 +492,7 @@ static int insert_check(VimState *state) s->did_backspace = false; - validate_cursor(); // may set must_redraw + validate_cursor(curwin); // may set must_redraw // Redraw the display when no characters are waiting. // Also shows mode, ruler and positions cursor. @@ -743,7 +744,7 @@ static int insert_handle_key(InsertState *s) ins_ctrl_o(); // don't move the cursor left when 'virtualedit' has "onemore". - if (get_ve_flags() & VE_ONEMORE) { + if (get_ve_flags(curwin) & VE_ONEMORE) { ins_at_eol = false; s->nomove = true; } @@ -1451,7 +1452,7 @@ void edit_putchar(int c, bool highlight) int attr; update_topline(curwin); // just in case w_topline isn't valid - validate_cursor(); + validate_cursor(curwin); if (highlight) { attr = HL_ATTR(HLF_8); } else { @@ -1521,7 +1522,7 @@ static void init_prompt(int cmdchar_todo) ml_append(curbuf->b_ml.ml_line_count, prompt, 0, false); } curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); inserted_bytes(curbuf->b_ml.ml_line_count, 0, 0, (colnr_T)strlen(prompt)); } @@ -1536,13 +1537,13 @@ static void init_prompt(int cmdchar_todo) } if (cmdchar_todo == 'A') { - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } if (curwin->w_cursor.col < (colnr_T)strlen(prompt)) { curwin->w_cursor.col = (colnr_T)strlen(prompt); } // Make sure the cursor is in a valid position. - check_cursor(); + check_cursor(curwin); } /// @return true if the cursor is in the editable position of the prompt line. @@ -2394,7 +2395,7 @@ static void stop_insert(pos_T *end_insert_pos, int esc, int nomove) pos_T tpos = curwin->w_cursor; curwin->w_cursor = *end_insert_pos; - check_cursor_col(); // make sure it is not past the line + check_cursor_col(curwin); // make sure it is not past the line while (true) { if (gchar_cursor() == NUL && curwin->w_cursor.col > 0) { curwin->w_cursor.col--; @@ -2471,7 +2472,7 @@ void free_last_insert(void) void beginline(int flags) { if ((flags & BL_SOL) && !p_sol) { - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } else { curwin->w_cursor.col = 0; curwin->w_cursor.coladd = 0; @@ -2497,13 +2498,13 @@ int oneright(void) { char *ptr; - if (virtual_active()) { + if (virtual_active(curwin)) { pos_T prevpos = curwin->w_cursor; // Adjust for multi-wide char (excluding TAB) ptr = get_cursor_pos_ptr(); - coladvance(getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) - ? ptr2cells(ptr) : 1)); + coladvance(curwin, getviscol() + ((*ptr != TAB && vim_isprintc(utf_ptr2char(ptr))) + ? ptr2cells(ptr) : 1)); curwin->w_set_curswant = true; // Return OK if the cursor moved, FAIL otherwise (at window edge). return (prevpos.col != curwin->w_cursor.col @@ -2519,7 +2520,7 @@ int oneright(void) // move "l" bytes right, but don't end up on the NUL, unless 'virtualedit' // contains "onemore". - if (ptr[l] == NUL && (get_ve_flags() & VE_ONEMORE) == 0) { + if (ptr[l] == NUL && (get_ve_flags(curwin) & VE_ONEMORE) == 0) { return FAIL; } curwin->w_cursor.col += l; @@ -2531,7 +2532,7 @@ int oneright(void) int oneleft(void) { - if (virtual_active()) { + if (virtual_active(curwin)) { int v = getviscol(); if (v == 0) { @@ -2541,7 +2542,7 @@ int oneleft(void) // We might get stuck on 'showbreak', skip over it. int width = 1; while (true) { - coladvance(v - width); + coladvance(curwin, v - width); // getviscol() is slow, skip it when 'showbreak' is empty, // 'breakindent' is not set and there are no multi-byte // characters @@ -2590,7 +2591,7 @@ void cursor_up_inner(win_T *wp, linenr_T n) // Count each sequence of folded lines as one logical line. // go to the start of the current fold - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); while (n--) { // move up one line @@ -2602,7 +2603,7 @@ void cursor_up_inner(win_T *wp, linenr_T n) // Insert mode or when 'foldopen' contains "all": it will open // in a moment. if (n > 0 || !((State & MODE_INSERT) || (fdo_flags & FDO_ALL))) { - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); } } if (lnum < 1) { @@ -2625,7 +2626,7 @@ int cursor_up(linenr_T n, bool upd_topline) cursor_up_inner(curwin, n); // try to advance to the column we want to be at - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); if (upd_topline) { update_topline(curwin); // make sure curwin->w_topline is valid @@ -2678,7 +2679,7 @@ int cursor_down(int n, bool upd_topline) cursor_down_inner(curwin, n); // try to advance to the column we want to be at - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); if (upd_topline) { update_topline(curwin); // make sure curwin->w_topline is valid @@ -2968,7 +2969,7 @@ static void replace_do_bs(int limit_col) } del_char_after_col(limit_col); if (l_State & VREPLACE_FLAG) { - orig_len = (int)strlen(get_cursor_pos_ptr()); + orig_len = get_cursor_pos_len(); } replace_push(cc); replace_pop_ins(); @@ -2976,7 +2977,7 @@ static void replace_do_bs(int limit_col) if (l_State & VREPLACE_FLAG) { // Get the number of screen cells used by the inserted characters char *p = get_cursor_pos_ptr(); - int ins_len = (int)strlen(p) - orig_len; + int ins_len = get_cursor_pos_len() - orig_len; int vcol = start_vcol; for (int i = 0; i < ins_len; i++) { vcol += win_chartabsize(curwin, p + i, vcol); @@ -3274,7 +3275,7 @@ static void ins_reg(void) // Cursor may be moved back a column. curwin->w_cursor = curpos; - check_cursor(); + check_cursor(curwin); } if (regname == NUL || !valid_yank_reg(regname, false)) { vim_beep(BO_REG); @@ -3466,7 +3467,7 @@ static bool ins_esc(int *count, int cmdchar, bool nomove) && (curwin->w_cursor.col != 0 || curwin->w_cursor.coladd > 0) && (restart_edit == NUL || (gchar_cursor() == NUL && !VIsual_active)) && !revins_on) { - if (curwin->w_cursor.coladd > 0 || get_ve_flags() == VE_ALL) { + if (curwin->w_cursor.coladd > 0 || get_ve_flags(curwin) == VE_ALL) { oneleft(); if (restart_edit != NUL) { curwin->w_cursor.coladd++; @@ -3598,7 +3599,7 @@ static void ins_ctrl_o(void) } else { restart_edit = 'I'; } - if (virtual_active()) { + if (virtual_active(curwin)) { ins_at_eol = false; // cursor always keeps its column } else { ins_at_eol = (gchar_cursor() == NUL); @@ -3673,23 +3674,6 @@ static void ins_del(void) AppendCharToRedobuff(K_DEL); } -// Delete one character for ins_bs(). -static void ins_bs_one(colnr_T *vcolp) -{ - dec_cursor(); - getvcol(curwin, &curwin->w_cursor, vcolp, NULL, NULL); - if (State & REPLACE_FLAG) { - // Don't delete characters before the insert point when in - // Replace mode - if (curwin->w_cursor.lnum != Insstart.lnum - || curwin->w_cursor.col >= Insstart.col) { - replace_do_bs(-1); - } - } else { - del_char(false); - } -} - /// Handle Backspace, delete-word and delete-line in Insert mode. /// /// @param c character that was typed @@ -3760,7 +3744,7 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) return false; } Insstart.lnum--; - Insstart.col = (colnr_T)strlen(ml_get(Insstart.lnum)); + Insstart.col = ml_get_len(Insstart.lnum); } // In replace mode: // cc < 0: NL was inserted, delete it @@ -3785,9 +3769,10 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) if (has_format_option(FO_AUTO) && has_format_option(FO_WHITE_PAR)) { char *ptr = ml_get_buf_mut(curbuf, curwin->w_cursor.lnum); - int len = (int)strlen(ptr); + int len = get_cursor_line_len(); if (len > 0 && ptr[len - 1] == ' ') { ptr[len - 1] = NUL; + curbuf->b_ml.ml_line_len--; } } @@ -3845,42 +3830,74 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) // Handle deleting one 'shiftwidth' or 'softtabstop'. if (mode == BACKSPACE_CHAR && ((p_sta && in_indent) - || ((get_sts_value() != 0 - || tabstop_count(curbuf->b_p_vsts_array)) + || ((get_sts_value() != 0 || tabstop_count(curbuf->b_p_vsts_array)) && curwin->w_cursor.col > 0 && (*(get_cursor_pos_ptr() - 1) == TAB || (*(get_cursor_pos_ptr() - 1) == ' ' && (!*inserted_space_p || arrow_used)))))) { - colnr_T vcol; - colnr_T want_vcol; - *inserted_space_p = false; - // Compute the virtual column where we want to be. Since - // 'showbreak' may get in the way, need to get the last column of - // the previous character. - getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); - colnr_T start_vcol = vcol; - dec_cursor(); - getvcol(curwin, &curwin->w_cursor, NULL, NULL, &want_vcol); - inc_cursor(); + + bool const use_ts = !curwin->w_p_list || curwin->w_p_lcs_chars.tab1; + char *const line = get_cursor_line_ptr(); + char *const cursor_ptr = line + curwin->w_cursor.col; + + colnr_T vcol = 0; + colnr_T space_vcol = 0; + StrCharInfo sci = utf_ptr2StrCharInfo(line); + StrCharInfo space_sci = sci; + bool prev_space = false; + + // Compute virtual column of cursor position, and find the last + // whitespace before cursor that is preceded by non-whitespace. + // Use charsize_nowrap() so that virtual text and wrapping are ignored. + while (sci.ptr < cursor_ptr) { + bool cur_space = ascii_iswhite(sci.chr.value); + if (!prev_space && cur_space) { + space_sci = sci; + space_vcol = vcol; + } + vcol += charsize_nowrap(curbuf, use_ts, vcol, sci.chr.value); + sci = utfc_next(sci); + prev_space = cur_space; + } + + // Compute the virtual column where we want to be. + colnr_T want_vcol = vcol > 0 ? vcol - 1 : 0; if (p_sta && in_indent) { - int ts = get_sw_value(curbuf); - want_vcol = (want_vcol / ts) * ts; + want_vcol -= want_vcol % get_sw_value(curbuf); } else { - want_vcol = tabstop_start(want_vcol, - get_sts_value(), - curbuf->b_p_vsts_array); + want_vcol = tabstop_start(want_vcol, get_sts_value(), curbuf->b_p_vsts_array); } - // delete characters until we are at or before want_vcol - while (vcol > want_vcol && curwin->w_cursor.col > 0 - && (cc = (uint8_t)(*(get_cursor_pos_ptr() - 1)), ascii_iswhite(cc))) { - ins_bs_one(&vcol); + // Find the position to stop backspacing. + // Use charsize_nowrap() so that virtual text and wrapping are ignored. + while (true) { + int size = charsize_nowrap(curbuf, use_ts, space_vcol, space_sci.chr.value); + if (space_vcol + size > want_vcol) { + break; + } + space_vcol += size; + space_sci = utfc_next(space_sci); + } + colnr_T const want_col = (int)(space_sci.ptr - line); + + // Delete characters until we are at or before want_col. + while (curwin->w_cursor.col > want_col) { + dec_cursor(); + if (State & REPLACE_FLAG) { + // Don't delete characters before the insert point when in Replace mode. + if (curwin->w_cursor.lnum != Insstart.lnum + || curwin->w_cursor.col >= Insstart.col) { + replace_do_bs(-1); + } + } else { + del_char(false); + } } - // insert extra spaces until we are at want_vcol - while (vcol < want_vcol) { - // Remember the first char we inserted + // Insert extra spaces until we are at want_vcol. + for (; space_vcol < want_vcol; space_vcol++) { + // Remember the first char we inserted. if (curwin->w_cursor.lnum == Insstart_orig.lnum && curwin->w_cursor.col < Insstart_orig.col) { Insstart_orig.col = curwin->w_cursor.col; @@ -3894,13 +3911,6 @@ static bool ins_bs(int c, int mode, int *inserted_space_p) replace_push(NUL); } } - getvcol(curwin, &curwin->w_cursor, &vcol, NULL, NULL); - } - - // If we are now back where we started delete one character. Can - // happen when using 'sts' and 'linebreak'. - if (vcol >= start_vcol) { - ins_bs_one(&vcol); } } else { // Delete up to starting point, start of line or previous word. @@ -4027,7 +4037,7 @@ static void ins_left(void) // always break undo when moving upwards/downwards, else undo may break start_arrow(&tpos); curwin->w_cursor.lnum--; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); curwin->w_set_curswant = true; // so we stay at the end } else { vim_beep(BO_CRSR); @@ -4061,7 +4071,7 @@ static void ins_end(int c) if (c == K_C_END) { curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; } - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); curwin->w_curswant = MAXCOL; start_arrow(&tpos); @@ -4095,13 +4105,13 @@ static void ins_right(void) foldOpenCursor(); } undisplay_dollar(); - if (gchar_cursor() != NUL || virtual_active()) { + if (gchar_cursor() != NUL || virtual_active(curwin)) { start_arrow_with_change(&curwin->w_cursor, end_change); if (!end_change) { AppendCharToRedobuff(K_RIGHT); } curwin->w_set_curswant = true; - if (virtual_active()) { + if (virtual_active(curwin)) { oneright(); } else { curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr()); @@ -4156,7 +4166,7 @@ static void ins_up(bool startcol) pos_T tpos = curwin->w_cursor; if (cursor_up(1, true) == OK) { if (startcol) { - coladvance(getvcol_nolist(&Insstart)); + coladvance(curwin, getvcol_nolist(&Insstart)); } if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill) { @@ -4183,7 +4193,7 @@ static void ins_pageup(void) } pos_T tpos = curwin->w_cursor; - if (onepage(BACKWARD, 1) == OK) { + if (pagescroll(BACKWARD, 1, false) == OK) { start_arrow(&tpos); can_cindent = true; } else { @@ -4201,7 +4211,7 @@ static void ins_down(bool startcol) pos_T tpos = curwin->w_cursor; if (cursor_down(1, true) == OK) { if (startcol) { - coladvance(getvcol_nolist(&Insstart)); + coladvance(curwin, getvcol_nolist(&Insstart)); } if (old_topline != curwin->w_topline || old_topfill != curwin->w_topfill) { @@ -4228,7 +4238,7 @@ static void ins_pagedown(void) } pos_T tpos = curwin->w_cursor; - if (onepage(FORWARD, 1) == OK) { + if (pagescroll(FORWARD, 1, false) == OK) { start_arrow(&tpos); can_cindent = true; } else { @@ -4330,7 +4340,7 @@ static bool ins_tab(void) if (State & VREPLACE_FLAG) { pos = curwin->w_cursor; cursor = &pos; - saved_line = xstrdup(get_cursor_line_ptr()); + saved_line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); ptr = saved_line + pos.col; } else { ptr = get_cursor_pos_ptr(); @@ -4411,13 +4421,13 @@ static bool ins_tab(void) if (i > 0) { STRMOVE(ptr, ptr + i); // correct replace stack. - if ((State & REPLACE_FLAG) - && !(State & VREPLACE_FLAG)) { + if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { for (temp = i; --temp >= 0;) { replace_join(repl_off); } } if (!(State & VREPLACE_FLAG)) { + curbuf->b_ml.ml_line_len -= i; inserted_bytes(fpos.lnum, change_col, cursor->col - change_col, fpos.col - change_col); } @@ -4462,8 +4472,7 @@ bool ins_eol(int c) // Strange Vi behaviour: In Replace mode, typing a NL will not delete the // character under the cursor. Only push a NUL on the replace stack, // nothing to put back when the NL is deleted. - if ((State & REPLACE_FLAG) - && !(State & VREPLACE_FLAG)) { + if ((State & REPLACE_FLAG) && !(State & VREPLACE_FLAG)) { replace_push(NUL); } @@ -4474,13 +4483,13 @@ bool ins_eol(int c) // Put cursor on NUL if on the last char and coladd is 1 (happens after // CTRL-O). - if (virtual_active() && curwin->w_cursor.coladd > 0) { - coladvance(getviscol()); + if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) { + coladvance(curwin, getviscol()); } // NL in reverse insert will always start in the end of current line. if (revins_on) { - curwin->w_cursor.col += (colnr_T)strlen(get_cursor_pos_ptr()); + curwin->w_cursor.col += get_cursor_pos_len(); } AppendToRedobuff(NL_STR); @@ -4574,7 +4583,7 @@ int ins_copychar(linenr_T lnum) } // try to advance to the cursor column - validate_virtcol(); + validate_virtcol(curwin); int const end_vcol = curwin->w_virtcol; char *line = ml_get(lnum); @@ -4720,7 +4729,7 @@ colnr_T get_nolist_virtcol(void) if (curwin->w_p_list && vim_strchr(p_cpo, CPO_LISTWM) == NULL) { return getvcol_nolist(&curwin->w_cursor); } - validate_virtcol(); + validate_virtcol(curwin); return curwin->w_virtcol; } diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 7e3060100c..64883e69a2 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -17,6 +17,7 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" +#include "nvim/change.h" #include "nvim/channel.h" #include "nvim/charset.h" #include "nvim/cmdexpand_defs.h" @@ -763,8 +764,8 @@ void fill_evalarg_from_eap(evalarg_T *evalarg, exarg_T *eap, bool skip) return; } - if (getline_equal(eap->getline, eap->cookie, getsourceline)) { - evalarg->eval_getline = eap->getline; + if (getline_equal(eap->ea_getline, eap->cookie, getsourceline)) { + evalarg->eval_getline = eap->ea_getline; evalarg->eval_cookie = eap->cookie; } } @@ -968,12 +969,12 @@ int skip_expr(char **pp, evalarg_T *const evalarg) /// Convert "tv" to a string. /// -/// @param convert when true convert a List into a sequence of lines. +/// @param join_list when true convert a List into a sequence of lines. /// /// @return an allocated string. -static char *typval2string(typval_T *tv, bool convert) +static char *typval2string(typval_T *tv, bool join_list) { - if (convert && tv->v_type == VAR_LIST) { + if (join_list && tv->v_type == VAR_LIST) { garray_T ga; ga_init(&ga, (int)sizeof(char), 80); if (tv->vval.v_list != NULL) { @@ -984,24 +985,28 @@ static char *typval2string(typval_T *tv, bool convert) } ga_append(&ga, NUL); return (char *)ga.ga_data; + } else if (tv->v_type == VAR_LIST || tv->v_type == VAR_DICT) { + return encode_tv2string(tv, NULL); } return xstrdup(tv_get_string(tv)); } /// Top level evaluation function, returning a string. /// -/// @param convert when true convert a List into a sequence of lines. +/// @param join_list when true convert a List into a sequence of lines. /// /// @return pointer to allocated memory, or NULL for failure. -char *eval_to_string(char *arg, bool convert) +char *eval_to_string_eap(char *arg, bool join_list, exarg_T *eap) { typval_T tv; char *retval; - if (eval0(arg, &tv, NULL, &EVALARG_EVALUATE) == FAIL) { + evalarg_T evalarg; + fill_evalarg_from_eap(&evalarg, eap, eap != NULL && eap->skip); + if (eval0(arg, &tv, NULL, &evalarg) == FAIL) { retval = NULL; } else { - retval = typval2string(&tv, convert); + retval = typval2string(&tv, join_list); tv_clear(&tv); } clear_evalarg(&EVALARG_EVALUATE, NULL); @@ -1009,6 +1014,11 @@ char *eval_to_string(char *arg, bool convert) return retval; } +char *eval_to_string(char *arg, bool join_list) +{ + return eval_to_string_eap(arg, join_list, NULL); +} + /// Call eval_to_string() without using current local variables and using /// textlock. /// @@ -1372,112 +1382,24 @@ Object eval_foldtext(win_T *wp) return retval; } -/// Get an lvalue +/// Get the lval of a list/dict/blob subitem starting at "p". Loop +/// until no more [idx] or .key is following. /// -/// Lvalue may be -/// - variable: "name", "na{me}" -/// - dictionary item: "dict.key", "dict['key']" -/// - list item: "list[expr]" -/// - list slice: "list[expr:expr]" -/// -/// Indexing only works if trying to use it with an existing List or Dictionary. -/// -/// @param[in] name Name to parse. -/// @param rettv Pointer to the value to be assigned or NULL. -/// @param[out] lp Lvalue definition. When evaluation errors occur `->ll_name` -/// is NULL. -/// @param[in] unlet True if using `:unlet`. This results in slightly -/// different behaviour when something is wrong; must end in -/// space or cmd separator. -/// @param[in] skip True when skipping. /// @param[in] flags @see GetLvalFlags. -/// @param[in] fne_flags Flags for find_name_end(). /// -/// @return A pointer to just after the name, including indexes. Returns NULL -/// for a parsing error, but it is still needed to free items in lp. -char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const bool unlet, - const bool skip, const int flags, const int fne_flags) - FUNC_ATTR_NONNULL_ARG(1, 3) +/// @return A pointer to the character after the subscript on success or NULL on +/// failure. +static char *get_lval_subscript(lval_T *lp, char *p, char *name, typval_T *rettv, hashtab_T *ht, + dictitem_T *v, int unlet, int flags) { - bool empty1 = false; int quiet = flags & GLV_QUIET; - - // Clear everything in "lp". - CLEAR_POINTER(lp); - - if (skip) { - // When skipping just find the end of the name. - lp->ll_name = name; - return (char *)find_name_end(name, NULL, NULL, FNE_INCL_BR | fne_flags); - } - - // Find the end of the name. - char *expr_start; - char *expr_end; - char *p = (char *)find_name_end(name, (const char **)&expr_start, - (const char **)&expr_end, - fne_flags); - if (expr_start != NULL) { - // Don't expand the name when we already know there is an error. - if (unlet && !ascii_iswhite(*p) && !ends_excmd(*p) - && *p != '[' && *p != '.') { - semsg(_(e_trailing_arg), p); - return NULL; - } - - lp->ll_exp_name = make_expanded_name(name, expr_start, expr_end, p); - lp->ll_name = lp->ll_exp_name; - if (lp->ll_exp_name == NULL) { - // Report an invalid expression in braces, unless the - // expression evaluation has been cancelled due to an - // aborting error, an interrupt, or an exception. - if (!aborting() && !quiet) { - emsg_severe = true; - semsg(_(e_invarg2), name); - return NULL; - } - lp->ll_name_len = 0; - } else { - lp->ll_name_len = strlen(lp->ll_name); - } - } else { - lp->ll_name = name; - lp->ll_name_len = (size_t)(p - lp->ll_name); - } - - // Without [idx] or .key we are done. - if ((*p != '[' && *p != '.') || lp->ll_name == NULL) { - return p; - } - - hashtab_T *ht = NULL; - - // Only pass &ht when we would write to the variable, it prevents autoload - // as well. - dictitem_T *v = find_var(lp->ll_name, lp->ll_name_len, - (flags & GLV_READ_ONLY) ? NULL : &ht, - flags & GLV_NO_AUTOLOAD); - if (v == NULL && !quiet) { - semsg(_("E121: Undefined variable: %.*s"), - (int)lp->ll_name_len, lp->ll_name); - } - if (v == NULL) { - return NULL; - } - - lp->ll_tv = &v->di_tv; - - if (tv_is_luafunc(lp->ll_tv)) { - // For v:lua just return a pointer to the "." after the "v:lua". - // If the caller is trans_function_name() it will check for a Lua function name. - return p; - } - - // Loop until no more [idx] or .key is following. typval_T var1; var1.v_type = VAR_UNKNOWN; typval_T var2; var2.v_type = VAR_UNKNOWN; + bool empty1 = false; + + // Loop until no more [idx] or .key is following. while (*p == '[' || (*p == '.' && p[1] != '=' && p[1] != '.')) { if (*p == '.' && lp->ll_tv->v_type != VAR_DICT) { if (!quiet) { @@ -1512,6 +1434,7 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const char *key = NULL; if (*p == '.') { key = p + 1; + for (len = 0; ASCII_ISALNUM(key[len]) || key[len] == '_'; len++) {} if (len == 0) { if (!quiet) { @@ -1730,6 +1653,116 @@ char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const return p; } +/// Get an lvalue +/// +/// Lvalue may be +/// - variable: "name", "na{me}" +/// - dictionary item: "dict.key", "dict['key']" +/// - list item: "list[expr]" +/// - list slice: "list[expr:expr]" +/// +/// Indexing only works if trying to use it with an existing List or Dictionary. +/// +/// @param[in] name Name to parse. +/// @param rettv Pointer to the value to be assigned or NULL. +/// @param[out] lp Lvalue definition. When evaluation errors occur `->ll_name` +/// is NULL. +/// @param[in] unlet True if using `:unlet`. This results in slightly +/// different behaviour when something is wrong; must end in +/// space or cmd separator. +/// @param[in] skip True when skipping. +/// @param[in] flags @see GetLvalFlags. +/// @param[in] fne_flags Flags for find_name_end(). +/// +/// @return A pointer to just after the name, including indexes. Returns NULL +/// for a parsing error, but it is still needed to free items in lp. +char *get_lval(char *const name, typval_T *const rettv, lval_T *const lp, const bool unlet, + const bool skip, const int flags, const int fne_flags) + FUNC_ATTR_NONNULL_ARG(1, 3) +{ + int quiet = flags & GLV_QUIET; + + // Clear everything in "lp". + CLEAR_POINTER(lp); + + if (skip) { + // When skipping just find the end of the name. + lp->ll_name = name; + return (char *)find_name_end(name, NULL, NULL, FNE_INCL_BR | fne_flags); + } + + // Find the end of the name. + char *expr_start; + char *expr_end; + char *p = (char *)find_name_end(name, (const char **)&expr_start, + (const char **)&expr_end, + fne_flags); + if (expr_start != NULL) { + // Don't expand the name when we already know there is an error. + if (unlet && !ascii_iswhite(*p) && !ends_excmd(*p) + && *p != '[' && *p != '.') { + semsg(_(e_trailing_arg), p); + return NULL; + } + + lp->ll_exp_name = make_expanded_name(name, expr_start, expr_end, p); + lp->ll_name = lp->ll_exp_name; + if (lp->ll_exp_name == NULL) { + // Report an invalid expression in braces, unless the + // expression evaluation has been cancelled due to an + // aborting error, an interrupt, or an exception. + if (!aborting() && !quiet) { + emsg_severe = true; + semsg(_(e_invarg2), name); + return NULL; + } + lp->ll_name_len = 0; + } else { + lp->ll_name_len = strlen(lp->ll_name); + } + } else { + lp->ll_name = name; + lp->ll_name_len = (size_t)(p - lp->ll_name); + } + + // Without [idx] or .key we are done. + if ((*p != '[' && *p != '.') || lp->ll_name == NULL) { + return p; + } + + hashtab_T *ht = NULL; + + // Only pass &ht when we would write to the variable, it prevents autoload + // as well. + dictitem_T *v = find_var(lp->ll_name, lp->ll_name_len, + (flags & GLV_READ_ONLY) ? NULL : &ht, + flags & GLV_NO_AUTOLOAD); + if (v == NULL && !quiet) { + semsg(_("E121: Undefined variable: %.*s"), + (int)lp->ll_name_len, lp->ll_name); + } + if (v == NULL) { + return NULL; + } + + lp->ll_tv = &v->di_tv; + + if (tv_is_luafunc(lp->ll_tv)) { + // For v:lua just return a pointer to the "." after the "v:lua". + // If the caller is trans_function_name() it will check for a Lua function name. + return p; + } + + // If the next character is a "." or a "[", then process the subitem. + p = get_lval_subscript(lp, p, name, rettv, ht, v, unlet, flags); + if (p == NULL) { + return NULL; + } + + lp->ll_name_len = (size_t)(p - lp->ll_name); + return p; +} + /// Clear lval "lp" that was filled by get_lval(). void clear_lval(lval_T *lp) { @@ -1892,7 +1925,7 @@ void *eval_for_line(const char *arg, bool *errp, exarg_T *eap, evalarg_T *const *errp = true; // Default: there is an error. - const char *expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon); + const char *expr = skip_var_list(arg, &fi->fi_varcount, &fi->fi_semicolon, false); if (expr == NULL) { return fi; } @@ -4766,6 +4799,88 @@ bool set_ref_in_list_items(list_T *l, int copyID, ht_stack_T **ht_stack) return abort; } +/// Mark the dict "dd" with "copyID". +/// Also see set_ref_in_item(). +static bool set_ref_in_item_dict(dict_T *dd, int copyID, ht_stack_T **ht_stack, + list_stack_T **list_stack) +{ + if (dd == NULL || dd->dv_copyID == copyID) { + return false; + } + + // Didn't see this dict yet. + dd->dv_copyID = copyID; + if (ht_stack == NULL) { + return set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack); + } + + ht_stack_T *const newitem = xmalloc(sizeof(ht_stack_T)); + newitem->ht = &dd->dv_hashtab; + newitem->prev = *ht_stack; + *ht_stack = newitem; + + QUEUE *w = NULL; + DictWatcher *watcher = NULL; + QUEUE_FOREACH(w, &dd->watchers, { + watcher = tv_dict_watcher_node_data(w); + set_ref_in_callback(&watcher->callback, copyID, ht_stack, list_stack); + }) + + return false; +} + +/// Mark the list "ll" with "copyID". +/// Also see set_ref_in_item(). +static bool set_ref_in_item_list(list_T *ll, int copyID, ht_stack_T **ht_stack, + list_stack_T **list_stack) +{ + if (ll == NULL || ll->lv_copyID == copyID) { + return false; + } + + // Didn't see this list yet. + ll->lv_copyID = copyID; + if (list_stack == NULL) { + return set_ref_in_list_items(ll, copyID, ht_stack); + } + + list_stack_T *const newitem = xmalloc(sizeof(list_stack_T)); + newitem->list = ll; + newitem->prev = *list_stack; + *list_stack = newitem; + + return false; +} + +/// Mark the partial "pt" with "copyID". +/// Also see set_ref_in_item(). +static bool set_ref_in_item_partial(partial_T *pt, int copyID, ht_stack_T **ht_stack, + list_stack_T **list_stack) +{ + if (pt == NULL || pt->pt_copyID == copyID) { + return false; + } + + // Didn't see this partial yet. + pt->pt_copyID = copyID; + + bool abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID); + + if (pt->pt_dict != NULL) { + typval_T dtv; + + dtv.v_type = VAR_DICT; + dtv.vval.v_dict = pt->pt_dict; + abort = abort || set_ref_in_item(&dtv, copyID, ht_stack, list_stack); + } + + for (int i = 0; i < pt->pt_argc; i++) { + abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID, ht_stack, list_stack); + } + + return abort; +} + /// Mark all lists and dicts referenced through typval "tv" with "copyID". /// /// @param tv Typval content will be marked. @@ -4780,71 +4895,15 @@ bool set_ref_in_item(typval_T *tv, int copyID, ht_stack_T **ht_stack, list_stack bool abort = false; switch (tv->v_type) { - case VAR_DICT: { - dict_T *dd = tv->vval.v_dict; - if (dd != NULL && dd->dv_copyID != copyID) { - // Didn't see this dict yet. - dd->dv_copyID = copyID; - if (ht_stack == NULL) { - abort = set_ref_in_ht(&dd->dv_hashtab, copyID, list_stack); - } else { - ht_stack_T *const newitem = xmalloc(sizeof(ht_stack_T)); - newitem->ht = &dd->dv_hashtab; - newitem->prev = *ht_stack; - *ht_stack = newitem; - } - - QUEUE *w = NULL; - DictWatcher *watcher = NULL; - QUEUE_FOREACH(w, &dd->watchers, { - watcher = tv_dict_watcher_node_data(w); - set_ref_in_callback(&watcher->callback, copyID, ht_stack, list_stack); - }) - } - break; - } - - case VAR_LIST: { - list_T *ll = tv->vval.v_list; - if (ll != NULL && ll->lv_copyID != copyID) { - // Didn't see this list yet. - ll->lv_copyID = copyID; - if (list_stack == NULL) { - abort = set_ref_in_list_items(ll, copyID, ht_stack); - } else { - list_stack_T *const newitem = xmalloc(sizeof(list_stack_T)); - newitem->list = ll; - newitem->prev = *list_stack; - *list_stack = newitem; - } - } - break; - } - - case VAR_PARTIAL: { - partial_T *pt = tv->vval.v_partial; - - // A partial does not have a copyID, because it cannot contain itself. - if (pt != NULL) { - abort = set_ref_in_func(pt->pt_name, pt->pt_func, copyID); - if (pt->pt_dict != NULL) { - typval_T dtv; - - dtv.v_type = VAR_DICT; - dtv.vval.v_dict = pt->pt_dict; - abort = abort || set_ref_in_item(&dtv, copyID, ht_stack, list_stack); - } - - for (int i = 0; i < pt->pt_argc; i++) { - abort = abort || set_ref_in_item(&pt->pt_argv[i], copyID, - ht_stack, list_stack); - } - } - break; - } + case VAR_DICT: + return set_ref_in_item_dict(tv->vval.v_dict, copyID, ht_stack, list_stack); + case VAR_LIST: + return set_ref_in_item_list(tv->vval.v_list, copyID, ht_stack, list_stack); case VAR_FUNC: abort = set_ref_in_func(tv->vval.v_string, NULL, copyID); break; + case VAR_PARTIAL: + return set_ref_in_item_partial(tv->vval.v_partial, copyID, ht_stack, list_stack); case VAR_UNKNOWN: case VAR_BOOL: case VAR_SPECIAL: @@ -6697,7 +6756,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret if (charcol) { len = mb_charlen(ml_get(pos.lnum)); } else { - len = (int)strlen(ml_get(pos.lnum)); + len = ml_get_len(pos.lnum); } // We accept "$" for the column number: last column. @@ -6787,7 +6846,7 @@ pos_T *var2fpos(const typval_T *const tv, const bool dollar_lnum, int *const ret if (charcol) { pos.col = (colnr_T)mb_charlen(get_cursor_line_ptr()); } else { - pos.col = (colnr_T)strlen(get_cursor_line_ptr()); + pos.col = get_cursor_line_len(); } } return &pos; @@ -7517,29 +7576,44 @@ int check_luafunc_name(const char *const str, const bool paren) return (int)(p - str); } -/// Return the character "str[index]" where "index" is the character index. If -/// "index" is out of range NULL is returned. +/// Return the character "str[index]" where "index" is the character index, +/// including composing characters. +/// If "index" is out of range NULL is returned. char *char_from_string(const char *str, varnumber_T index) { - size_t nbyte = 0; varnumber_T nchar = index; - if (str == NULL || index < 0) { + if (str == NULL) { return NULL; } size_t slen = strlen(str); - while (nchar > 0 && nbyte < slen) { - nbyte += (size_t)utf_ptr2len(str + nbyte); - nchar--; + + // do the same as for a list: a negative index counts from the end + if (index < 0) { + int clen = 0; + + for (size_t nbyte = 0; nbyte < slen; clen++) { + nbyte += (size_t)utfc_ptr2len(str + nbyte); + } + nchar = clen + index; + if (nchar < 0) { + // unlike list: index out of range results in empty string + return NULL; + } + } + + size_t nbyte = 0; + for (; nchar > 0 && nbyte < slen; nchar--) { + nbyte += (size_t)utfc_ptr2len(str + nbyte); } if (nbyte >= slen) { return NULL; } - return xmemdupz(str + nbyte, (size_t)utf_ptr2len(str + nbyte)); + return xmemdupz(str + nbyte, (size_t)utfc_ptr2len(str + nbyte)); } /// Get the byte index for character index "idx" in string "str" with length -/// "str_len". +/// "str_len". Composing characters are included. /// If going over the end return "str_len". /// If "idx" is negative count from the end, -1 is the last character. /// When going over the start return -1. @@ -7550,7 +7624,7 @@ static ssize_t char_idx2byte(const char *str, size_t str_len, varnumber_T idx) if (nchar >= 0) { while (nchar > 0 && nbyte < str_len) { - nbyte += (size_t)utf_ptr2len(str + nbyte); + nbyte += (size_t)utfc_ptr2len(str + nbyte); nchar--; } } else { @@ -7567,7 +7641,8 @@ static ssize_t char_idx2byte(const char *str, size_t str_len, varnumber_T idx) return (ssize_t)nbyte; } -/// Return the slice "str[first:last]" using character indexes. +/// Return the slice "str[first : last]" using character indexes. Composing +/// characters are included. /// /// @param exclusive true for slice(). /// @@ -7589,7 +7664,7 @@ char *string_slice(const char *str, varnumber_T first, varnumber_T last, bool ex end_byte = char_idx2byte(str, slen, last); if (!exclusive && end_byte >= 0 && end_byte < (ssize_t)slen) { // end index is inclusive - end_byte += utf_ptr2len(str + end_byte); + end_byte += utfc_ptr2len(str + end_byte); } } @@ -7876,8 +7951,8 @@ hashtab_T *find_var_ht_dict(const char *name, const size_t name_len, const char .channel_id = LUA_INTERNAL_CALL, }; bool should_free; - // should_free is ignored as script_sctx will be resolved to a fnmae - // & new_script_item will consume it. + // should_free is ignored as script_ctx will be resolved to a fname + // and new_script_item() will consume it. char *sc_name = get_scriptname(last_set, &should_free); new_script_item(sc_name, ¤t_sctx.sc_sid); } @@ -8083,10 +8158,12 @@ void ex_echo(exarg_T *eap) // Call msg_start() after eval1(), evaluating the expression // may cause a message to appear. if (eap->cmdidx == CMD_echo) { - // Mark the saved text as finishing the line, so that what - // follows is displayed on a new line when scrolling back - // at the more prompt. - msg_sb_eol(); + if (!msg_didout) { + // Mark the saved text as finishing the line, so that what + // follows is displayed on a new line when scrolling back + // at the more prompt. + msg_sb_eol(); + } msg_start(); } } else if (eap->cmdidx == CMD_echo) { @@ -8182,7 +8259,7 @@ void ex_execute(exarg_T *eap) did_emsg = save_did_emsg; } } else if (eap->cmdidx == CMD_execute) { - do_cmdline(ga.ga_data, eap->getline, eap->cookie, DOCMD_NOWAIT|DOCMD_VERBOSE); + do_cmdline(ga.ga_data, eap->ea_getline, eap->cookie, DOCMD_NOWAIT|DOCMD_VERBOSE); } } @@ -8752,7 +8829,7 @@ void script_host_eval(char *name, typval_T *argvars, typval_T *rettv) /// an empty typval_T. typval_T eval_call_provider(char *provider, char *method, list_T *arguments, bool discard) { - if (!eval_has_provider(provider)) { + if (!eval_has_provider(provider, false)) { semsg("E319: No \"%s\" provider found. Run \":checkhealth provider\"", provider); return (typval_T){ @@ -8810,7 +8887,7 @@ typval_T eval_call_provider(char *provider, char *method, list_T *arguments, boo } /// Checks if provider for feature `feat` is enabled. -bool eval_has_provider(const char *feat) +bool eval_has_provider(const char *feat, bool throw_if_fast) { if (!strequal(feat, "clipboard") && !strequal(feat, "python3") @@ -8823,6 +8900,11 @@ bool eval_has_provider(const char *feat) return false; } + if (throw_if_fast && !nlua_is_deferred_safe()) { + semsg(e_luv_api_disabled, "Vimscript function"); + return false; + } + char name[32]; // Normalized: "python3_compiled" => "python3". snprintf(name, sizeof(name), "%s", feat); strchrsub(name, '_', '\0'); // Chop any "_xx" suffix. @@ -8885,6 +8967,7 @@ void invoke_prompt_callback(void) // Add a new line for the prompt before invoking the callback, so that // text can always be inserted above the last line. ml_append(lnum, "", 0, false); + appended_lines_mark(lnum, 1); curwin->w_cursor.lnum = lnum + 1; curwin->w_cursor.col = 0; diff --git a/src/nvim/eval.lua b/src/nvim/eval.lua index b7120d5dd5..7d4438ded6 100644 --- a/src/nvim/eval.lua +++ b/src/nvim/eval.lua @@ -2071,14 +2071,13 @@ M.funcs = { The result is a Number: 1 exists 0 does not exist - -1 not implemented on this system |exepath()| can be used to get the full path of an executable. ]=], fast = true, name = 'executable', params = { { 'expr', 'any' } }, - returns = '0|1|-1', + returns = '0|1', signature = 'executable({expr})', }, execute = { @@ -2481,6 +2480,7 @@ M.funcs = { 't' Handle keys as if typed; otherwise they are handled as if coming from a mapping. This matters for undo, opening folds, etc. + 'L' Lowlevel input. Other flags are not used. 'i' Insert the string instead of appending (see above). 'x' Execute commands until typeahead is empty. This is similar to using ":normal!". You can call feedkeys() @@ -3383,14 +3383,14 @@ M.funcs = { args = { 0, 1 }, desc = [=[ Get a single character from the user or input stream. - If [expr] is omitted, wait until a character is available. - If [expr] is 0, only get a character when one is available. + If {expr} is omitted, wait until a character is available. + If {expr} is 0, only get a character when one is available. Return zero otherwise. - If [expr] is 1, only check if a character is available, it is + If {expr} is 1, only check if a character is available, it is not consumed. Return zero if no character available. If you prefer always getting a string use |getcharstr()|. - Without [expr] and when [expr] is 0 a whole character or + Without {expr} and when {expr} is 0 a whole character or special key is returned. If it is a single character, the result is a Number. Use |nr2char()| to convert it to a String. Otherwise a String is returned with the encoded character. @@ -3400,11 +3400,11 @@ M.funcs = { also a String when a modifier (shift, control, alt) was used that is not included in the character. - When [expr] is 0 and Esc is typed, there will be a short delay + When {expr} is 0 and Esc is typed, there will be a short delay while Vim waits to see if this is the start of an escape sequence. - When [expr] is 1 only the first byte is returned. For a + When {expr} is 1 only the first byte is returned. For a one-byte character it is the character itself as a number. Use nr2char() to convert it to a String. @@ -3449,7 +3449,7 @@ M.funcs = { name = 'getchar', params = {}, returns = 'integer', - signature = 'getchar([expr])', + signature = 'getchar([{expr}])', }, getcharmod = { desc = [=[ @@ -3526,10 +3526,10 @@ M.funcs = { desc = [=[ Get a single character from the user or input stream as a string. - If [expr] is omitted, wait until a character is available. - If [expr] is 0 or false, only get a character when one is + If {expr} is omitted, wait until a character is available. + If {expr} is 0 or false, only get a character when one is available. Return an empty string otherwise. - If [expr] is 1 or true, only check if a character is + If {expr} is 1 or true, only check if a character is available, it is not consumed. Return an empty string if no character is available. Otherwise this works like |getchar()|, except that a number @@ -3538,7 +3538,7 @@ M.funcs = { name = 'getcharstr', params = {}, returns = 'string', - signature = 'getcharstr([expr])', + signature = 'getcharstr([{expr}])', }, getcmdcompltype = { desc = [=[ @@ -4414,6 +4414,46 @@ M.funcs = { returns = 'string[]', signature = 'getregion({pos1}, {pos2} [, {opts}])', }, + getregionpos = { + args = { 2, 3 }, + base = 1, + desc = [=[ + Same as |getregion()|, but returns a list of positions + describing the buffer text segments bound by {pos1} and + {pos2}. + The segments are a pair of positions for every line: > + [[{start_pos}, {end_pos}], ...] + < + The position is a |List| with four numbers: + [bufnum, lnum, col, off] + "bufnum" is the buffer number. + "lnum" and "col" are the position in the buffer. The first + column is 1. + If the "off" number of a starting position is non-zero, it is + the offset in screen columns from the start of the character. + E.g., a position within a <Tab> or after the last character. + If the "off" number of an ending position is non-zero, it is + the offset of the character's first cell not included in the + selection, otherwise all its cells are included. + + Apart from the options supported by |getregion()|, {opts} also + supports the following: + + eol If |TRUE|, indicate positions beyond + the end of a line with "col" values + one more than the length of the line. + If |FALSE|, positions are limited + within their lines, and if a line is + empty or the selection is entirely + beyond the end of a line, a "col" + value of 0 is used for both positions. + (default: |FALSE|) + ]=], + name = 'getregionpos', + params = { { 'pos1', 'table' }, { 'pos2', 'table' }, { 'opts', 'table' } }, + returns = 'integer[][][]', + signature = 'getregionpos({pos1}, {pos2} [, {opts}])', + }, getregtype = { args = { 0, 1 }, base = 1, @@ -4470,11 +4510,12 @@ M.funcs = { Examples: >vim echo getscriptinfo({'name': 'myscript'}) - echo getscriptinfo({'sid': 15}).variables + echo getscriptinfo({'sid': 15})[0].variables < ]=], name = 'getscriptinfo', params = { { 'opts', 'table' } }, + returns = 'vim.fn.getscriptinfo.ret[]', signature = 'getscriptinfo([{opts}])', }, gettabinfo = { @@ -4905,6 +4946,7 @@ M.funcs = { endif < ]=], + fast = true, name = 'has', params = { { 'feature', 'any' } }, returns = '0|1', @@ -7249,7 +7291,7 @@ M.funcs = { base = 1, desc = [=[ Return a string that indicates the current mode. - If [expr] is supplied and it evaluates to a non-zero Number or + If {expr} is supplied and it evaluates to a non-zero Number or a non-empty String (|non-zero-arg|), then the full mode is returned, otherwise only the first letter is returned. Also see |state()|. @@ -7304,7 +7346,7 @@ M.funcs = { ]=], name = 'mode', params = { { 'expr', 'any' } }, - signature = 'mode([expr])', + signature = 'mode([{expr}])', }, msgpackdump = { args = { 1, 2 }, @@ -7836,6 +7878,9 @@ M.funcs = { echo printf("%1$*2$.*3$f", 1.4142135, 6, 2) < 1.41 + You will get an overflow error |E1510|, when the field-width + or precision will result in a string longer than 6400 chars. + *E1500* You cannot mix positional and non-positional arguments: >vim echo printf("%s%1$s", "One", "Two") @@ -7898,6 +7943,7 @@ M.funcs = { name = 'printf', params = { { 'fmt', 'any' }, { 'expr1', 'any' } }, signature = 'printf({fmt}, {expr1} ...)', + returns = 'string', }, prompt_getprompt = { args = 1, @@ -8746,6 +8792,7 @@ M.funcs = { When a match has been found its line number is returned. If there is no match a 0 is returned and the cursor doesn't move. No error message is given. + To get the matched string, use |matchbufline()|. {flags} is a String, which can contain these character flags: 'b' search Backward instead of forward @@ -9896,10 +9943,11 @@ M.funcs = { Otherwise encloses {string} in single-quotes and replaces all "'" with "'\''". - If {special} is a |non-zero-arg|: - - Special items such as "!", "%", "#" and "<cword>" will be - preceded by a backslash. The backslash will be removed again - by the |:!| command. + The {special} argument adds additional escaping of keywords + used in Vim commands. If it is a |non-zero-arg|: + - Special items such as "!", "%", "#" and "<cword>" (as listed + in |expand()|) will be preceded by a backslash. + The backslash will be removed again by the |:!| command. - The <NL> character is escaped. If 'shell' contains "csh" in the tail: @@ -10481,7 +10529,8 @@ M.funcs = { Similar to using a |slice| "expr[start : end]", but "end" is used exclusive. And for a string the indexes are used as character indexes instead of byte indexes. - Also, composing characters are not counted. + Also, composing characters are treated as a part of the + preceding base character. When {end} is omitted the slice continues to the last item. When {end} is -1 the last item is omitted. Returns an empty value if {start} or {end} are invalid. @@ -10953,8 +11002,8 @@ M.funcs = { of byte index and length. When {skipcc} is omitted or zero, composing characters are counted separately. - When {skipcc} set to 1, Composing characters are ignored, - similar to |slice()|. + When {skipcc} set to 1, composing characters are treated as a + part of the preceding base character, similar to |slice()|. When a character index is used where a character does not exist it is omitted and counted as one character. For example: >vim @@ -10977,7 +11026,7 @@ M.funcs = { in String {string}. When {skipcc} is omitted or zero, composing characters are counted separately. - When {skipcc} set to 1, Composing characters are ignored. + When {skipcc} set to 1, composing characters are ignored. |strcharlen()| always does this. Returns zero on error. @@ -11124,10 +11173,10 @@ M.funcs = { for infinite and NaN floating-point values representations which use |str2float()|. Strings are also dumped literally, only single quote is escaped, which does not allow using YAML - for parsing back binary strings. |eval()| should always work for - strings and floats though and this is the only official - method, use |msgpackdump()| or |json_encode()| if you need to - share data with other application. + for parsing back binary strings. |eval()| should always work + for strings and floats though, and this is the only official + method. Use |msgpackdump()| or |json_encode()| if you need to + share data with other applications. ]=], name = 'string', @@ -11615,6 +11664,10 @@ M.funcs = { synconcealed(lnum, 4) [1, 'X', 2] synconcealed(lnum, 5) [1, 'X', 2] synconcealed(lnum, 6) [0, '', 0] + + Note: Doesn't consider |matchadd()| highlighting items, + since syntax and matching highlighting are two different + mechanisms |syntax-vs-match|. ]=], name = 'synconcealed', params = { { 'lnum', 'integer' }, { 'col', 'integer' } }, @@ -12687,9 +12740,7 @@ M.funcs = { [1, 1], unless there is a tabline, then it is [2, 1]. {nr} can be the window number or the |window-ID|. Use zero for the current window. - Returns [0, 0] if the window cannot be found in the current - tabpage. - + Returns [0, 0] if the window cannot be found. ]=], name = 'win_screenpos', params = { { 'nr', 'integer' } }, @@ -12699,10 +12750,10 @@ M.funcs = { args = { 2, 3 }, base = 1, desc = [=[ - Move the window {nr} to a new split of the window {target}. - This is similar to moving to {target}, creating a new window - using |:split| but having the same contents as window {nr}, and - then closing {nr}. + Temporarily switch to window {target}, then move window {nr} + to a new split adjacent to {target}. + Unlike commands such as |:split|, no new windows are created + (the |window-ID| of window {nr} is unchanged after the move). Both {nr} and {target} can be window numbers or |window-ID|s. Both must be in the current tab page. @@ -12856,7 +12907,9 @@ M.funcs = { # the number of the last accessed window (where |CTRL-W_p| goes to). If there is no previous window or it is in another tab page 0 is - returned. + returned. May refer to the current window in + some cases (e.g. when evaluating 'statusline' + expressions). {N}j the number of the Nth window below the current window (where |CTRL-W_j| goes to). {N}k the number of the Nth window above the current diff --git a/src/nvim/eval/buffer.c b/src/nvim/eval/buffer.c index 7b8f71ef3f..73bfd6db2a 100644 --- a/src/nvim/eval/buffer.c +++ b/src/nvim/eval/buffer.c @@ -197,7 +197,7 @@ static void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, typval_ && ml_replace(lnum, line, true) == OK) { inserted_bytes(lnum, 0, old_len, (int)strlen(line)); if (is_curbuf && lnum == curwin->w_cursor.lnum) { - check_cursor_col(); + check_cursor_col(curwin); } rettv->vval.v_number = 0; // OK } @@ -229,7 +229,7 @@ static void set_buffer_lines(buf_T *buf, linenr_T lnum_arg, bool append, typval_ wp->w_cursor.lnum += (linenr_T)added; } } - check_cursor_col(); + check_cursor_col(curwin); update_topline(curwin); } @@ -469,7 +469,7 @@ void f_deletebufline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } } } - check_cursor_col(); + check_cursor_col(curwin); deleted_lines_mark(first, count); rettv->vval.v_number = 0; // OK diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index d7237d6443..e3afc1cf54 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -727,7 +727,7 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) return; } - check_cursor(); + check_cursor(curwin); winchanged = true; } @@ -738,7 +738,7 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) if (fp->col == MAXCOL) { // '> can be MAXCOL, get the length of the line then if (fp->lnum <= curbuf->b_ml.ml_line_count) { - col = (colnr_T)strlen(ml_get(fp->lnum)) + 1; + col = ml_get_len(fp->lnum) + 1; } else { col = MAXCOL; } @@ -746,7 +746,7 @@ static void get_col(typval_T *argvars, typval_T *rettv, bool charcol) col = fp->col + 1; // col(".") when the cursor is on the NUL at the end of the line // because of "coladd" can be seen as an extra column. - if (virtual_active() && fp == &curwin->w_cursor) { + if (virtual_active(curwin) && fp == &curwin->w_cursor) { char *p = get_cursor_pos_ptr(); if (curwin->w_cursor.coladd >= (colnr_T)win_chartabsize(curwin, p, @@ -1185,13 +1185,14 @@ static void set_cursorpos(typval_T *argvars, typval_T *rettv, bool charcol) if (lnum > 0) { curwin->w_cursor.lnum = lnum; } - if (col > 0) { - curwin->w_cursor.col = col - 1; + if (col != MAXCOL && --col < 0) { + col = 0; } + curwin->w_cursor.col = col; curwin->w_cursor.coladd = coladd; // Make sure the cursor is in a valid position. - check_cursor(); + check_cursor(curwin); // Correct cursor for multi-byte character. mb_adjust_cursor(); @@ -1361,7 +1362,7 @@ static void f_dictwatcherdel(typval_T *argvars, typval_T *rettv, EvalFuncData fp /// "did_filetype()" function static void f_did_filetype(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - rettv->vval.v_number = did_filetype; + rettv->vval.v_number = curbuf->b_did_filetype; } /// "diff_filler()" function @@ -2019,6 +2020,9 @@ static void extend_dict(typval_T *argvars, const char *arg_errmsg, bool is_new, action = tv_get_string_chk(&argvars[2]); if (action == NULL) { + if (is_new) { + tv_dict_unref(d1); + } return; // Type error; error message already given. } size_t i; @@ -2028,6 +2032,9 @@ static void extend_dict(typval_T *argvars, const char *arg_errmsg, bool is_new, } } if (i == 3) { + if (is_new) { + tv_dict_unref(d1); + } semsg(_(e_invarg2), action); return; } @@ -2816,24 +2823,24 @@ static char *block_def2str(struct block_def *bd) return ret; } -/// "getregion()" function -static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +static int getregionpos(typval_T *argvars, typval_T *rettv, pos_T *p1, pos_T *p2, + bool *const inclusive, MotionType *region_type, oparg_T *oa) + FUNC_ATTR_NONNULL_ALL { tv_list_alloc_ret(rettv, kListLenMayKnow); if (tv_check_for_list_arg(argvars, 0) == FAIL || tv_check_for_list_arg(argvars, 1) == FAIL || tv_check_for_opt_dict_arg(argvars, 2) == FAIL) { - return; + return FAIL; } int fnum1 = -1; int fnum2 = -1; - pos_T p1, p2; - if (list2fpos(&argvars[0], &p1, &fnum1, NULL, false) != OK - || list2fpos(&argvars[1], &p2, &fnum2, NULL, false) != OK + if (list2fpos(&argvars[0], p1, &fnum1, NULL, false) != OK + || list2fpos(&argvars[1], p2, &fnum2, NULL, false) != OK || fnum1 != fnum2) { - return; + return FAIL; } bool is_select_exclusive; @@ -2851,87 +2858,109 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) type = default_type; } - MotionType region_type = kMTUnknown; if (type[0] == 'v' && type[1] == NUL) { - region_type = kMTCharWise; + *region_type = kMTCharWise; } else if (type[0] == 'V' && type[1] == NUL) { - region_type = kMTLineWise; + *region_type = kMTLineWise; } else if (type[0] == Ctrl_V && type[1] == NUL) { - region_type = kMTBlockWise; + *region_type = kMTBlockWise; } else { - return; + semsg(_(e_invargNval), "type", type); + return FAIL; } - buf_T *const save_curbuf = curbuf; + buf_T *findbuf = fnum1 != 0 ? buflist_findnr(fnum1) : curbuf; + if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL) { + emsg(_(e_buffer_is_not_loaded)); + return FAIL; + } - if (fnum1 != 0) { - buf_T *findbuf = buflist_findnr(fnum1); - // buffer not loaded - if (findbuf == NULL || findbuf->b_ml.ml_mfp == NULL) { - return; - } - curbuf = findbuf; + if (p1->lnum < 1 || p1->lnum > findbuf->b_ml.ml_line_count) { + semsg(_(e_invalid_line_number_nr), p1->lnum); + return FAIL; + } + if (p1->col == MAXCOL) { + p1->col = ml_get_buf_len(findbuf, p1->lnum) + 1; + } else if (p1->col < 1 || p1->col > ml_get_buf_len(findbuf, p1->lnum) + 1) { + semsg(_(e_invalid_column_number_nr), p1->col); + return FAIL; } - const TriState save_virtual = virtual_op; - virtual_op = virtual_active(); + if (p2->lnum < 1 || p2->lnum > findbuf->b_ml.ml_line_count) { + semsg(_(e_invalid_line_number_nr), p2->lnum); + return FAIL; + } + if (p2->col == MAXCOL) { + p2->col = ml_get_buf_len(findbuf, p2->lnum) + 1; + } else if (p2->col < 1 || p2->col > ml_get_buf_len(findbuf, p2->lnum) + 1) { + semsg(_(e_invalid_column_number_nr), p2->col); + return FAIL; + } + + curbuf = findbuf; + curwin->w_buffer = curbuf; + virtual_op = virtual_active(curwin); - // NOTE: Adjust is needed. - p1.col--; - p2.col--; + // NOTE: Adjustment is needed. + p1->col--; + p2->col--; - if (!lt(p1, p2)) { + if (!lt(*p1, *p2)) { // swap position - pos_T p = p1; - p1 = p2; - p2 = p; + pos_T p = *p1; + *p1 = *p2; + *p2 = p; } - oparg_T oa; - bool inclusive = true; - - if (region_type == kMTCharWise) { - // handle 'selection' == "exclusive" - if (is_select_exclusive && !equalpos(p1, p2)) { - if (p2.coladd > 0) { - p2.coladd--; - } else if (p2.col > 0) { - p2.col--; - mark_mb_adjustpos(curbuf, &p2); - } else if (p2.lnum > 1) { - p2.lnum--; - p2.col = (colnr_T)strlen(ml_get(p2.lnum)); - if (p2.col > 0) { - p2.col--; - mark_mb_adjustpos(curbuf, &p2); - } - } + if (*region_type == kMTCharWise) { + // Handle 'selection' == "exclusive". + if (is_select_exclusive && !equalpos(*p1, *p2)) { + // When backing up to previous line, inclusive becomes false. + *inclusive = !unadjust_for_sel_inner(p2); } - // if fp2 is on NUL (empty line) inclusive becomes false - if (*ml_get_pos(&p2) == NUL && !virtual_op) { - inclusive = false; + // If p2 is on NUL (end of line), inclusive becomes false. + if (*inclusive && !virtual_op && *ml_get_pos(p2) == NUL) { + *inclusive = false; } - } else if (region_type == kMTBlockWise) { + } else if (*region_type == kMTBlockWise) { colnr_T sc1, ec1, sc2, ec2; - getvvcol(curwin, &p1, &sc1, NULL, &ec1); - getvvcol(curwin, &p2, &sc2, NULL, &ec2); - oa.motion_type = kMTBlockWise; - oa.inclusive = true; - oa.op_type = OP_NOP; - oa.start = p1; - oa.end = p2; - oa.start_vcol = MIN(sc1, sc2); + getvvcol(curwin, p1, &sc1, NULL, &ec1); + getvvcol(curwin, p2, &sc2, NULL, &ec2); + oa->motion_type = kMTBlockWise; + oa->inclusive = true; + oa->op_type = OP_NOP; + oa->start = *p1; + oa->end = *p2; + oa->start_vcol = MIN(sc1, sc2); if (is_select_exclusive && ec1 < sc2 && 0 < sc2 && ec2 > ec1) { - oa.end_vcol = sc2 - 1; + oa->end_vcol = sc2 - 1; } else { - oa.end_vcol = MAX(ec1, ec2); + oa->end_vcol = MAX(ec1, ec2); } } // Include the trailing byte of a multi-byte char. - int l = utfc_ptr2len(ml_get_pos(&p2)); + int l = utfc_ptr2len(ml_get_pos(p2)); if (l > 1) { - p2.col += l - 1; + p2->col += l - 1; + } + + return OK; +} + +/// "getregion()" function +static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + buf_T *const save_curbuf = curbuf; + const TriState save_virtual = virtual_op; + + pos_T p1, p2; + bool inclusive = true; + MotionType region_type = kMTUnknown; + oparg_T oa; + + if (getregionpos(argvars, rettv, &p1, &p2, &inclusive, ®ion_type, &oa) == FAIL) { + return; } for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) { @@ -2955,10 +2984,127 @@ static void f_getregion(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_list_append_allocated_string(rettv->vval.v_list, akt); } - if (curbuf != save_curbuf) { - curbuf = save_curbuf; + // getregionpos() may change curbuf and virtual_op + curbuf = save_curbuf; + curwin->w_buffer = curbuf; + virtual_op = save_virtual; +} + +static void add_regionpos_range(typval_T *rettv, pos_T p1, pos_T p2) +{ + list_T *l1 = tv_list_alloc(2); + tv_list_append_list(rettv->vval.v_list, l1); + + list_T *l2 = tv_list_alloc(4); + tv_list_append_list(l1, l2); + + list_T *l3 = tv_list_alloc(4); + tv_list_append_list(l1, l3); + + tv_list_append_number(l2, curbuf->b_fnum); + tv_list_append_number(l2, p1.lnum); + tv_list_append_number(l2, p1.col); + tv_list_append_number(l2, p1.coladd); + + tv_list_append_number(l3, curbuf->b_fnum); + tv_list_append_number(l3, p2.lnum); + tv_list_append_number(l3, p2.col); + tv_list_append_number(l3, p2.coladd); +} + +/// "getregionpos()" function +static void f_getregionpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) +{ + buf_T *const save_curbuf = curbuf; + const TriState save_virtual = virtual_op; + + pos_T p1, p2; + bool inclusive = true; + MotionType region_type = kMTUnknown; + bool allow_eol = false; + oparg_T oa; + + if (getregionpos(argvars, rettv, &p1, &p2, &inclusive, ®ion_type, &oa) == FAIL) { + return; + } + + if (argvars[2].v_type == VAR_DICT) { + allow_eol = tv_dict_get_bool(argvars[2].vval.v_dict, "eol", false); + } + + for (linenr_T lnum = p1.lnum; lnum <= p2.lnum; lnum++) { + pos_T ret_p1, ret_p2; + colnr_T line_len = ml_get_len(lnum); + + if (region_type == kMTLineWise) { + ret_p1.col = 1; + ret_p1.coladd = 0; + ret_p2.col = MAXCOL; + ret_p2.coladd = 0; + } else { + struct block_def bd; + + if (region_type == kMTBlockWise) { + block_prep(&oa, &bd, lnum, false); + } else { + charwise_block_prep(p1, p2, &bd, lnum, inclusive); + } + + if (bd.is_oneChar) { // selection entirely inside one char + if (region_type == kMTBlockWise) { + ret_p1.col = bd.textcol; + ret_p1.coladd = bd.start_char_vcols - (bd.start_vcol - oa.start_vcol); + } else { + ret_p1.col = p1.col + 1; + ret_p1.coladd = p1.coladd; + } + } else if (region_type == kMTBlockWise && oa.start_vcol > bd.start_vcol) { + // blockwise selection entirely beyond end of line + ret_p1.col = MAXCOL; + ret_p1.coladd = oa.start_vcol - bd.start_vcol; + bd.is_oneChar = true; + } else if (bd.startspaces > 0) { + ret_p1.col = bd.textcol; + ret_p1.coladd = bd.start_char_vcols - bd.startspaces; + } else { + ret_p1.col = bd.textcol + 1; + ret_p1.coladd = 0; + } + + if (bd.is_oneChar) { // selection entirely inside one char + ret_p2.col = ret_p1.col; + ret_p2.coladd = ret_p1.coladd + bd.startspaces + bd.endspaces; + } else if (bd.endspaces > 0) { + ret_p2.col = bd.textcol + bd.textlen + 1; + ret_p2.coladd = bd.endspaces; + } else { + ret_p2.col = bd.textcol + bd.textlen; + ret_p2.coladd = 0; + } + } + + if (!allow_eol && ret_p1.col > line_len) { + ret_p1.col = 0; + ret_p1.coladd = 0; + } else if (ret_p1.col > line_len + 1) { + ret_p1.col = line_len + 1; + } + + if (!allow_eol && ret_p2.col > line_len) { + ret_p2.col = ret_p1.col == 0 ? 0 : line_len; + ret_p2.coladd = 0; + } else if (ret_p2.col > line_len + 1) { + ret_p2.col = line_len + 1; + } + + ret_p1.lnum = lnum; + ret_p2.lnum = lnum; + add_regionpos_range(rettv, ret_p1, ret_p2); } + // getregionpos() may change curbuf and virtual_op + curbuf = save_curbuf; + curwin->w_buffer = curbuf; virtual_op = save_virtual; } @@ -3416,19 +3562,19 @@ static void f_has(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } else if (STRICMP(name, "syntax_items") == 0) { n = syntax_present(curwin); } else if (STRICMP(name, "clipboard_working") == 0) { - n = eval_has_provider("clipboard"); + n = eval_has_provider("clipboard", true); } else if (STRICMP(name, "pythonx") == 0) { - n = eval_has_provider("python3"); + n = eval_has_provider("python3", true); } else if (STRICMP(name, "wsl") == 0) { n = has_wsl(); #ifdef UNIX } else if (STRICMP(name, "unnamedplus") == 0) { - n = eval_has_provider("clipboard"); + n = eval_has_provider("clipboard", true); #endif } } - if (!n && eval_has_provider(name)) { + if (!n && eval_has_provider(name, true)) { n = true; } @@ -3974,7 +4120,7 @@ static void f_islocked(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) FNE_CHECK_START); if (end != NULL && lv.ll_name != NULL) { if (*end != NUL) { - semsg(_(e_trailing_arg), end); + semsg(_(lv.ll_name_len == 0 ? e_invarg2 : e_trailing_arg), end); } else { if (lv.ll_tv == NULL) { dictitem_T *di = find_var(lv.ll_name, lv.ll_name_len, NULL, true); @@ -4630,7 +4776,7 @@ static void f_line(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (wp != NULL && tp != NULL) { switchwin_T switchwin; if (switch_win_noblock(&switchwin, wp, tp, true) == OK) { - check_cursor(); + check_cursor(curwin); fp = var2fpos(&argvars[0], true, &fnum, false); } restore_win_noblock(&switchwin, true); @@ -6454,7 +6600,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) char *v = os_resolve_shortcut(fname); if (v == NULL) { if (os_is_reparse_point_include(fname)) { - v = os_realpath(fname, v); + v = os_realpath(fname, NULL, MAXPATHL + 1); } } rettv->vval.v_string = (v == NULL ? xstrdup(fname) : v); @@ -6606,7 +6752,7 @@ static void f_resolve(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) xfree(buf); } # else - char *v = os_realpath(fname, NULL); + char *v = os_realpath(fname, NULL, MAXPATHL + 1); rettv->vval.v_string = v == NULL ? xstrdup(fname) : v; # endif #endif @@ -6957,12 +7103,13 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) .sa_tm = &tm, }; + const size_t patlen = strlen(pat); int subpatnum; // Repeat until {skip} returns false. while (true) { - subpatnum - = searchit(curwin, curbuf, &pos, NULL, dir, (char *)pat, 1, options, RE_SEARCH, &sia); + subpatnum = searchit(curwin, curbuf, &pos, NULL, dir, (char *)pat, patlen, 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)) { @@ -7016,7 +7163,7 @@ static int search_cmn(typval_T *argvars, pos_T *match_pos, int *flagsp) } // "/$" will put the cursor after the end of the line, may need to // correct that here - check_cursor(); + check_cursor(curwin); } // If 'n' flag is used: restore cursor position. @@ -7517,16 +7664,20 @@ int do_searchpair(const char *spat, const char *mpat, const char *epat, int dir, // Make two search patterns: start/end (pat2, for in nested pairs) and // start/middle/end (pat3, for the top pair). - const size_t pat2_len = strlen(spat) + strlen(epat) + 17; - char *pat2 = xmalloc(pat2_len); - const size_t pat3_len = strlen(spat) + strlen(mpat) + strlen(epat) + 25; - char *pat3 = xmalloc(pat3_len); - snprintf(pat2, pat2_len, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); + const size_t spatlen = strlen(spat); + const size_t epatlen = strlen(epat); + const size_t pat2size = spatlen + epatlen + 17; + char *pat2 = xmalloc(pat2size); + const size_t pat3size = spatlen + strlen(mpat) + epatlen + 25; + char *pat3 = xmalloc(pat3size); + int pat2len = snprintf(pat2, pat2size, "\\m\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat); + int pat3len; if (*mpat == NUL) { STRCPY(pat3, pat2); + pat3len = pat2len; } else { - snprintf(pat3, pat3_len, - "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat, mpat); + pat3len = snprintf(pat3, pat3size, + "\\m\\(%s\\m\\)\\|\\(%s\\m\\)\\|\\(%s\\m\\)", spat, epat, mpat); } if (flags & SP_START) { options |= SEARCH_START; @@ -7543,13 +7694,15 @@ int do_searchpair(const char *spat, const char *mpat, const char *epat, int dir, pos_T foundpos; clearpos(&foundpos); char *pat = pat3; + assert(pat3len >= 0); + size_t patlen = (size_t)pat3len; while (true) { searchit_arg_T sia = { .sa_stop_lnum = lnum_stop, .sa_tm = &tm, }; - int n = searchit(curwin, curbuf, &pos, NULL, dir, pat, 1, + int n = searchit(curwin, curbuf, &pos, NULL, dir, pat, patlen, 1, options, RE_SEARCH, &sia); if (n == FAIL || (firstpos.lnum != 0 && equalpos(pos, firstpos))) { // didn't find it or found the first match again: FAIL @@ -7778,7 +7931,7 @@ static void set_position(typval_T *argvars, typval_T *rettv, bool charpos) curwin->w_curswant = curswant - 1; curwin->w_set_curswant = false; } - check_cursor(); + check_cursor(curwin); rettv->vval.v_number = 0; } else if (name[0] == '\'' && name[1] != NUL && name[2] == NUL) { // set mark @@ -8283,7 +8436,7 @@ static void f_spellbadword(typval_T *argvars, typval_T *rettv, EvalFuncData fptr size_t len = 0; if (argvars[0].v_type == VAR_UNKNOWN) { // Find the start and length of the badly spelled word. - len = spell_move_to(curwin, FORWARD, true, true, &attr); + len = spell_move_to(curwin, FORWARD, SMT_ALL, true, &attr); if (len != 0) { word = get_cursor_pos_ptr(); curwin->w_set_curswant = true; @@ -8675,7 +8828,7 @@ static void f_synID(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) int id = 0; if (!transerr && lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count - && col >= 0 && (size_t)col < strlen(ml_get(lnum))) { + && col >= 0 && col < ml_get_len(lnum)) { id = syn_get_id(curwin, lnum, col, trans, NULL, false); } @@ -8798,8 +8951,8 @@ static void f_synconcealed(typval_T *argvars, typval_T *rettv, EvalFuncData fptr CLEAR_FIELD(str); - if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count && col >= 0 - && (size_t)col <= strlen(ml_get(lnum)) && curwin->w_p_cole > 0) { + if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count + && col >= 0 && col <= ml_get_len(lnum) && curwin->w_p_cole > 0) { syn_get_id(curwin, lnum, col, false, NULL, false); syntax_flags = get_syntax_info(&matchid); @@ -8832,10 +8985,8 @@ static void f_synstack(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) const linenr_T lnum = tv_get_lnum(argvars); const colnr_T col = (colnr_T)tv_get_number(&argvars[1]) - 1; - if (lnum >= 1 - && lnum <= curbuf->b_ml.ml_line_count - && col >= 0 - && (size_t)col <= strlen(ml_get(lnum))) { + if (lnum >= 1 && lnum <= curbuf->b_ml.ml_line_count + && col >= 0 && col <= ml_get_len(lnum)) { tv_list_alloc_ret(rettv, kListLenMayKnow); syn_get_id(curwin, lnum, col, false, NULL, true); @@ -9193,7 +9344,7 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) goto theend; } - check_cursor(); + check_cursor(curwin); winchanged = true; } @@ -9205,9 +9356,9 @@ static void f_virtcol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) if (fp->col < 0) { fp->col = 0; } else { - const size_t len = strlen(ml_get(fp->lnum)); - if (fp->col > (colnr_T)len) { - fp->col = (colnr_T)len; + const colnr_T len = ml_get_len(fp->lnum); + if (fp->col > len) { + fp->col = len; } } getvvcol(curwin, fp, &vcol_start, NULL, &vcol_end); diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 9328f53dbd..eb8c89c36e 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -859,7 +859,7 @@ int tv_list_slice_or_index(list_T *list, bool range, varnumber_T n1_arg, varnumb // A list index out of range is an error. if (!range) { if (verbose) { - semsg(_(e_list_index_out_of_range_nr), (int64_t)n1); + semsg(_(e_list_index_out_of_range_nr), (int64_t)n1_arg); } return FAIL; } diff --git a/src/nvim/eval/typval_defs.h b/src/nvim/eval/typval_defs.h index 0d6ee28adc..e88e6a222a 100644 --- a/src/nvim/eval/typval_defs.h +++ b/src/nvim/eval/typval_defs.h @@ -364,6 +364,7 @@ struct ufunc { struct partial_S { int pt_refcount; ///< Reference count. + int pt_copyID; char *pt_name; ///< Function name; when NULL use pt_func->name. ufunc_T *pt_func; ///< Function pointer; when NULL lookup function with pt_name. bool pt_auto; ///< When true the partial was created by using dict.member diff --git a/src/nvim/eval/userfunc.c b/src/nvim/eval/userfunc.c index d16814ed1e..0ec07399b4 100644 --- a/src/nvim/eval/userfunc.c +++ b/src/nvim/eval/userfunc.c @@ -345,7 +345,7 @@ int get_lambda_tv(char **arg, typval_T *rettv, evalarg_T *evalarg) char *p = xmalloc(len); ((char **)(newlines.ga_data))[newlines.ga_len++] = p; STRCPY(p, "return "); - xstrlcpy(p + 7, start, (size_t)(end - start) + 1); + xmemcpyz(p + 7, start, (size_t)(end - start)); if (strstr(p + 7, "a:") == NULL) { // No a: variables are used for sure. flags |= FC_NOARGS; @@ -2300,17 +2300,28 @@ void ex_function(exarg_T *eap) arg = fudi.fd_newkey; } if (arg != NULL && (fudi.fd_di == NULL || !tv_is_func(fudi.fd_di->di_tv))) { - int j = ((uint8_t)(*arg) == K_SPECIAL) ? 3 : 0; - while (arg[j] != NUL && (j == 0 ? eval_isnamec1(arg[j]) : eval_isnamec(arg[j]))) { - j++; + char *name_base = arg; + if ((uint8_t)(*arg) == K_SPECIAL) { + name_base = vim_strchr(arg, '_'); + if (name_base == NULL) { + name_base = arg + 3; + } else { + name_base++; + } } - if (arg[j] != NUL) { + int i; + for (i = 0; name_base[i] != NUL && (i == 0 + ? eval_isnamec1(name_base[i]) + : eval_isnamec(name_base[i])); i++) {} + if (name_base[i] != NUL) { emsg_funcname(e_invarg2, arg); + goto ret_free; } } // Disallow using the g: dict. if (fudi.fd_dict != NULL && fudi.fd_dict->dv_scope == VAR_DEF_SCOPE) { emsg(_("E862: Cannot use g: here")); + goto ret_free; } } @@ -2360,7 +2371,7 @@ void ex_function(exarg_T *eap) // Read the body of the function, until ":endfunction" is found. if (KeyTyped) { // Check if the function already exists, don't let the user type the - // whole function before telling him it doesn't work! For a script we + // whole function before telling them it doesn't work! For a script we // need to skip the body to be able to find what follows. if (!eap->skip && !eap->forceit) { if (fudi.fd_dict != NULL && fudi.fd_newkey == NULL) { @@ -2404,10 +2415,10 @@ void ex_function(exarg_T *eap) } } else { xfree(line_to_free); - if (eap->getline == NULL) { + if (eap->ea_getline == NULL) { theline = getcmdline(':', 0, indent, do_concat); } else { - theline = eap->getline(':', eap->cookie, indent, do_concat); + theline = eap->ea_getline(':', eap->cookie, indent, do_concat); } line_to_free = theline; } @@ -2428,7 +2439,7 @@ void ex_function(exarg_T *eap) } // Detect line continuation: SOURCING_LNUM increased more than one. - linenr_T sourcing_lnum_off = get_sourced_lnum(eap->getline, eap->cookie); + linenr_T sourcing_lnum_off = get_sourced_lnum(eap->ea_getline, eap->cookie); if (SOURCING_LNUM < sourcing_lnum_off) { sourcing_lnum_off -= SOURCING_LNUM; } else { @@ -2571,11 +2582,13 @@ void ex_function(exarg_T *eap) // and ":let [a, b] =<< [trim] EOF" arg = p; if (checkforcmd(&arg, "let", 2)) { - while (vim_strchr("$@&", *arg) != NULL) { - arg++; + int var_count = 0; + int semicolon = 0; + arg = (char *)skip_var_list(arg, &var_count, &semicolon, true); + if (arg != NULL) { + arg = skipwhite(arg); } - arg = skipwhite(find_name_end(arg, NULL, NULL, FNE_INCL_BR)); - if (arg[0] == '=' && arg[1] == '<' && arg[2] == '<') { + if (arg != NULL && strncmp(arg, "=<<", 3) == 0) { p = skipwhite(arg + 3); while (true) { if (strncmp(p, "trim", 4) == 0) { diff --git a/src/nvim/eval/vars.c b/src/nvim/eval/vars.c index 91ac60d8ea..2eca209ea3 100644 --- a/src/nvim/eval/vars.c +++ b/src/nvim/eval/vars.c @@ -57,11 +57,13 @@ typedef int (*ex_unletlock_callback)(lval_T *, char *, exarg_T *, int); #define DICT_MAXNEST 100 // maximum nesting of lists and dicts static const char *e_letunexp = N_("E18: Unexpected characters in :let"); +static const char e_double_semicolon_in_list_of_variables[] + = N_("E452: Double ; in list of variables"); static const char *e_lock_unlock = N_("E940: Cannot lock or unlock variable %s"); static const char e_setting_v_str_to_value_with_wrong_type[] = N_("E963: Setting v:%s to value with wrong type"); -static const char e_cannot_use_heredoc_here[] - = N_("E991: Cannot use =<< here"); +static const char e_missing_end_marker_str[] = N_("E990: Missing end marker '%s'"); +static const char e_cannot_use_heredoc_here[] = N_("E991: Cannot use =<< here"); /// Evaluate one Vim expression {expr} in string "p" and append the /// resulting string to "gap". "p" points to the opening "{". @@ -86,7 +88,7 @@ char *eval_one_expr_in_str(char *p, garray_T *gap, bool evaluate) } if (evaluate) { *block_end = NUL; - char *expr_val = eval_to_string(block_start, true); + char *expr_val = eval_to_string(block_start, false); *block_end = '}'; if (expr_val == NULL) { return NULL; @@ -177,8 +179,15 @@ list_T *heredoc_get(exarg_T *eap, char *cmd, bool script_get) int text_indent_len = 0; char *text_indent = NULL; char dot[] = "."; - - if (eap->getline == NULL) { + bool heredoc_in_string = false; + char *line_arg = NULL; + char *nl_ptr = vim_strchr(cmd, '\n'); + + if (nl_ptr != NULL) { + heredoc_in_string = true; + line_arg = nl_ptr + 1; + *nl_ptr = NUL; + } else if (eap->ea_getline == NULL) { emsg(_(e_cannot_use_heredoc_here)); return NULL; } @@ -214,11 +223,12 @@ list_T *heredoc_get(exarg_T *eap, char *cmd, bool script_get) break; } + const char comment_char = '"'; // The marker is the next word. - if (*cmd != NUL && *cmd != '"') { + if (*cmd != NUL && *cmd != comment_char) { marker = skipwhite(cmd); char *p = skiptowhite(marker); - if (*skipwhite(p) != NUL && *skipwhite(p) != '"') { + if (*skipwhite(p) != NUL && *skipwhite(p) != comment_char) { semsg(_(e_trailing_arg), p); return NULL; } @@ -244,13 +254,34 @@ list_T *heredoc_get(exarg_T *eap, char *cmd, bool script_get) int mi = 0; int ti = 0; - xfree(theline); - theline = eap->getline(NUL, eap->cookie, 0, false); - if (theline == NULL) { - if (!script_get) { - semsg(_("E990: Missing end marker '%s'"), marker); + if (heredoc_in_string) { + // heredoc in a string separated by newlines. Get the next line + // from the string. + + if (*line_arg == NUL) { + if (!script_get) { + semsg(_(e_missing_end_marker_str), marker); + } + break; + } + + theline = line_arg; + char *next_line = vim_strchr(theline, '\n'); + if (next_line == NULL) { + line_arg += strlen(line_arg); + } else { + *next_line = NUL; + line_arg = next_line + 1; + } + } else { + xfree(theline); + theline = eap->ea_getline(NUL, eap->cookie, 0, false); + if (theline == NULL) { + if (!script_get) { + semsg(_(e_missing_end_marker_str), marker); + } + break; } - break; } // with "trim": skip the indent matching the :let line to find the @@ -296,13 +327,17 @@ list_T *heredoc_get(exarg_T *eap, char *cmd, bool script_get) eval_failed = true; continue; } - xfree(theline); - theline = str; + tv_list_append_allocated_string(l, str); + } else { + tv_list_append_string(l, str, -1); } - - tv_list_append_string(l, str, -1); } - xfree(theline); + if (heredoc_in_string) { + // Next command follows the heredoc in the string. + eap->nextcmd = line_arg; + } else { + xfree(theline); + } xfree(text_indent); if (eval_failed) { @@ -341,7 +376,7 @@ void ex_let(exarg_T *eap) const char *argend; int first = true; - argend = skip_var_list(arg, &var_count, &semicolon); + argend = skip_var_list(arg, &var_count, &semicolon, false); if (argend == NULL) { return; } @@ -515,10 +550,11 @@ int ex_let_vars(char *arg_start, typval_T *tv, int copy, int semicolon, int var_ /// Skip over assignable variable "var" or list of variables "[var, var]". /// Used for ":let varvar = expr" and ":for varvar in expr". /// For "[var, var]" increment "*var_count" for each variable. -/// for "[var, var; var]" set "semicolon". +/// for "[var, var; var]" set "semicolon" to 1. +/// If "silent" is true do not give an "invalid argument" error message. /// /// @return NULL for an error. -const char *skip_var_list(const char *arg, int *var_count, int *semicolon) +const char *skip_var_list(const char *arg, int *var_count, int *semicolon, bool silent) { if (*arg == '[') { const char *s; @@ -528,7 +564,9 @@ const char *skip_var_list(const char *arg, int *var_count, int *semicolon) p = skipwhite(p + 1); // skip whites after '[', ';' or ',' s = skip_var_one(p); if (s == p) { - semsg(_(e_invarg2), p); + if (!silent) { + semsg(_(e_invarg2), p); + } return NULL; } (*var_count)++; @@ -538,12 +576,16 @@ const char *skip_var_list(const char *arg, int *var_count, int *semicolon) break; } else if (*p == ';') { if (*semicolon == 1) { - emsg(_("E452: Double ; in list of variables")); + if (!silent) { + emsg(_(e_double_semicolon_in_list_of_variables)); + } return NULL; } *semicolon = 1; } else if (*p != ',') { - semsg(_(e_invarg2), p); + if (!silent) { + semsg(_(e_invarg2), p); + } return NULL; } } diff --git a/src/nvim/eval/window.c b/src/nvim/eval/window.c index b8aa0c9641..68de40f983 100644 --- a/src/nvim/eval/window.c +++ b/src/nvim/eval/window.c @@ -14,6 +14,7 @@ #include "nvim/eval/typval.h" #include "nvim/eval/typval_defs.h" #include "nvim/eval/window.h" +#include "nvim/ex_getln.h" #include "nvim/garray.h" #include "nvim/garray_defs.h" #include "nvim/gettext_defs.h" @@ -515,7 +516,7 @@ bool win_execute_before(win_execute_T *args, win_T *wp, tabpage_T *tp) } if (switch_win_noblock(&args->switchwin, wp, tp, true) == OK) { - check_cursor(); + check_cursor(curwin); return true; } return false; @@ -539,7 +540,7 @@ void win_execute_after(win_execute_T *args) // In case the command moved the cursor or changed the Visual area, // check it is valid. - check_cursor(); + check_cursor(curwin); if (VIsual_active) { check_pos(curbuf, &VIsual); } @@ -583,9 +584,13 @@ void f_win_getid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) void f_win_gotoid(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { int id = (int)tv_get_number(&argvars[0]); + if (curwin->handle == id) { + // Nothing to do. + rettv->vval.v_number = 1; + return; + } - if (cmdwin_type != 0) { - emsg(_(e_cmdwin)); + if (text_or_buf_locked()) { return; } FOR_ALL_TAB_WINDOWS(tp, wp) { @@ -659,55 +664,19 @@ void f_win_screenpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) tv_list_append_number(rettv->vval.v_list, wp == NULL ? 0 : wp->w_wincol + 1); } -/// Move the window wp into a new split of targetwin in a given direction -static void win_move_into_split(win_T *wp, win_T *targetwin, int size, int flags) -{ - int height = wp->w_height; - win_T *oldwin = curwin; - - if (wp == targetwin || is_aucmd_win(wp)) { - return; - } - - // Jump to the target window - if (curwin != targetwin) { - win_goto(targetwin); - } - - // Remove the old window and frame from the tree of frames - int dir; - winframe_remove(wp, &dir, NULL); - win_remove(wp, NULL); - last_status(false); // may need to remove last status line - win_comp_pos(); // recompute window positions - - // Split a window on the desired side and put the old window there - win_split_ins(size, flags, wp, dir); - - // If splitting horizontally, try to preserve height - if (size == 0 && !(flags & WSP_VERT)) { - win_setheight_win(height, wp); - if (p_ea) { - win_equal(wp, true, 'v'); - } - } - - if (oldwin != curwin) { - win_goto(oldwin); - } -} - /// "win_splitmove()" function void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { win_T *wp = find_win_by_nr_or_id(&argvars[0]); win_T *targetwin = find_win_by_nr_or_id(&argvars[1]); + win_T *oldwin = curwin; + + rettv->vval.v_number = -1; if (wp == NULL || targetwin == NULL || wp == targetwin || !win_valid(wp) || !win_valid(targetwin) - || win_float_valid(wp) || win_float_valid(targetwin)) { + || targetwin->w_floating) { emsg(_(e_invalwindow)); - rettv->vval.v_number = -1; return; } @@ -732,7 +701,27 @@ void f_win_splitmove(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) size = (int)tv_dict_get_number(d, "size"); } - win_move_into_split(wp, targetwin, size, flags); + // Check if we're allowed to continue before we bother switching windows. + if (is_aucmd_win(wp) || text_or_buf_locked() || check_split_disallowed(wp) == FAIL) { + return; + } + + if (curwin != targetwin) { + win_goto(targetwin); + } + + // Autocommands may have sent us elsewhere or closed "wp" or "oldwin". + if (curwin == targetwin && win_valid(wp)) { + if (win_splitmove(wp, size, flags) == OK) { + rettv->vval.v_number = 0; + } + } else { + emsg(_(e_auabort)); + } + + if (oldwin != curwin && win_valid(oldwin)) { + win_goto(oldwin); + } } /// "win_gettype(nr)" function @@ -785,7 +774,7 @@ void f_winbufnr(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "wincol()" function void f_wincol(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - validate_cursor(); + validate_cursor(curwin); rettv->vval.v_number = curwin->w_wcol + 1; } @@ -822,7 +811,7 @@ void f_winlayout(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// "winline()" function void f_winline(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) { - validate_cursor(); + validate_cursor(curwin); rettv->vval.v_number = curwin->w_wrow + 1; } @@ -894,10 +883,10 @@ void f_winrestview(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) curwin->w_skipcol = (colnr_T)tv_get_number(&di->di_tv); } - check_cursor(); + check_cursor(curwin); win_new_height(curwin, curwin->w_height); win_new_width(curwin, curwin->w_width); - changed_window_setting(); + changed_window_setting(curwin); if (curwin->w_topline <= 0) { curwin->w_topline = 1; @@ -967,11 +956,8 @@ int switch_win_noblock(switchwin_T *switchwin, win_T *win, tabpage_T *tp, bool n if (tp != NULL) { switchwin->sw_curtab = curtab; if (no_display) { - curtab->tp_firstwin = firstwin; - curtab->tp_lastwin = lastwin; - curtab = tp; - firstwin = curtab->tp_firstwin; - lastwin = curtab->tp_lastwin; + unuse_tabpage(curtab); + use_tabpage(tp); } else { goto_tabpage_tp(tp, false, false); } @@ -998,11 +984,12 @@ void restore_win_noblock(switchwin_T *switchwin, bool no_display) { if (switchwin->sw_curtab != NULL && valid_tabpage(switchwin->sw_curtab)) { if (no_display) { - curtab->tp_firstwin = firstwin; - curtab->tp_lastwin = lastwin; - curtab = switchwin->sw_curtab; - firstwin = curtab->tp_firstwin; - lastwin = curtab->tp_lastwin; + win_T *const old_tp_curwin = curtab->tp_curwin; + + unuse_tabpage(curtab); + // Don't change the curwin of the tabpage we temporarily visited. + curtab->tp_curwin = old_tp_curwin; + use_tabpage(switchwin->sw_curtab); } else { goto_tabpage_tp(switchwin->sw_curtab, false, false); } diff --git a/src/nvim/event/libuv_process.c b/src/nvim/event/libuv_process.c index a7966994e0..f77d686c10 100644 --- a/src/nvim/event/libuv_process.c +++ b/src/nvim/event/libuv_process.c @@ -90,7 +90,7 @@ int libuv_process_spawn(LibuvProcess *uvproc) int status; if ((status = uv_spawn(&proc->loop->uv, &uvproc->uv, &uvproc->uvopts))) { - ELOG("uv_spawn(%s) failed: %s", uvproc->uvopts.file, uv_strerror(status)); + ILOG("uv_spawn(%s) failed: %s", uvproc->uvopts.file, uv_strerror(status)); if (uvproc->uvopts.env) { os_free_fullenv(uvproc->uvopts.env); } diff --git a/src/nvim/event/loop.c b/src/nvim/event/loop.c index 93948d3eaa..e1ebcecbd6 100644 --- a/src/nvim/event/loop.c +++ b/src/nvim/event/loop.c @@ -39,10 +39,8 @@ void loop_init(Loop *loop, void *data) /// @param ms 0: non-blocking poll. /// > 0: timeout after `ms`. /// < 0: wait forever. -/// @param once true: process at most one `Loop.uv` event. -/// false: process until `ms` timeout (only has effect if `ms` > 0). /// @return true if `ms` > 0 and was reached -bool loop_uv_run(Loop *loop, int64_t ms, bool once) +static bool loop_uv_run(Loop *loop, int64_t ms) { if (loop->recursive++) { abort(); // Should not re-enter uv_run @@ -60,9 +58,7 @@ bool loop_uv_run(Loop *loop, int64_t ms, bool once) mode = UV_RUN_NOWAIT; } - do { - uv_run(&loop->uv, mode); - } while (ms > 0 && !once && !*timeout_expired); + uv_run(&loop->uv, mode); if (ms > 0) { uv_timer_stop(&loop->poll_timer); @@ -83,7 +79,7 @@ bool loop_uv_run(Loop *loop, int64_t ms, bool once) /// @return true if `ms` > 0 and was reached bool loop_poll_events(Loop *loop, int64_t ms) { - bool timeout_expired = loop_uv_run(loop, ms, true); + bool timeout_expired = loop_uv_run(loop, ms); multiqueue_process_events(loop->fast_events); return timeout_expired; } diff --git a/src/nvim/event/rstream.c b/src/nvim/event/rstream.c index f50c8a0e5a..6b4ab472e4 100644 --- a/src/nvim/event/rstream.c +++ b/src/nvim/event/rstream.c @@ -106,7 +106,7 @@ static void read_cb(uv_stream_t *uvstream, ssize_t cnt, const uv_buf_t *buf) // http://docs.libuv.org/en/latest/stream.html#c.uv_read_start. // // We don't need to do anything with the RBuffer because the next call - // to `alloc_cb` will return the same unused pointer(`rbuffer_produced` + // to `alloc_cb` will return the same unused pointer (`rbuffer_produced` // won't be called) if (cnt == UV_ENOBUFS || cnt == 0) { return; diff --git a/src/nvim/event/wstream.c b/src/nvim/event/wstream.c index 406ff1620d..c67a9b96ed 100644 --- a/src/nvim/event/wstream.c +++ b/src/nvim/event/wstream.c @@ -103,7 +103,7 @@ err: /// Creates a WBuffer object for holding output data. Instances of this /// object can be reused across Stream instances, and the memory is freed -/// automatically when no longer needed(it tracks the number of references +/// automatically when no longer needed (it tracks the number of references /// internally) /// /// @param data Data stored by the WBuffer @@ -111,7 +111,7 @@ err: /// @param refcount The number of references for the WBuffer. This will be used /// by Stream instances to decide when a WBuffer should be freed. /// @param cb Pointer to function that will be responsible for freeing -/// the buffer data(passing 'free' will work as expected). +/// the buffer data (passing `xfree` will work as expected). /// @return The allocated WBuffer instance WBuffer *wstream_new_buffer(char *data, size_t size, size_t refcount, wbuffer_data_finalizer cb) FUNC_ATTR_NONNULL_ARG(1) diff --git a/src/nvim/ex_cmds.c b/src/nvim/ex_cmds.c index 74ad8e95a2..834cc6698a 100644 --- a/src/nvim/ex_cmds.c +++ b/src/nvim/ex_cmds.c @@ -541,7 +541,7 @@ void ex_sort(exarg_T *eap) // Also get the longest line length for allocating "sortbuf". for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { char *s = ml_get(lnum); - int len = (int)strlen(s); + int len = ml_get_len(lnum); if (maxlen < len) { maxlen = len; } @@ -643,8 +643,8 @@ void ex_sort(exarg_T *eap) } char *s = ml_get(get_lnum); - size_t bytelen = strlen(s) + 1; // include EOL in bytelen - old_count += (bcount_t)bytelen; + colnr_T bytelen = ml_get_len(get_lnum) + 1; // include EOL in bytelen + old_count += bytelen; if (!unique || i == 0 || string_compare(s, sortbuf1) != 0) { // Copy the line into a buffer, it may become invalid in // ml_append(). And it's needed for "unique". @@ -652,7 +652,7 @@ void ex_sort(exarg_T *eap) if (ml_append(lnum++, sortbuf1, 0, false) == FAIL) { break; } - new_count += (bcount_t)bytelen; + new_count += bytelen; } fast_breakcheck(); if (got_int) { @@ -740,7 +740,7 @@ int do_move(linenr_T line1, linenr_T line2, linenr_T dest) return FAIL; } for (extra = 0, l = line1; l <= line2; l++) { - char *str = xstrdup(ml_get(l + extra)); + char *str = xstrnsave(ml_get(l + extra), (size_t)ml_get_len(l + extra)); ml_append(dest + l - line1, str, 0, false); xfree(str); if (dest < line1) { @@ -876,9 +876,8 @@ void ex_copy(linenr_T line1, linenr_T line2, linenr_T n) curwin->w_cursor.lnum = n; while (line1 <= line2) { - // need to use xstrdup() because the line will be unlocked within - // ml_append() - char *p = xstrdup(ml_get(line1)); + // need to make a copy because the line will be unlocked within ml_append() + char *p = xstrnsave(ml_get(line1), (size_t)ml_get_len(line1)); ml_append(curwin->w_cursor.lnum, p, 0, false); xfree(p); @@ -2008,6 +2007,10 @@ static int check_readonly(int *forceit, buf_T *buf) /// GETFILE_OPEN_OTHER for successfully opening another file. int getfile(int fnum, char *ffname_arg, char *sfname_arg, bool setpm, linenr_T lnum, bool forceit) { + if (!check_can_set_curbuf_forceit(forceit)) { + return GETFILE_ERROR; + } + char *ffname = ffname_arg; char *sfname = sfname_arg; bool other; @@ -2463,7 +2466,7 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum // Since we are starting to edit a file, consider the filetype to be // unset. Helps for when an autocommand changes files and expects syntax // highlighting to work in the other file. - did_filetype = false; + curbuf->b_did_filetype = false; // other_file oldbuf // false false re-edit same file, buffer is re-used @@ -2634,14 +2637,14 @@ int do_ecmd(int fnum, char *ffname, char *sfname, exarg_T *eap, linenr_T newlnum if (newcol >= 0) { // position set by autocommands curwin->w_cursor.lnum = newlnum; curwin->w_cursor.col = newcol; - check_cursor(); + check_cursor(curwin); } else if (newlnum > 0) { // line number from caller or old position curwin->w_cursor.lnum = newlnum; check_cursor_lnum(curwin); if (solcol >= 0 && !p_sol) { // 'sol' is off: Use last known column. curwin->w_cursor.col = solcol; - check_cursor_col(); + check_cursor_col(curwin); curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; } else { @@ -2780,7 +2783,7 @@ void ex_append(exarg_T *eap) indent = get_indent_lnum(lnum); } } - if (eap->getline == NULL) { + if (eap->ea_getline == NULL) { // No getline() function, use the lines that follow. This ends // when there is no more. if (eap->nextcmd == NULL || *eap->nextcmd == NUL) { @@ -2800,7 +2803,8 @@ void ex_append(exarg_T *eap) // Set State to avoid the cursor shape to be set to MODE_INSERT // state when getline() returns. State = MODE_CMDLINE; - theline = eap->getline(eap->cstack->cs_looplevel > 0 ? -1 : NUL, eap->cookie, indent, true); + theline = eap->ea_getline(eap->cstack->cs_looplevel > 0 ? -1 : NUL, + eap->cookie, indent, true); State = save_State; } lines_left = Rows - 1; @@ -3095,8 +3099,9 @@ void sub_set_replacement(SubReplacementString sub) /// @param[in] save Save pattern to options, history /// /// @returns true if :substitute can be replaced with a join command -static bool sub_joining_lines(exarg_T *eap, char *pat, const char *sub, const char *cmd, bool save) - FUNC_ATTR_NONNULL_ARG(1, 3, 4) +static bool sub_joining_lines(exarg_T *eap, char *pat, size_t patlen, const char *sub, + const char *cmd, bool save) + FUNC_ATTR_NONNULL_ARG(1, 4, 5) { // TODO(vim): find a generic solution to make line-joining operations more // efficient, avoid allocating a string that grows in size. @@ -3134,10 +3139,10 @@ static bool sub_joining_lines(exarg_T *eap, char *pat, const char *sub, const ch if (save) { if ((cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) { - save_re_pat(RE_SUBST, pat, magic_isset()); + save_re_pat(RE_SUBST, pat, patlen, magic_isset()); } // put pattern in history - add_to_history(HIST_SEARCH, pat, true, NUL); + add_to_history(HIST_SEARCH, pat, patlen, true, NUL); } return true; @@ -3296,7 +3301,8 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n if (nmatch > 1) { \ sub_firstlnum += (linenr_T)nmatch - 1; \ xfree(sub_firstline); \ - sub_firstline = xstrdup(ml_get(sub_firstlnum)); \ + sub_firstline = xstrnsave(ml_get(sub_firstlnum), \ + (size_t)ml_get_len(sub_firstlnum)); \ /* When going beyond the last line, stop substituting. */ \ if (sub_firstlnum <= line2) { \ do_again = true; \ @@ -3327,6 +3333,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n }; char *pat = NULL; char *sub = NULL; // init for GCC + size_t patlen = 0; int delimiter; bool has_second_delim = false; int sublen; @@ -3378,12 +3385,14 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n which_pat = RE_SEARCH; // use last '/' pattern } pat = ""; // empty search pattern + patlen = 0; 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 = (uint8_t)(*cmd++); // remember delimiter character pat = cmd; // remember start of search pat + patlen = strlen(pat); cmd = skip_regexp_ex(cmd, delimiter, magic_isset(), &eap->arg, NULL, NULL); if (cmd[0] == delimiter) { // end delimiter found *cmd++ = NUL; // replace it with a NUL @@ -3410,6 +3419,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n return 0; } pat = NULL; // search_regcomp() will use previous pattern + patlen = 0; sub = xstrdup(old_sub.sub); // Vi compatibility quirk: repeating with ":s" keeps the cursor in the @@ -3417,7 +3427,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n endcolumn = (curwin->w_curswant == MAXCOL); } - if (sub != NULL && sub_joining_lines(eap, pat, sub, cmd, cmdpreview_ns <= 0)) { + if (sub != NULL && sub_joining_lines(eap, pat, patlen, sub, cmd, cmdpreview_ns <= 0)) { xfree(sub); return 0; } @@ -3472,7 +3482,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n return 0; } - if (search_regcomp(pat, NULL, RE_SUBST, which_pat, + if (search_regcomp(pat, patlen, NULL, RE_SUBST, which_pat, (cmdpreview_ns > 0 ? 0 : SEARCH_HIS), ®match) == FAIL) { if (subflags.do_error) { emsg(_(e_invcmd)); @@ -3624,7 +3634,8 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n break; } if (sub_firstline == NULL) { - sub_firstline = xstrdup(ml_get(sub_firstlnum)); + sub_firstline = xstrnsave(ml_get(sub_firstlnum), + (size_t)ml_get_len(sub_firstlnum)); } // Save the line number of the last change for the final @@ -3761,7 +3772,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n // really update the line, it would change // what matches. Temporarily replace the line // and change it back afterwards. - orig_line = xstrdup(ml_get(lnum)); + orig_line = xstrnsave(ml_get(lnum), (size_t)ml_get_len(lnum)); char *new_line = concat_str(new_start, sub_firstline + copycol); // Position the cursor relative to the end of the line, the @@ -3783,7 +3794,7 @@ static int do_sub(exarg_T *eap, const proftime_T timeout, const int cmdpreview_n highlight_match = true; update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_SOME_VALID); show_cursor_info_later(true); update_screen(); @@ -4243,7 +4254,7 @@ skip: // when interactive leave cursor on the match if (!subflags.do_ask) { if (endcolumn) { - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } else { beginline(BL_WHITE | BL_FIX); } @@ -4274,7 +4285,7 @@ skip: if (subflags.do_ask && hasAnyFolding(curwin)) { // Cursor position may require updating - changed_window_setting(); + changed_window_setting(curwin); } vim_regfree(regmatch.regprog); @@ -4289,7 +4300,7 @@ skip: // Show 'inccommand' preview if there are matched lines. if (cmdpreview_ns > 0 && !aborting()) { if (got_quit || profile_passed_limit(timeout)) { // Too slow, disable. - set_string_option_direct(kOptInccommand, "", 0, SID_NONE); + set_option_direct(kOptInccommand, STATIC_CSTR_AS_OPTVAL(""), 0, SID_NONE); } else if (*p_icm != NUL && pat != NULL) { if (pre_hl_id == 0) { pre_hl_id = syn_check_group(S_LEN("Substitute")); @@ -4384,6 +4395,7 @@ void ex_global(exarg_T *eap) char delim; // delimiter, normally '/' char *pat; + size_t patlen; regmmatch_T regmatch; // When nesting the command works on one line. This allows for @@ -4419,6 +4431,7 @@ void ex_global(exarg_T *eap) } cmd++; pat = ""; + patlen = 0; } else if (*cmd == NUL) { emsg(_("E148: Regular expression missing from global")); return; @@ -4428,6 +4441,7 @@ void ex_global(exarg_T *eap) delim = *cmd; // get the delimiter cmd++; // skip delimiter if there is one pat = cmd; // remember start of pattern + patlen = strlen(pat); cmd = skip_regexp_ex(cmd, delim, magic_isset(), &eap->arg, NULL, NULL); if (cmd[0] == delim) { // end delimiter found *cmd++ = NUL; // replace it with a NUL @@ -4435,7 +4449,7 @@ void ex_global(exarg_T *eap) } char *used_pat; - if (search_regcomp(pat, &used_pat, RE_BOTH, which_pat, + if (search_regcomp(pat, patlen, &used_pat, RE_BOTH, which_pat, SEARCH_HIS, ®match) == FAIL) { emsg(_(e_invcmd)); return; @@ -4510,7 +4524,7 @@ void global_exe(char *cmd) if (global_need_beginline) { beginline(BL_WHITE | BL_FIX); } else { - check_cursor(); // cursor may be beyond the end of the line + check_cursor(curwin); // cursor may be beyond the end of the line } // the cursor may not have moved in the text but a change in a previous @@ -4569,7 +4583,7 @@ bool prepare_tagpreview(bool undo_sync) RESET_BINDING(curwin); // don't take over 'scrollbind' and 'cursorbind' curwin->w_p_diff = false; // no 'diff' - set_string_option_direct(kOptFoldcolumn, "0", 0, SID_NONE); // no 'foldcolumn' + set_option_direct(kOptFoldcolumn, STATIC_CSTR_AS_OPTVAL("0"), 0, SID_NONE); // no 'foldcolumn' return true; } @@ -4588,7 +4602,7 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i buf_T *cmdpreview_buf = NULL; // disable file info message - set_string_option_direct(kOptShortmess, "F", 0, SID_NONE); + set_option_direct(kOptShortmess, STATIC_CSTR_AS_OPTVAL("F"), 0, SID_NONE); // Place cursor on nearest matching line, to undo do_sub() cursor placement. for (size_t i = 0; i < lines.subresults.size; i++) { @@ -4622,8 +4636,8 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i } char *str = NULL; // construct the line to show in here - size_t old_line_size = 0; - size_t line_size = 0; + colnr_T old_line_size = 0; + colnr_T line_size = 0; linenr_T linenr_preview = 0; // last line added to preview buffer linenr_T linenr_origbuf = 0; // last line added to original buffer linenr_T next_linenr = 0; // next line to show for the match @@ -4662,21 +4676,21 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i line = ""; } else { line = ml_get_buf(orig_buf, next_linenr); - line_size = strlen(line) + (size_t)col_width + 1; + line_size = ml_get_buf_len(orig_buf, next_linenr) + col_width + 1; // Reallocate if line not long enough if (line_size > old_line_size) { - str = xrealloc(str, line_size * sizeof(char)); + str = xrealloc(str, (size_t)line_size * sizeof(char)); old_line_size = line_size; } } // Put "|lnum| line" into `str` and append it to the preview buffer. - snprintf(str, line_size, "|%*" PRIdLINENR "| %s", col_width - 3, + snprintf(str, (size_t)line_size, "|%*" PRIdLINENR "| %s", col_width - 3, next_linenr, line); if (linenr_preview == 0) { ml_replace_buf(cmdpreview_buf, 1, str, true, false); } else { - ml_append_buf(cmdpreview_buf, linenr_preview, str, (colnr_T)line_size, false); + ml_append_buf(cmdpreview_buf, linenr_preview, str, line_size, false); } linenr_preview += 1; } @@ -4689,7 +4703,7 @@ static int show_sub(exarg_T *eap, pos_T old_cusr, PreviewLines *preview_lines, i xfree(str); - set_string_option_direct(kOptShortmess, save_shm_p, 0, SID_NONE); + set_option_direct(kOptShortmess, CSTR_AS_OPTVAL(save_shm_p), 0, SID_NONE); xfree(save_shm_p); return preview ? 2 : 1; diff --git a/src/nvim/ex_cmds.lua b/src/nvim/ex_cmds.lua index 1318eda5eb..c8574c805c 100644 --- a/src/nvim/ex_cmds.lua +++ b/src/nvim/ex_cmds.lua @@ -1,6 +1,6 @@ local bit = require 'bit' -local module = {} +local M = {} -- Description of the values below is contained in ex_cmds_defs.h file. -- "EX_" prefix is omitted. @@ -32,14 +32,14 @@ local FILES = bit.bor(XFILE, EXTRA) local WORD1 = bit.bor(EXTRA, NOSPC) local FILE1 = bit.bor(FILES, NOSPC) -module.flags = { +M.flags = { RANGE = RANGE, DFLALL = DFLALL, PREVIEW = PREVIEW, } -- The following table is described in ex_cmds_defs.h file. -module.cmds = { +M.cmds = { { command = 'append', flags = bit.bor(BANG, RANGE, ZEROR, TRLBAR, CMDWIN, LOCK_OK, MODIFY), @@ -337,7 +337,7 @@ module.cmds = { { command = 'caddbuffer', flags = bit.bor(RANGE, WORD1, TRLBAR), - addr_type = 'ADDR_OTHER', + addr_type = 'ADDR_LINES', func = 'ex_cbuffer', }, { @@ -373,7 +373,7 @@ module.cmds = { { command = 'cbuffer', flags = bit.bor(BANG, RANGE, WORD1, TRLBAR), - addr_type = 'ADDR_OTHER', + addr_type = 'ADDR_LINES', func = 'ex_cbuffer', }, { @@ -459,7 +459,7 @@ module.cmds = { { command = 'cgetbuffer', flags = bit.bor(RANGE, WORD1, TRLBAR), - addr_type = 'ADDR_OTHER', + addr_type = 'ADDR_LINES', func = 'ex_cbuffer', }, { @@ -812,7 +812,7 @@ module.cmds = { }, { command = 'drop', - flags = bit.bor(FILES, CMDARG, NEEDARG, ARGOPT, TRLBAR), + flags = bit.bor(BANG, FILES, CMDARG, NEEDARG, ARGOPT, TRLBAR), addr_type = 'ADDR_NONE', func = 'ex_drop', }, @@ -1329,7 +1329,7 @@ module.cmds = { { command = 'laddbuffer', flags = bit.bor(RANGE, WORD1, TRLBAR), - addr_type = 'ADDR_OTHER', + addr_type = 'ADDR_LINES', func = 'ex_cbuffer', }, { @@ -1353,7 +1353,7 @@ module.cmds = { { command = 'lbuffer', flags = bit.bor(BANG, RANGE, WORD1, TRLBAR), - addr_type = 'ADDR_OTHER', + addr_type = 'ADDR_LINES', func = 'ex_cbuffer', }, { @@ -1451,7 +1451,7 @@ module.cmds = { { command = 'lgetbuffer', flags = bit.bor(RANGE, WORD1, TRLBAR), - addr_type = 'ADDR_OTHER', + addr_type = 'ADDR_LINES', func = 'ex_cbuffer', }, { @@ -3359,4 +3359,4 @@ module.cmds = { }, } -return module +return M diff --git a/src/nvim/ex_cmds2.c b/src/nvim/ex_cmds2.c index 8016e37ca7..f4a6e61831 100644 --- a/src/nvim/ex_cmds2.c +++ b/src/nvim/ex_cmds2.c @@ -212,10 +212,24 @@ void dialog_changed(buf_T *buf, bool checkall) } if (ret == VIM_YES) { - if (buf->b_fname != NULL - && check_overwrite(&ea, buf, buf->b_fname, buf->b_ffname, false) == OK) { + bool empty_bufname = buf->b_fname == NULL; + if (empty_bufname) { + buf_set_name(buf->b_fnum, "Untitled"); + } + + if (check_overwrite(&ea, buf, buf->b_fname, buf->b_ffname, false) == OK) { // didn't hit Cancel - buf_write_all(buf, false); + if (buf_write_all(buf, false) == OK) { + return; + } + } + + // restore to empty when write failed + if (empty_bufname) { + XFREE_CLEAR(buf->b_fname); + XFREE_CLEAR(buf->b_ffname); + XFREE_CLEAR(buf->b_sfname); + unchanged(buf, true, false); } } else if (ret == VIM_NO) { unchanged(buf, true, false); @@ -444,6 +458,30 @@ int buf_write_all(buf_T *buf, bool forceit) /// ":argdo", ":windo", ":bufdo", ":tabdo", ":cdo", ":ldo", ":cfdo" and ":lfdo" void ex_listdo(exarg_T *eap) { + if (curwin->w_p_wfb) { + if ((eap->cmdidx == CMD_ldo || eap->cmdidx == CMD_lfdo) && !eap->forceit) { + // Disallow :ldo if 'winfixbuf' is applied + emsg(_(e_winfixbuf_cannot_go_to_buffer)); + return; + } + + if (win_valid(prevwin) && !prevwin->w_p_wfb) { + // 'winfixbuf' is set; attempt to change to a window without it. + win_goto(prevwin); + } + if (curwin->w_p_wfb) { + // Split the window, which will be 'nowinfixbuf', and set curwin to that + (void)win_split(0, 0); + + if (curwin->w_p_wfb) { + // Autocommands set 'winfixbuf' or sent us to another window + // with it set, or we failed to split the window. Give up. + emsg(_(e_winfixbuf_cannot_go_to_buffer)); + return; + } + } + } + char *save_ei = NULL; // Temporarily override SHM_OVER and SHM_OVERALL to avoid that file @@ -582,7 +620,7 @@ void ex_listdo(exarg_T *eap) i++; // execute the command if (execute) { - do_cmdline(eap->arg, eap->getline, eap->cookie, DOCMD_VERBOSE + DOCMD_NOWAIT); + do_cmdline(eap->arg, eap->ea_getline, eap->cookie, DOCMD_VERBOSE + DOCMD_NOWAIT); } if (eap->cmdidx == CMD_bufdo) { @@ -630,7 +668,7 @@ void ex_listdo(exarg_T *eap) } if (eap->cmdidx == CMD_windo && execute) { - validate_cursor(); // cursor may have moved + validate_cursor(curwin); // cursor may have moved // required when 'scrollbind' has been set if (curwin->w_p_scb) { do_check_scrollbind(true); @@ -842,11 +880,13 @@ void ex_drop(exarg_T *eap) const int save_ar = curbuf->b_p_ar; // reload the file if it is newer - curbuf->b_p_ar = 1; + curbuf->b_p_ar = true; buf_check_timestamp(curbuf); curbuf->b_p_ar = save_ar; } - ex_rewind(eap); + if (curbuf->b_ml.ml_flags & ML_EMPTY) { + ex_rewind(eap); + } return; } } diff --git a/src/nvim/ex_cmds_defs.h b/src/nvim/ex_cmds_defs.h index 827680cbb5..07f92ca169 100644 --- a/src/nvim/ex_cmds_defs.h +++ b/src/nvim/ex_cmds_defs.h @@ -167,8 +167,8 @@ struct exarg { int bad_char; ///< BAD_KEEP, BAD_DROP or replacement byte int useridx; ///< user command index char *errmsg; ///< returned error message - LineGetter getline; ///< Function used to get the next line - void *cookie; ///< argument for getline() + LineGetter ea_getline; ///< function used to get the next line + void *cookie; ///< argument for ea_getline() cstack_T *cstack; ///< condition stack for ":if" etc. }; diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 2913f6d4e9..1fcfc505df 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -144,7 +144,7 @@ struct loop_cookie { int current_line; // last read line from growarray int repeating; // true when looping a second time // When "repeating" is false use "getline" and "cookie" to get lines - char *(*getline)(int, void *, int, bool); + LineGetter lc_getline; void *cookie; }; @@ -216,6 +216,38 @@ static void restore_dbg_stuff(struct dbg_stuff *dsp) current_exception = dsp->current_exception; } +/// Check if ffname differs from fnum. +/// fnum is a buffer number. 0 == current buffer, 1-or-more must be a valid buffer ID. +/// ffname is a full path to where a buffer lives on-disk or would live on-disk. +static bool is_other_file(int fnum, char *ffname) +{ + if (fnum != 0) { + if (fnum == curbuf->b_fnum) { + return false; + } + + return true; + } + + if (ffname == NULL) { + return true; + } + + if (*ffname == NUL) { + return false; + } + + if (!curbuf->file_id_valid + && curbuf->b_sfname != NULL + && *curbuf->b_sfname != NUL) { + // This occurs with unsaved buffers. In which case `ffname` + // actually corresponds to curbuf->b_sfname + return path_fnamecmp(ffname, curbuf->b_sfname) != 0; + } + + return otherfile(ffname); +} + /// Repeatedly get commands for Ex mode, until the ":vi" command is given. void do_exmode(void) { @@ -590,7 +622,7 @@ int do_cmdline(char *cmdline, LineGetter fgetline, void *cookie, int flags) cmd_cookie = (void *)&cmd_loop_cookie; cmd_loop_cookie.lines_gap = &lines_ga; cmd_loop_cookie.current_line = current_line; - cmd_loop_cookie.getline = fgetline; + cmd_loop_cookie.lc_getline = fgetline; cmd_loop_cookie.cookie = cookie; cmd_loop_cookie.repeating = (current_line < lines_ga.ga_len); @@ -971,10 +1003,10 @@ 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) { + if (cp->lc_getline == NULL) { line = getcmdline(c, 0, indent, do_concat); } else { - line = cp->getline(c, cp->cookie, indent, do_concat); + line = cp->lc_getline(c, cp->cookie, indent, do_concat); } if (line != NULL) { store_loop_line(cp->lines_gap, line); @@ -1011,7 +1043,7 @@ bool getline_equal(LineGetter fgetline, void *cookie, LineGetter func) LineGetter gp = fgetline; struct loop_cookie *cp = (struct loop_cookie *)cookie; while (gp == get_loop_line) { - gp = cp->getline; + gp = cp->lc_getline; cp = cp->cookie; } return gp == func; @@ -1029,7 +1061,7 @@ void *getline_cookie(LineGetter fgetline, void *cookie) LineGetter gp = fgetline; struct loop_cookie *cp = (struct loop_cookie *)cookie; while (gp == get_loop_line) { - gp = cp->getline; + gp = cp->lc_getline; cp = cp->cookie; } return cp; @@ -1456,7 +1488,7 @@ bool parse_cmdline(char *cmdline, exarg_T *eap, CmdParseInfo *cmdinfo, const cha .line2 = 1, .cmd = cmdline, .cmdlinep = &cmdline, - .getline = NULL, + .ea_getline = NULL, .cookie = NULL, }; @@ -1743,8 +1775,8 @@ int execute_cmd(exarg_T *eap, CmdParseInfo *cmdinfo, bool preview) && eap->addr_type == ADDR_LINES) { // Put the first line at the start of a closed fold, put the last line // at the end of a closed fold. - hasFolding(eap->line1, &eap->line1, NULL); - hasFolding(eap->line2, NULL, &eap->line2); + hasFolding(curwin, eap->line1, &eap->line1, NULL); + hasFolding(curwin, eap->line2, NULL, &eap->line2); } // Use first argument as count when possible @@ -1965,7 +1997,7 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter // The "ea" structure holds the arguments that can be used. ea.cmd = *cmdlinep; ea.cmdlinep = cmdlinep; - ea.getline = fgetline; + ea.ea_getline = fgetline; ea.cookie = cookie; ea.cstack = cstack; @@ -2213,8 +2245,8 @@ static char *do_one_cmd(char **cmdlinep, int flags, cstack_T *cstack, LineGetter && ea.addr_type == ADDR_LINES) { // Put the first line at the start of a closed fold, put the last line // at the end of a closed fold. - hasFolding(ea.line1, &ea.line1, NULL); - hasFolding(ea.line2, NULL, &ea.line2); + hasFolding(curwin, ea.line1, &ea.line1, NULL); + hasFolding(curwin, ea.line2, NULL, &ea.line2); } // For the ":make" and ":grep" commands we insert the 'makeprg'/'grepprg' @@ -2440,7 +2472,7 @@ int parse_command_modifiers(exarg_T *eap, const char **errormsg, cmdmod_T *cmod, // in ex mode, an empty line works like :+ if (*eap->cmd == NUL && exmode_active - && getline_equal(eap->getline, eap->cookie, getexline) + && getline_equal(eap->ea_getline, eap->cookie, getexline) && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { eap->cmd = "+"; if (!skip_only) { @@ -2697,7 +2729,7 @@ static void apply_cmdmod(cmdmod_T *cmod) // Set 'eventignore' to "all". // First save the existing option value for restoring it later. cmod->cmod_save_ei = xstrdup(p_ei); - set_string_option_direct(kOptEventignore, "all", 0, SID_NONE); + set_option_direct(kOptEventignore, STATIC_CSTR_AS_OPTVAL("all"), 0, SID_NONE); } } @@ -2717,7 +2749,7 @@ void undo_cmdmod(cmdmod_T *cmod) if (cmod->cmod_save_ei != NULL) { // Restore 'eventignore' to the value before ":noautocmd". - set_string_option_direct(kOptEventignore, cmod->cmod_save_ei, 0, SID_NONE); + set_option_direct(kOptEventignore, CSTR_AS_OPTVAL(cmod->cmod_save_ei), 0, SID_NONE); free_string_option(cmod->cmod_save_ei); cmod->cmod_save_ei = NULL; } @@ -2875,9 +2907,9 @@ int parse_cmd_address(exarg_T *eap, const char **errormsg, bool silent) // (where zero usually means to use the first line). // Check the cursor position before returning. if (eap->line2 > 0) { - check_cursor(); + check_cursor(curwin); } else { - check_cursor_col(); + check_cursor_col(curwin); } need_check_cursor = true; } @@ -2899,7 +2931,7 @@ int parse_cmd_address(exarg_T *eap, const char **errormsg, bool silent) theend: if (need_check_cursor) { - check_cursor(); + check_cursor(curwin); } return ret; } @@ -3474,7 +3506,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool } searchcmdlen = 0; flags = silent ? 0 : SEARCH_HIS | SEARCH_MSG; - if (!do_search(NULL, c, c, cmd, 1, flags, NULL)) { + if (!do_search(NULL, c, c, cmd, strlen(cmd), 1, flags, NULL)) { curwin->w_cursor = pos; cmd = NULL; goto error; @@ -3511,7 +3543,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool pos.coladd = 0; if (searchit(curwin, curbuf, &pos, NULL, *cmd == '?' ? BACKWARD : FORWARD, - "", 1, SEARCH_MSG, i, NULL) != FAIL) { + "", 0, 1, SEARCH_MSG, i, NULL) != FAIL) { lnum = pos.lnum; } else { cmd = NULL; @@ -3596,7 +3628,7 @@ static linenr_T get_address(exarg_T *eap, char **ptr, cmd_addr_T addr_type, bool // closed fold after the first address. if (addr_type == ADDR_LINES && (i == '-' || i == '+') && address_count >= 2) { - hasFolding(lnum, NULL, &lnum); + hasFolding(curwin, lnum, NULL, &lnum); } if (i == '-') { lnum -= n; @@ -4050,7 +4082,7 @@ void separate_nextcmd(exarg_T *eap) break; } } else if ( - // Check for '"': start of comment or '|': next command */ + // Check for '"': start of comment or '|': next command // :@" does not start a comment! // :redir @" doesn't either. (*p == '"' @@ -4368,12 +4400,15 @@ static int get_tabpage_arg(exarg_T *eap) tab_number = 0; } else { tab_number = (int)eap->line2; - char *cmdp = eap->cmd; - while (--cmdp > *eap->cmdlinep && (*cmdp == ' ' || ascii_isdigit(*cmdp))) {} - if (!unaccept_arg0 && *cmdp == '-') { - tab_number--; - if (tab_number < unaccept_arg0) { - eap->errmsg = _(e_invrange); + if (!unaccept_arg0) { + char *cmdp = eap->cmd; + while (--cmdp > *eap->cmdlinep + && (ascii_iswhite(*cmdp) || ascii_isdigit(*cmdp))) {} + if (*cmdp == '-') { + tab_number--; + if (tab_number < unaccept_arg0) { + eap->errmsg = _(e_invrange); + } } } } @@ -5334,6 +5369,10 @@ static void ex_resize(exarg_T *eap) /// ":find [+command] <file>" command. static void ex_find(exarg_T *eap) { + if (!check_can_set_curbuf_forceit(eap->forceit)) { + return; + } + char *file_to_find = NULL; char *search_ctx = NULL; char *fname = find_file_in_path(eap->arg, strlen(eap->arg), @@ -5364,6 +5403,16 @@ static void ex_find(exarg_T *eap) /// ":edit", ":badd", ":balt", ":visual". static void ex_edit(exarg_T *eap) { + char *ffname = eap->cmdidx == CMD_enew ? NULL : eap->arg; + + // Exclude commands which keep the window's current buffer + if (eap->cmdidx != CMD_badd + && eap->cmdidx != CMD_balt + // All other commands must obey 'winfixbuf' / ! rules + && (is_other_file(0, ffname) && !check_can_set_curbuf_forceit(eap->forceit))) { + return; + } + do_exedit(eap, NULL); } @@ -5516,8 +5565,6 @@ static void ex_swapname(exarg_T *eap) /// (1998-11-02 16:21:01 R. Edward Ralston <eralston@computer.org>) static void ex_syncbind(exarg_T *eap) { - win_T *save_curwin = curwin; - buf_T *save_curbuf = curbuf; linenr_T topline; int y; linenr_T old_linenr = curwin->w_cursor.lnum; @@ -5544,23 +5591,19 @@ static void ex_syncbind(exarg_T *eap) // Set all scrollbind windows to the same topline. FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { - curwin = wp; - if (curwin->w_p_scb) { - curbuf = curwin->w_buffer; - y = topline - curwin->w_topline; + if (wp->w_p_scb) { + y = topline - wp->w_topline; if (y > 0) { - scrollup(y, true); + scrollup(wp, y, true); } else { - scrolldown(-y, true); + scrolldown(wp, -y, true); } - curwin->w_scbind_pos = topline; - redraw_later(curwin, UPD_VALID); - cursor_correct(); - curwin->w_redr_status = true; + wp->w_scbind_pos = topline; + redraw_later(wp, UPD_VALID); + cursor_correct(wp); + wp->w_redr_status = true; } } - curwin = save_curwin; - curbuf = save_curbuf; if (curwin->w_p_scb) { did_syncbind = true; checkpcmark(); @@ -5842,8 +5885,8 @@ static void ex_equal(exarg_T *eap) static void ex_sleep(exarg_T *eap) { - if (cursor_valid()) { - setcursor_mayforce(true); + if (cursor_valid(curwin)) { + setcursor_mayforce(curwin, true); } int64_t len = eap->line2; @@ -5978,7 +6021,7 @@ static void ex_put(exarg_T *eap) eap->forceit = true; } curwin->w_cursor.lnum = eap->line2; - check_cursor_col(); + check_cursor_col(curwin); do_put(eap->regname, NULL, eap->forceit ? BACKWARD : FORWARD, 1, PUT_LINE|PUT_CURSLINE); } @@ -6072,7 +6115,7 @@ static void ex_at(exarg_T *eap) int prev_len = typebuf.tb_len; curwin->w_cursor.lnum = eap->line2; - check_cursor_col(); + check_cursor_col(curwin); // Get the register name. No name means use the previous one. int c = (uint8_t)(*eap->arg); @@ -6294,7 +6337,7 @@ static void ex_redraw(exarg_T *eap) RedrawingDisabled = 0; p_lz = false; - validate_cursor(); + validate_cursor(curwin); update_topline(curwin); if (eap->forceit) { redraw_all_later(UPD_NOT_VALID); @@ -6447,10 +6490,10 @@ static void ex_mark(exarg_T *eap) /// Update w_topline, w_leftcol and the cursor position. void update_topline_cursor(void) { - check_cursor(); // put cursor on valid line + check_cursor(curwin); // put cursor on valid line update_topline(curwin); if (!curwin->w_p_wrap) { - validate_cursor(); + validate_cursor(curwin); } update_curswant(); } @@ -6670,7 +6713,7 @@ static void ex_checkpath(exarg_T *eap) { find_pattern_in_path(NULL, 0, 0, false, false, CHECK_PATH, 1, eap->forceit ? ACTION_SHOW_ALL : ACTION_SHOW, - 1, (linenr_T)MAXLNUM); + 1, (linenr_T)MAXLNUM, eap->forceit); } /// ":psearch" @@ -6729,7 +6772,7 @@ static void ex_findpat(exarg_T *eap) if (!eap->skip) { find_pattern_in_path(eap->arg, 0, strlen(eap->arg), whole, !eap->forceit, *eap->cmd == 'd' ? FIND_DEFINE : FIND_ANY, - n, action, eap->line1, eap->line2); + n, action, eap->line1, eap->line2, eap->forceit); } } @@ -6754,7 +6797,7 @@ static void ex_pedit(exarg_T *eap) if (curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_VALID); win_enter(curwin_save, true); } @@ -7339,7 +7382,7 @@ void filetype_maybe_enable(void) /// ":setfiletype [FALLBACK] {name}" static void ex_setfiletype(exarg_T *eap) { - if (did_filetype) { + if (curbuf->b_did_filetype) { return; } @@ -7350,7 +7393,7 @@ static void ex_setfiletype(exarg_T *eap) set_option_value_give_err(kOptFiletype, CSTR_AS_OPTVAL(arg), OPT_LOCAL); if (arg != eap->arg) { - did_filetype = false; + curbuf->b_did_filetype = false; } } @@ -7396,7 +7439,7 @@ static void ex_folddo(exarg_T *eap) { // First set the marks for all lines closed/open. for (linenr_T lnum = eap->line1; lnum <= eap->line2; lnum++) { - if (hasFolding(lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed)) { + if (hasFolding(curwin, lnum, NULL, NULL) == (eap->cmdidx == CMD_folddoclosed)) { ml_setmarked(lnum); } } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index 44a78711d2..f18dc0f747 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -470,7 +470,7 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state .sa_tm = &tm, }; found = do_search(NULL, firstc == ':' ? '/' : firstc, search_delim, - ccline.cmdbuff + skiplen, count, + ccline.cmdbuff + skiplen, (size_t)patlen, count, search_flags, &sia); ccline.cmdbuff[skiplen + patlen] = next_char; emsg_off--; @@ -510,7 +510,7 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state s->match_start = curwin->w_cursor; set_search_match(&curwin->w_cursor); - validate_cursor(); + validate_cursor(curwin); end_pos = curwin->w_cursor; s->match_end = end_pos; curwin->w_cursor = save_pos; @@ -530,7 +530,7 @@ static void may_do_incsearch_highlighting(int firstc, int count, incsearch_state ccline.cmdbuff[skiplen + patlen] = next_char; } - validate_cursor(); + validate_cursor(curwin); // May redraw the status line to show the cursor position. if (p_ru && (curwin->w_status_height > 0 || global_stl_height() > 0)) { @@ -626,7 +626,7 @@ static void finish_incsearch_highlighting(bool gotesc, incsearch_state_T *s, magic_overruled = s->magic_overruled_save; - validate_cursor(); // needed for TAB + validate_cursor(curwin); // needed for TAB status_redraw_all(); redraw_all_later(UPD_SOME_VALID); if (call_update_screen) { @@ -767,7 +767,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear } setmouse(); - ui_cursor_shape(); // may show different cursor shape + setcursor(); TryState tstate; Error err = ERROR_INIT; @@ -884,11 +884,12 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear && ccline.cmdlen && s->firstc != NUL && (s->some_key_typed || s->histype == HIST_SEARCH)) { - add_to_history(s->histype, ccline.cmdbuff, true, + size_t cmdbufflen = strlen(ccline.cmdbuff); + add_to_history(s->histype, ccline.cmdbuff, cmdbufflen, true, s->histype == HIST_SEARCH ? s->firstc : NUL); if (s->firstc == ':') { xfree(new_last_cmdline); - new_last_cmdline = xstrdup(ccline.cmdbuff); + new_last_cmdline = xstrnsave(ccline.cmdbuff, cmdbufflen); } } @@ -919,7 +920,7 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear need_wait_return = false; } - set_string_option_direct(kOptInccommand, s->save_p_icm, 0, SID_NONE); + set_option_direct(kOptInccommand, CSTR_AS_OPTVAL(s->save_p_icm), 0, SID_NONE); State = s->save_State; if (cmdpreview != save_cmdpreview) { cmdpreview = save_cmdpreview; // restore preview state @@ -927,7 +928,6 @@ static uint8_t *command_line_enter(int firstc, int count, int indent, bool clear } may_trigger_modechanged(); setmouse(); - ui_cursor_shape(); // may show different cursor shape sb_text_end_cmdline(); theend: @@ -1168,6 +1168,7 @@ static int command_line_execute(VimState *state, int key) return -1; // get another key } + disptick_T display_tick_saved = display_tick; CommandLineState *s = (CommandLineState *)state; s->c = key; @@ -1179,6 +1180,10 @@ static int command_line_execute(VimState *state, int key) } else { map_execute_lua(false); } + // Re-apply 'incsearch' highlighting in case it was cleared. + if (display_tick > display_tick_saved && s->is_state.did_incsearch) { + may_do_incsearch_highlighting(s->firstc, s->count, &s->is_state); + } // nvim_select_popupmenu_item() can be called from the handling of // K_EVENT, K_COMMAND, or K_LUA. @@ -1447,7 +1452,7 @@ static int may_do_command_line_next_incsearch(int firstc, int count, incsearch_s pat[patlen] = NUL; int found = searchit(curwin, curbuf, &t, NULL, next_match ? FORWARD : BACKWARD, - pat, count, search_flags, + pat, (size_t)patlen, count, search_flags, RE_SEARCH, NULL); emsg_off--; pat[patlen] = save; @@ -1483,7 +1488,7 @@ static int may_do_command_line_next_incsearch(int firstc, int count, incsearch_s curwin->w_cursor = s->match_start; changed_cline_bef_curs(curwin); update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); highlight_match = true; save_viewstate(curwin, &s->old_viewstate); redraw_later(curwin, UPD_NOT_VALID); @@ -1964,7 +1969,7 @@ static int command_line_handle_key(CommandLineState *s) return command_line_not_changed(s); // Ignore mouse case K_MIDDLEMOUSE: - cmdline_paste(eval_has_provider("clipboard") ? '*' : 0, true, true); + cmdline_paste(eval_has_provider("clipboard", false) ? '*' : 0, true, true); redrawcmd(); return command_line_changed(s); @@ -2550,7 +2555,7 @@ static bool cmdpreview_may_show(CommandLineState *s) // Open preview buffer if inccommand=split. if (icm_split && (cmdpreview_buf = cmdpreview_open_buf()) == NULL) { // Failed to create preview buffer, so disable preview. - set_string_option_direct(kOptInccommand, "nosplit", 0, SID_NONE); + set_option_direct(kOptInccommand, STATIC_CSTR_AS_OPTVAL("nosplit"), 0, SID_NONE); icm_split = false; } // Setup preview namespace if it's not already set. @@ -3445,9 +3450,11 @@ void cmdline_screen_cleared(void) /// called by ui_flush, do what redraws necessary to keep cmdline updated. void cmdline_ui_flush(void) { - if (!ui_has(kUICmdline)) { + static bool flushing = false; + if (!ui_has(kUICmdline) || flushing) { return; } + flushing = true; int level = ccline.level; CmdlineInfo *line = &ccline; while (level > 0 && line) { @@ -3462,6 +3469,7 @@ void cmdline_ui_flush(void) } line = line->prev_ccline; } + flushing = false; } // Put a character on the command line. Shifts the following text to the @@ -3859,7 +3867,6 @@ void cursorcmd(void) if (ccline.redraw_state < kCmdRedrawPos) { ccline.redraw_state = kCmdRedrawPos; } - setcursor(); return; } @@ -4553,6 +4560,7 @@ static int open_cmdwin(void) State = save_State; may_trigger_modechanged(); setmouse(); + setcursor(); return cmdwin_result; } @@ -4583,7 +4591,7 @@ char *script_get(exarg_T *const eap, size_t *const lenp) { char *cmd = eap->arg; - if (cmd[0] != '<' || cmd[1] != '<' || eap->getline == NULL) { + if (cmd[0] != '<' || cmd[1] != '<' || eap->ea_getline == NULL) { *lenp = strlen(eap->arg); return eap->skip ? NULL : xmemdupz(eap->arg, *lenp); } @@ -4623,6 +4631,6 @@ static void set_search_match(pos_T *t) t->col = search_match_endcol; if (t->lnum > curbuf->b_ml.ml_line_count) { t->lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } } diff --git a/src/nvim/ex_session.c b/src/nvim/ex_session.c index fb37bc86f1..0e5d2fe4f5 100644 --- a/src/nvim/ex_session.c +++ b/src/nvim/ex_session.c @@ -12,6 +12,7 @@ #include "nvim/arglist.h" #include "nvim/arglist_defs.h" #include "nvim/ascii_defs.h" +#include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" #include "nvim/eval.h" @@ -1092,6 +1093,8 @@ void ex_mkrc(exarg_T *eap) } xfree(viewFile); + + apply_autocmds(EVENT_SESSIONWRITEPOST, NULL, NULL, false, curbuf); } /// @return the name of the view file for the current buffer. @@ -1135,7 +1138,7 @@ static char *get_view_file(char c) } *s++ = '='; *s++ = c; - xstrlcpy(s, ".vim", 5); + xmemcpyz(s, S_LEN(".vim")); xfree(sname); return retval; diff --git a/src/nvim/extmark.c b/src/nvim/extmark.c index c4a34f8019..3236590010 100644 --- a/src/nvim/extmark.c +++ b/src/nvim/extmark.c @@ -206,7 +206,9 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r } } - bool marks_cleared = false; + bool marks_cleared_any = false; + bool marks_cleared_all = l_row == 0 && l_col == 0; + MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, l_row, l_col, itr); while (true) { @@ -214,16 +216,29 @@ bool extmark_clear(buf_T *buf, uint32_t ns_id, int l_row, colnr_T l_col, int u_r if (mark.pos.row < 0 || mark.pos.row > u_row || (mark.pos.row == u_row && mark.pos.col > u_col)) { + if (mark.pos.row >= 0) { + marks_cleared_all = false; + } break; } if (mark.ns == ns_id || all_ns) { - marks_cleared = true; + marks_cleared_any = true; extmark_del(buf, itr, mark, true); } else { marktree_itr_next(buf->b_marktree, itr); } } - return marks_cleared; + + if (marks_cleared_all) { + if (all_ns) { + map_destroy(uint32_t, buf->b_extmark_ns); + *buf->b_extmark_ns = (Map(uint32_t, uint32_t)) MAP_INIT; + } else { + map_del(uint32_t, uint32_t)(buf->b_extmark_ns, ns_id, NULL); + } + } + + return marks_cleared_any; } /// @return the position of marks between a range, @@ -315,10 +330,6 @@ MTPair extmark_from_id(buf_T *buf, uint32_t ns_id, uint32_t id) /// free extmarks from the buffer void extmark_free_all(buf_T *buf) { - if (!map_size(buf->b_extmark_ns)) { - return; - } - MarkTreeIter itr[1] = { 0 }; marktree_itr_get(buf->b_marktree, 0, 0, itr); while (true) { diff --git a/src/nvim/file_search.c b/src/nvim/file_search.c index ed4848b402..a8b0dbddee 100644 --- a/src/nvim/file_search.c +++ b/src/nvim/file_search.c @@ -291,7 +291,7 @@ void *vim_findfile_init(char *path, char *filename, char *stopdirs, int level, i if (!vim_isAbsName(rel_fname) && len + 1 < MAXPATHL) { // Make the start dir an absolute path name. - xstrlcpy(ff_expand_buffer, rel_fname, len + 1); + xmemcpyz(ff_expand_buffer, rel_fname, len); search_ctx->ffsc_start_dir = FullName_save(ff_expand_buffer, false); } else { search_ctx->ffsc_start_dir = xmemdupz(rel_fname, len); diff --git a/src/nvim/fileio.c b/src/nvim/fileio.c index 3b715e2c0b..df9c4928c9 100644 --- a/src/nvim/fileio.c +++ b/src/nvim/fileio.c @@ -234,7 +234,7 @@ int readfile(char *fname, char *sfname, linenr_T from, linenr_T lines_to_skip, int using_b_fname; static char *msg_is_a_directory = N_("is a directory"); - au_did_filetype = false; // reset before triggering any autocommands + curbuf->b_au_did_filetype = false; // reset before triggering any autocommands curbuf->b_no_eol_lnum = 0; // in case it was set by the previous read @@ -957,7 +957,7 @@ retry: int tlen = 0; while (true) { p = (uint8_t *)ml_get(read_buf_lnum) + read_buf_col; - int n = (int)strlen((char *)p); + int n = ml_get_len(read_buf_lnum) - read_buf_col; if (tlen + n + 1 > size) { // Filled up to "size", append partial line. // Change NL to NUL to reverse the effect done @@ -1620,7 +1620,7 @@ failed: save_file_ff(curbuf); // If editing a new file: set 'fenc' for the current buffer. // Also for ":read ++edit file". - set_string_option_direct(kOptFileencoding, fenc, OPT_LOCAL, 0); + set_option_direct(kOptFileencoding, CSTR_AS_OPTVAL(fenc), OPT_LOCAL, 0); } if (fenc_alloced) { xfree(fenc); @@ -1854,7 +1854,7 @@ failed: } else if (newfile || (read_buffer && sfname != NULL)) { apply_autocmds_exarg(EVENT_BUFREADPOST, NULL, sfname, false, curbuf, eap); - if (!au_did_filetype && *curbuf->b_p_ft != NUL) { + if (!curbuf->b_au_did_filetype && *curbuf->b_p_ft != NUL) { // EVENT_FILETYPE was not triggered but the buffer already has a // filetype. Trigger EVENT_FILETYPE using the existing filetype. apply_autocmds(EVENT_FILETYPE, curbuf->b_p_ft, curbuf->b_fname, true, curbuf); @@ -1968,7 +1968,7 @@ void set_forced_fenc(exarg_T *eap) } char *fenc = enc_canonize(eap->cmd + eap->force_enc); - set_string_option_direct(kOptFileencoding, fenc, OPT_LOCAL, 0); + set_option_direct(kOptFileencoding, CSTR_AS_OPTVAL(fenc), OPT_LOCAL, 0); xfree(fenc); } @@ -3151,7 +3151,7 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) if (saved == OK) { curbuf->b_flags |= BF_CHECK_RO; // check for RO again - keep_filetype = true; // don't detect 'filetype' + curbuf->b_keep_filetype = true; // don't detect 'filetype' if (readfile(buf->b_ffname, buf->b_fname, 0, 0, (linenr_T)MAXLNUM, &ea, flags, shortmess(SHM_FILEINFO)) != OK) { if (!aborting()) { @@ -3197,9 +3197,9 @@ void buf_reload(buf_T *buf, int orig_mode, bool reload_options) curwin->w_topline = old_topline; } curwin->w_cursor = old_cursor; - check_cursor(); + check_cursor(curwin); update_topline(curwin); - keep_filetype = false; + curbuf->b_keep_filetype = false; // Update folds unless they are defined manually. FOR_ALL_TAB_WINDOWS(tp, wp) { diff --git a/src/nvim/fold.c b/src/nvim/fold.c index c571aaf0a4..59a4dc6aad 100644 --- a/src/nvim/fold.c +++ b/src/nvim/fold.c @@ -143,7 +143,7 @@ void copyFoldingState(win_T *wp_from, win_T *wp_to) } // hasAnyFolding() {{{2 -/// @return true if there may be folded lines in the current window. +/// @return true if there may be folded lines in window "win". int hasAnyFolding(win_T *win) { // very simple now, but can become more complex later @@ -155,10 +155,10 @@ int hasAnyFolding(win_T *win) /// When returning true, *firstp and *lastp are set to the first and last /// lnum of the sequence of folded lines (skipped when NULL). /// -/// @return true if line "lnum" in the current window is part of a closed fold. -bool hasFolding(linenr_T lnum, linenr_T *firstp, linenr_T *lastp) +/// @return true if line "lnum" in window "win" is part of a closed fold. +bool hasFolding(win_T *win, linenr_T lnum, linenr_T *firstp, linenr_T *lastp) { - return hasFoldingWin(curwin, lnum, firstp, lastp, true, NULL); + return hasFoldingWin(win, lnum, firstp, lastp, true, NULL); } // hasFoldingWin() {{{2 @@ -398,13 +398,13 @@ void opFoldRange(pos_T firstpos, pos_T lastpos, int opening, int recurse, bool h // Opening one level only: next fold to open is after the one going to // be opened. if (opening && !recurse) { - hasFolding(lnum, NULL, &lnum_next); + hasFolding(curwin, lnum, NULL, &lnum_next); } setManualFold(temp, opening, recurse, &done); // Closing one level only: next line to close a fold is after just // closed fold. if (!opening && !recurse) { - hasFolding(lnum, NULL, &lnum_next); + hasFolding(curwin, lnum, NULL, &lnum_next); } } if (done == DONE_NOTHING) { @@ -477,7 +477,7 @@ static void newFoldLevelWin(win_T *wp) } wp->w_fold_manual = false; } - changed_window_setting_win(wp); + changed_window_setting(wp); } // foldCheckClose() {{{2 @@ -492,7 +492,7 @@ void foldCheckClose(void) checkupdate(curwin); if (checkCloseRec(&curwin->w_folds, curwin->w_cursor.lnum, (int)curwin->w_p_fdl)) { - changed_window_setting(); + changed_window_setting(curwin); } } @@ -518,7 +518,7 @@ static bool checkCloseRec(garray_T *gap, linenr_T lnum, int level) return retval; } -// foldCreateAllowed() {{{2 +// foldManualAllowed() {{{2 /// @return true if it's allowed to manually create or delete a fold or, /// give an error message and return false if not. int foldManualAllowed(bool create) @@ -661,7 +661,7 @@ void foldCreate(win_T *wp, pos_T start, pos_T end) fp->fd_small = kNone; // redraw - changed_window_setting_win(wp); + changed_window_setting(wp); } } @@ -735,7 +735,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const did_one = true; // redraw window - changed_window_setting_win(wp); + changed_window_setting(wp); } } if (!did_one) { @@ -746,7 +746,7 @@ void deleteFold(win_T *const wp, const linenr_T start, const linenr_T end, const } } else { // Deleting markers may make cursor column invalid - check_cursor_col_win(wp); + check_cursor_col(wp); } if (last_lnum > 0) { @@ -1009,16 +1009,15 @@ void foldAdjustVisual(void) start = &curwin->w_cursor; end = &VIsual; } - if (hasFolding(start->lnum, &start->lnum, NULL)) { + if (hasFolding(curwin, start->lnum, &start->lnum, NULL)) { start->col = 0; } - if (!hasFolding(end->lnum, NULL, &end->lnum)) { + if (!hasFolding(curwin, end->lnum, NULL, &end->lnum)) { return; } - char *ptr = ml_get(end->lnum); - end->col = (colnr_T)strlen(ptr); + end->col = ml_get_len(end->lnum); if (end->col > 0 && *p_sel == 'o') { end->col--; } @@ -1026,11 +1025,11 @@ void foldAdjustVisual(void) mb_adjust_cursor(); } -// cursor_foldstart() {{{2 +// foldAdjustCursor() {{{2 /// Move the cursor to the first line of a closed fold. -void foldAdjustCursor(void) +void foldAdjustCursor(win_T *wp) { - hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); + hasFolding(wp, wp->w_cursor.lnum, &wp->w_cursor.lnum, NULL); } // Internal functions for "fold_T" {{{1 @@ -1269,7 +1268,7 @@ static linenr_T setManualFoldWin(win_T *wp, linenr_T lnum, bool opening, bool re } wp->w_fold_manual = true; if (done & DONE_ACTION) { - changed_window_setting_win(wp); + changed_window_setting(wp); } done |= DONE_FOLD; } else if (donep == NULL && wp == curwin) { @@ -1605,7 +1604,7 @@ static void foldAddMarker(buf_T *buf, pos_T pos, const char *marker, size_t mark // Allocate a new line: old-line + 'cms'-start + marker + 'cms'-end char *line = ml_get_buf(buf, lnum); - size_t line_len = strlen(line); + size_t line_len = (size_t)ml_get_buf_len(buf, lnum); size_t added = 0; if (u_save(lnum - 1, lnum + 1) != OK) { @@ -1618,7 +1617,7 @@ static void foldAddMarker(buf_T *buf, pos_T pos, const char *marker, size_t mark STRCPY(newline, line); // Append the marker to the end of the line if (p == NULL || line_is_comment) { - xstrlcpy(newline + line_len, marker, markerlen + 1); + xmemcpyz(newline + line_len, marker, markerlen); added = markerlen; } else { STRCPY(newline + line_len, cms); @@ -1686,7 +1685,7 @@ static void foldDelMarker(buf_T *buf, linenr_T lnum, char *marker, size_t marker } if (u_save(lnum - 1, lnum + 1) == OK) { // Make new line: text-before-marker + text-after-marker - char *newline = xmalloc(strlen(line) - len + 1); + char *newline = xmalloc((size_t)ml_get_buf_len(buf, lnum) - len + 1); assert(p >= line); memcpy(newline, line, (size_t)(p - line)); STRCPY(newline + (p - line), p + len); @@ -2117,7 +2116,7 @@ static void foldUpdateIEMS(win_T *const wp, linenr_T top, linenr_T bot) // If some fold changed, need to redraw and position cursor. if (fold_changed && wp->w_p_fen) { - changed_window_setting_win(wp); + changed_window_setting(wp); } // If we updated folds past "bot", need to redraw more lines. Don't do diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 04b4363e42..62c99ce082 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -259,8 +259,12 @@ put('version') fixdict(1 + #version) for _, item in ipairs(version) do -- NB: all items are mandatory. But any error will be less confusing - -- with placholder vim.NIL (than invalid mpack data) - put(item[1], item[2] or vim.NIL) + -- with placeholder vim.NIL (than invalid mpack data) + local val = item[2] + if val == nil then + val = vim.NIL + end + put(item[1], val) end put('build', version_build) @@ -716,23 +720,6 @@ end -- start building lua output output = assert(io.open(lua_c_bindings_outputf, 'wb')) -output:write([[ -#include <lua.h> -#include <lualib.h> -#include <lauxlib.h> - -#include "nvim/ex_docmd.h" -#include "nvim/ex_getln.h" -#include "nvim/func_attr.h" -#include "nvim/globals.h" -#include "nvim/api/private/defs.h" -#include "nvim/api/private/helpers.h" -#include "nvim/api/private/dispatch.h" -#include "nvim/lua/converter.h" -#include "nvim/lua/executor.h" -#include "nvim/memory.h" - -]]) include_headers(output, headers) output:write('\n') @@ -913,7 +900,7 @@ exit_0: write_shifted_output(string.format( [[ if (lua_gettop(lstate) == 0) { - nlua_push_%s(lstate, %sret, true); + nlua_push_%s(lstate, %sret, kNluaPushSpecial | kNluaPushFreeRefs); } ]], return_type, @@ -927,10 +914,10 @@ exit_0: else local special = (fn.since ~= nil and fn.since < 11) write_shifted_output( - ' nlua_push_%s(lstate, %sret, %s);\n', + ' nlua_push_%s(lstate, %sret, %s | kNluaPushFreeRefs);\n', return_type, ret_mode, - tostring(special) + special and 'kNluaPushSpecial' or '0' ) end @@ -975,8 +962,6 @@ end output:write(string.format( [[ void nlua_add_api_functions(lua_State *lstate) - REAL_FATTR_NONNULL_ALL; -void nlua_add_api_functions(lua_State *lstate) { lua_createtable(lstate, 0, %u); ]], diff --git a/src/nvim/generators/gen_api_ui_events.lua b/src/nvim/generators/gen_api_ui_events.lua index 0808f71daa..516b5ad5ae 100644 --- a/src/nvim/generators/gen_api_ui_events.lua +++ b/src/nvim/generators/gen_api_ui_events.lua @@ -31,6 +31,10 @@ local function write_signature(output, ev, prefix, notype) end local function write_arglist(output, ev) + if #ev.parameters == 0 then + return + end + output:write(' MAXSIZE_TEMP_ARRAY(args, ' .. #ev.parameters .. ');\n') for j = 1, #ev.parameters do local param = ev.parameters[j] local kind = string.upper(param[1]) @@ -107,14 +111,14 @@ for i = 1, #events do end ev.since = tonumber(ev.since) + local args = #ev.parameters > 0 and 'args' or 'noargs' if not ev.remote_only then if not ev.remote_impl and not ev.noexport then remote_output:write('void remote_ui_' .. ev.name) write_signature(remote_output, ev, 'RemoteUI *ui') remote_output:write('\n{\n') - remote_output:write(' Array args = ui->call_buf;\n') write_arglist(remote_output, ev) - remote_output:write(' push_call(ui, "' .. ev.name .. '", args);\n') + remote_output:write(' push_call(ui, "' .. ev.name .. '", ' .. args .. ');\n') remote_output:write('}\n\n') end end @@ -124,9 +128,8 @@ for i = 1, #events do write_signature(call_output, ev, '') call_output:write('\n{\n') if ev.remote_only then - call_output:write(' Array args = call_buf;\n') write_arglist(call_output, ev) - call_output:write(' ui_call_event("' .. ev.name .. '", args);\n') + call_output:write(' ui_call_event("' .. ev.name .. '", ' .. args .. ');\n') elseif ev.compositor_impl then call_output:write(' ui_comp_' .. ev.name) write_signature(call_output, ev, '', true) diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 749844e658..0718d965c6 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -164,14 +164,24 @@ local function dump_option(i, o) if o.enable_if then w(get_cond(o.enable_if)) end + + -- An option cannot be both hidden and immutable. + assert(not o.hidden or not o.immutable) + + local has_var = true if o.varname then w(' .var=&' .. o.varname) - -- Immutable options can directly point to the default value. - elseif o.immutable then + elseif o.hidden or o.immutable then + -- Hidden and immutable options can directly point to the default value. w((' .var=&options[%u].def_val'):format(i - 1)) elseif #o.scope == 1 and o.scope[1] == 'window' then w(' .var=VAR_WIN') + else + has_var = false end + -- `enable_if = false` should be present iff there is no variable. + assert((o.enable_if == false) == not has_var) + w(' .hidden=' .. (o.hidden and 'true' or 'false')) w(' .immutable=' .. (o.immutable and 'true' or 'false')) if #o.scope == 1 and o.scope[1] == 'global' then w(' .indir=PV_NONE') diff --git a/src/nvim/generators/nvim_version.lua.in b/src/nvim/generators/nvim_version.lua.in index d0dbf77922..c29141fc68 100644 --- a/src/nvim/generators/nvim_version.lua.in +++ b/src/nvim/generators/nvim_version.lua.in @@ -2,7 +2,7 @@ return { {"major", ${NVIM_VERSION_MAJOR}}, {"minor", ${NVIM_VERSION_MINOR}}, {"patch", ${NVIM_VERSION_PATCH}}, - {"prerelease", "$NVIM_VERSION_PRERELEASE" ~= ""}, + {"prerelease", "${NVIM_VERSION_PRERELEASE}" ~= ""}, {"api_level", ${NVIM_API_LEVEL}}, {"api_compatible", ${NVIM_API_LEVEL_COMPAT}}, {"api_prerelease", ${NVIM_API_PRERELEASE}}, diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 64c9c5a8c3..9b19644b7e 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -64,6 +64,15 @@ #include "nvim/undo.h" #include "nvim/vim_defs.h" +/// State for adding bytes to a recording or 'showcmd'. +typedef struct { + uint8_t buf[MB_MAXBYTES * 3 + 4]; + int prev_c; + size_t buflen; + unsigned pending_special; + unsigned pending_mbyte; +} gotchars_state_T; + /// Index in scriptin static int curscript = -1; /// Streams to read script from @@ -94,6 +103,12 @@ static buffheader_T readbuf1 = { { NULL, { NUL } }, NULL, 0, 0 }; /// Second read ahead buffer. Used for redo. static buffheader_T readbuf2 = { { NULL, { NUL } }, NULL, 0, 0 }; +/// Buffer used to store typed characters for vim.on_key(). +static kvec_withinit_t(char, MAXMAPLEN) on_key_buf = KVI_INITIAL_VALUE(on_key_buf); + +/// Number of following bytes that should not be stored for vim.on_key(). +static size_t no_on_key_len = 0; + static int typeahead_char = 0; ///< typeahead char that's not flushed /// When block_redo is true the redo buffer will not be changed. @@ -255,7 +270,7 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle size_t len; if (buf->bh_space >= (size_t)slen) { len = strlen(buf->bh_curr->b_str); - xstrlcpy(buf->bh_curr->b_str + len, s, (size_t)slen + 1); + xmemcpyz(buf->bh_curr->b_str + len, s, (size_t)slen); buf->bh_space -= (size_t)slen; } else { if (slen < MINIMAL_SIZE) { @@ -265,7 +280,7 @@ static void add_buff(buffheader_T *const buf, const char *const s, ptrdiff_t sle } 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); + xmemcpyz(p->b_str, s, (size_t)slen); p->b_next = buf->bh_curr->b_next; buf->bh_curr->b_next = p; @@ -994,14 +1009,19 @@ int ins_typebuf(char *str, int noremap, int offset, bool nottyped, bool silent) /// Uses cmd_silent, KeyTyped and KeyNoremap to restore the flags belonging to /// the char. /// +/// @param no_on_key don't store these bytes for vim.on_key() +/// /// @return the length of what was inserted -int ins_char_typebuf(int c, int modifiers) +int ins_char_typebuf(int c, int modifiers, bool no_on_key) { char buf[MB_MAXBYTES * 3 + 4]; unsigned len = special_to_buf(c, modifiers, true, buf); assert(len < sizeof(buf)); buf[len] = NUL; ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent); + if (KeyTyped && no_on_key) { + no_on_key_len += len; + } return (int)len; } @@ -1101,40 +1121,90 @@ void del_typebuf(int len, int offset) } } +/// Add a single byte to a recording or 'showcmd'. +/// Return true if a full key has been received, false otherwise. +static bool gotchars_add_byte(gotchars_state_T *state, uint8_t byte) + FUNC_ATTR_NONNULL_ALL +{ + int c = state->buf[state->buflen++] = byte; + bool retval = false; + const bool in_special = state->pending_special > 0; + const bool in_mbyte = state->pending_mbyte > 0; + + if (in_special) { + state->pending_special--; + } else if (c == K_SPECIAL) { + // When receiving a special key sequence, store it until we have all + // the bytes and we can decide what to do with it. + state->pending_special = 2; + } + + if (state->pending_special > 0) { + goto ret_false; + } + + if (in_mbyte) { + state->pending_mbyte--; + } else { + if (in_special) { + if (state->prev_c == KS_MODIFIER) { + // When receiving a modifier, wait for the modified key. + goto ret_false; + } + c = TO_SPECIAL(state->prev_c, c); + } + // When receiving a multibyte character, store it until we have all + // the bytes, so that it won't be split between two buffer blocks, + // and delete_buff_tail() will work properly. + state->pending_mbyte = MB_BYTE2LEN_CHECK(c) - 1; + } + + if (state->pending_mbyte > 0) { + goto ret_false; + } + + retval = true; +ret_false: + state->prev_c = c; + return retval; +} + /// Write typed characters to script file. -/// If recording is on put the character in the recordbuffer. +/// If recording is on put the character in the record buffer. static void gotchars(const uint8_t *chars, size_t len) FUNC_ATTR_NONNULL_ALL { const uint8_t *s = chars; - static uint8_t buf[4] = { 0 }; - static size_t buflen = 0; size_t todo = len; + static gotchars_state_T state; - while (todo--) { - buf[buflen++] = *s++; - - // When receiving a special key sequence, store it until we have all - // the bytes and we can decide what to do with it. - if (buflen == 1 && buf[0] == K_SPECIAL) { - continue; - } - if (buflen == 2) { + while (todo-- > 0) { + if (!gotchars_add_byte(&state, *s++)) { continue; } // Handle one byte at a time; no translation to be done. - for (size_t i = 0; i < buflen; i++) { - updatescript(buf[i]); + for (size_t i = 0; i < state.buflen; i++) { + updatescript(state.buf[i]); } + state.buf[state.buflen] = NUL; + if (reg_recording != 0) { - buf[buflen] = NUL; - add_buff(&recordbuff, (char *)buf, (ptrdiff_t)buflen); + add_buff(&recordbuff, (char *)state.buf, (ptrdiff_t)state.buflen); // remember how many chars were last recorded - last_recorded_len += buflen; + last_recorded_len += state.buflen; + } + + if (state.buflen > no_on_key_len) { + vim_unescape_ks((char *)state.buf + no_on_key_len); + kvi_concat(on_key_buf, (char *)state.buf + no_on_key_len); + no_on_key_len = 0; + } else { + no_on_key_len -= state.buflen; } - buflen = 0; + + state.buflen = 0; } may_sync_undo(); @@ -1151,6 +1221,7 @@ static void gotchars(const uint8_t *chars, size_t len) void gotchars_ignore(void) { uint8_t nop_buf[3] = { K_SPECIAL, KS_EXTRA, KE_IGNORE }; + no_on_key_len += 3; gotchars(nop_buf, 3); } @@ -1440,6 +1511,61 @@ int merge_modifiers(int c_arg, int *modifiers) return c; } +/// Add a single byte to 'showcmd' for a partially matched mapping. +/// Call add_to_showcmd() if a full key has been received. +static void add_byte_to_showcmd(uint8_t byte) +{ + static gotchars_state_T state; + + if (!p_sc || msg_silent != 0) { + return; + } + + if (!gotchars_add_byte(&state, byte)) { + return; + } + + state.buf[state.buflen] = NUL; + state.buflen = 0; + + int modifiers = 0; + int c = NUL; + + const uint8_t *ptr = state.buf; + if (ptr[0] == K_SPECIAL && ptr[1] == KS_MODIFIER && ptr[2] != NUL) { + modifiers = ptr[2]; + ptr += 3; + } + + if (*ptr != NUL) { + const char *mb_ptr = mb_unescape((const char **)&ptr); + c = mb_ptr != NULL ? utf_ptr2char(mb_ptr) : *ptr++; + if (c <= 0x7f) { + // Merge modifiers into the key to make the result more readable. + int modifiers_after = modifiers; + int mod_c = merge_modifiers(c, &modifiers_after); + if (modifiers_after == 0) { + modifiers = 0; + c = mod_c; + } + } + } + + // TODO(zeertzjq): is there a more readable and yet compact representation of + // modifiers and special keys? + if (modifiers != 0) { + add_to_showcmd(K_SPECIAL); + add_to_showcmd(KS_MODIFIER); + add_to_showcmd(modifiers); + } + if (c != NUL) { + add_to_showcmd(c); + } + while (*ptr != NUL) { + add_to_showcmd(*ptr++); + } +} + /// Get the next input character. /// Can return a special key or a multi-byte character. /// Can return NUL when called recursively, use safe_vgetc() if that's not @@ -1621,9 +1747,13 @@ int vgetc(void) if (!no_mapping && KeyTyped && mod_mask == MOD_MASK_ALT && !(State & MODE_TERMINAL) && !is_mouse_key(c)) { mod_mask = 0; - int len = ins_char_typebuf(c, 0); - ins_char_typebuf(ESC, 0); - ungetchars(len + 3); // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes + int len = ins_char_typebuf(c, 0, false); + ins_char_typebuf(ESC, 0, false); + int old_len = len + 3; // K_SPECIAL KS_MODIFIER MOD_MASK_ALT takes 3 more bytes + ungetchars(old_len); + if (on_key_buf.size >= (size_t)old_len) { + on_key_buf.size -= (size_t)old_len; + } continue; } @@ -1639,7 +1769,9 @@ int vgetc(void) may_garbage_collect = false; // Execute Lua on_key callbacks. - nlua_execute_on_key(c); + nlua_execute_on_key(c, on_key_buf.items, on_key_buf.size); + kvi_destroy(on_key_buf); + kvi_init(on_key_buf); // Need to process the character before we know it's safe to do something // else. @@ -2508,7 +2640,7 @@ static int vgetorpeek(bool advance) unshowmode(true); mode_deleted = true; } - validate_cursor(); + validate_cursor(curwin); int old_wcol = curwin->w_wcol; int old_wrow = curwin->w_wrow; @@ -2541,7 +2673,7 @@ static int vgetorpeek(bool advance) curwin->w_wrow = curwin->w_cline_row + curwin->w_wcol / curwin->w_width_inner; curwin->w_wcol %= curwin->w_width_inner; - curwin->w_wcol += curwin_col_off(); + curwin->w_wcol += win_col_off(curwin); col = 0; // no correction needed } else { curwin->w_wcol--; @@ -2664,7 +2796,7 @@ static int vgetorpeek(bool advance) showcmd_idx = typebuf.tb_len - SHOWCMD_COLS; } while (showcmd_idx < typebuf.tb_len) { - add_to_showcmd(typebuf.tb_buf[typebuf.tb_off + showcmd_idx++]); + add_byte_to_showcmd(typebuf.tb_buf[typebuf.tb_off + showcmd_idx++]); } curwin->w_wcol = old_wcol; curwin->w_wrow = old_wrow; diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 22f7daa823..83fef1fe75 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -341,8 +341,6 @@ EXTERN bool did_check_timestamps INIT( = false); // did check timestamps // recently EXTERN int no_check_timestamps INIT( = 0); // Don't check timestamps -EXTERN int modified_was_set; // did ":set modified" - // Mouse coordinates, set by handle_mouse_event() EXTERN int mouse_grid; EXTERN int mouse_row; @@ -363,7 +361,7 @@ EXTERN bool sys_menu INIT( = false); // currently active window. EXTERN win_T *firstwin; // first window EXTERN win_T *lastwin; // last window -EXTERN win_T *prevwin INIT( = NULL); // previous window +EXTERN win_T *prevwin INIT( = NULL); // previous window (may equal curwin) #define ONE_WINDOW (firstwin == lastwin) #define FOR_ALL_FRAMES(frp, first_frame) \ for ((frp) = first_frame; (frp) != NULL; (frp) = (frp)->fr_next) @@ -939,6 +937,7 @@ EXTERN const char e_using_float_as_string[] INIT(= N_("E806: Using a Float as a EXTERN const char e_cannot_edit_other_buf[] INIT(= N_("E788: Not allowed to edit another buffer now")); EXTERN const char e_using_number_as_bool_nr[] INIT(= N_("E1023: Using a Number as a Bool: %d")); EXTERN const char e_not_callable_type_str[] INIT(= N_("E1085: Not a callable type: %s")); +EXTERN const char e_auabort[] INIT(= N_("E855: Autocommands caused command to abort")); EXTERN const char e_api_error[] INIT(= N_("E5555: API call: %s")); @@ -957,6 +956,7 @@ EXTERN const char e_highlight_group_name_invalid_char[] INIT(= N_("E5248: Invali EXTERN const char e_highlight_group_name_too_long[] INIT(= N_("E1249: Highlight group name too long")); +EXTERN const char e_invalid_column_number_nr[] INIT( = N_("E964: Invalid column number: %ld")); EXTERN const char e_invalid_line_number_nr[] INIT(= N_("E966: Invalid line number: %ld")); EXTERN const char e_stray_closing_curly_str[] @@ -969,6 +969,9 @@ EXTERN const char e_val_too_large[] INIT(= N_("E1510: Value too large: %s")); EXTERN const char e_undobang_cannot_redo_or_move_branch[] INIT(= N_("E5767: Cannot use :undo! to redo or move to a different undo branch")); +EXTERN const char e_winfixbuf_cannot_go_to_buffer[] +INIT(= N_("E1513: Cannot switch buffer. 'winfixbuf' is enabled")); + EXTERN const char e_trustfile[] INIT(= N_("E5570: Cannot update trust file: %s")); EXTERN const char e_unknown_option2[] INIT(= N_("E355: Unknown option: %s")); diff --git a/src/nvim/grid.c b/src/nvim/grid.c index e386853022..56246bf001 100644 --- a/src/nvim/grid.c +++ b/src/nvim/grid.c @@ -1,3 +1,6 @@ +// Low-level functions to manipulate individual character cells on the +// screen grid. +// // Most of the routines in this file perform screen (grid) manipulations. The // given operation is performed physically on the screen. The corresponding // change is also made to the internal screen image. In this way, the editor @@ -338,7 +341,7 @@ static int grid_line_first = INT_MAX; static int grid_line_last = 0; static int grid_line_clear_to = 0; static int grid_line_clear_attr = 0; -static bool grid_line_rl = false; +static int grid_line_flags = 0; /// Start a group of grid_line_puts calls that builds a single grid line. /// @@ -358,7 +361,7 @@ void grid_line_start(ScreenGrid *grid, int row) grid_line_last = 0; grid_line_clear_to = 0; grid_line_clear_attr = 0; - grid_line_rl = false; + grid_line_flags = 0; assert((size_t)grid_line_maxcol <= linebuf_size); @@ -433,15 +436,14 @@ int grid_line_puts(int col, const char *text, int textlen, int attr) ? utfc_ptr2schar_len(ptr, (int)((text + len) - ptr), &firstc) : utfc_ptr2schar(ptr, &firstc); int mbyte_cells = utf_char2cells(firstc); - if (mbyte_cells > 2) { + if (mbyte_cells > 2 || schar == 0) { mbyte_cells = 1; - schar = schar_from_char(0xFFFD); } if (col + mbyte_cells > max_col) { // Only 1 cell left, but character requires 2 cells: - // display a '>' in the last column to avoid wrapping. */ + // display a '>' in the last column to avoid wrapping. schar = schar_from_ascii('>'); mbyte_cells = 1; } @@ -515,7 +517,7 @@ void grid_line_mirror(void) return; } linebuf_mirror(&grid_line_first, &grid_line_last, &grid_line_clear_to, grid_line_maxcol); - grid_line_rl = true; + grid_line_flags |= SLF_RIGHTLEFT; } void linebuf_mirror(int *firstp, int *lastp, int *clearp, int maxcol) @@ -568,7 +570,7 @@ void grid_line_flush(void) } grid_put_linebuf(grid, grid_line_row, grid_line_coloff, grid_line_first, grid_line_last, - grid_line_clear_to, grid_line_rl, grid_line_clear_attr, false); + grid_line_clear_to, grid_line_clear_attr, -1, grid_line_flags); } /// flush grid line but only if on a valid row @@ -619,17 +621,21 @@ static int grid_char_needs_redraw(ScreenGrid *grid, int col, size_t off_to, int /// Move one buffered line to the window grid, but only the characters that /// have actually changed. Handle insert/delete character. -/// "coloff" gives the first column on the grid for this line. -/// "endcol" gives the columns where valid characters are. -/// "clear_width" is the width of the window. It's > 0 if the rest of the line -/// needs to be cleared, negative otherwise. -/// "rl" is true for rightleft text, like a window with 'rightleft' option set -/// When true and "clear_width" > 0, clear columns 0 to "endcol" -/// When false and "clear_width" > 0, clear columns "endcol" to "clear_width" -/// If "wrap" is true, then hint to the UI that "row" contains a line -/// which has wrapped into the next row. +/// +/// @param coloff gives the first column on the grid for this line. +/// @param endcol gives the columns where valid characters are. +/// @param clear_width see SLF_RIGHTLEFT. +/// @param flags can have bits: +/// - SLF_RIGHTLEFT rightleft text, like a window with 'rightleft' option set: +/// - When false, clear columns "endcol" to "clear_width". +/// - When true, clear columns "col" to "endcol". +/// - SLF_WRAP hint to UI that "row" contains a line wrapped into the next row. +/// - SLF_INC_VCOL: +/// - When false, use "last_vcol" for grid->vcols[] of the columns to clear. +/// - When true, use an increasing sequence starting from "last_vcol + 1" for +/// grid->vcols[] of the columns to clear. void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int col, int endcol, int clear_width, - bool rl, int bg_attr, bool wrap) + int bg_attr, colnr_T last_vcol, int flags) { bool redraw_next; // redraw_this for next character bool clear_next = false; @@ -659,7 +665,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int col, int endcol } int clear_start = endcol; - if (rl) { + if (flags & SLF_RIGHTLEFT) { clear_start = col; col = endcol; endcol = clear_width; @@ -743,10 +749,15 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int col, int endcol } int clear_dirty_start = -1, clear_end = -1; + if (flags & SLF_RIGHTLEFT) { + for (col = clear_width - 1; col >= clear_start; col--) { + size_t off = off_to + (size_t)col; + grid->vcols[off] = (flags & SLF_INC_VCOL) ? ++last_vcol : last_vcol; + } + } // blank out the rest of the line // TODO(bfredl): we could cache winline widths - col = clear_start; - while (col < clear_width) { + for (col = clear_start; col < clear_width; col++) { size_t off = off_to + (size_t)col; if (grid->chars[off] != schar_from_ascii(' ') || grid->attrs[off] != bg_attr @@ -758,17 +769,18 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int col, int endcol } clear_end = col + 1; } - grid->vcols[off] = MAXCOL; - col++; + if (!(flags & SLF_RIGHTLEFT)) { + grid->vcols[off] = (flags & SLF_INC_VCOL) ? ++last_vcol : last_vcol; + } } - if (rl && start_dirty != -1 && clear_dirty_start != -1) { + if ((flags & SLF_RIGHTLEFT) && start_dirty != -1 && clear_dirty_start != -1) { if (grid->throttled || clear_dirty_start >= start_dirty - 5) { // cannot draw now or too small to be worth a separate "clear" event start_dirty = clear_dirty_start; } else { ui_line(grid, row, invalid_row, coloff + clear_dirty_start, coloff + clear_dirty_start, - coloff + clear_end, bg_attr, wrap); + coloff + clear_end, bg_attr, flags & SLF_WRAP); } clear_end = end_dirty; } else { @@ -785,7 +797,7 @@ void grid_put_linebuf(ScreenGrid *grid, int row, int coloff, int col, int endcol if (clear_end > start_dirty) { if (!grid->throttled) { ui_line(grid, row, invalid_row, coloff + start_dirty, coloff + end_dirty, coloff + clear_end, - bg_attr, wrap); + bg_attr, flags & SLF_WRAP); } else if (grid->dirty_col) { // TODO(bfredl): really get rid of the extra pseudo terminal in message.c // by using a linebuf_char copy for "throttled message line" diff --git a/src/nvim/grid.h b/src/nvim/grid.h index 7506f0fc9d..25144cdc2c 100644 --- a/src/nvim/grid.h +++ b/src/nvim/grid.h @@ -27,8 +27,12 @@ EXTERN sattr_T *linebuf_attr INIT( = NULL); EXTERN colnr_T *linebuf_vcol INIT( = NULL); EXTERN char *linebuf_scratch INIT( = NULL); -// Low-level functions to manipulate individual character cells on the -// screen grid. +/// flags for grid_put_linebuf() +enum { + SLF_RIGHTLEFT = 1, + SLF_WRAP = 2, + SLF_INC_VCOL = 4, +}; /// Put a ASCII character in a screen cell. /// diff --git a/src/nvim/grid_defs.h b/src/nvim/grid_defs.h index 10a6161171..ac67f42fe0 100644 --- a/src/nvim/grid_defs.h +++ b/src/nvim/grid_defs.h @@ -37,7 +37,7 @@ enum { /// attrs[] contains the highlighting attribute for each cell. /// /// vcols[] contains the virtual columns in the line. -1 means not available -/// or before buffer text, MAXCOL means after the end of the line. +/// or before buffer text. /// -2 or -3 means in fold column and a mouse click should: /// -2: open a fold /// -3: close a fold diff --git a/src/nvim/help.c b/src/nvim/help.c index 779772cedf..e9f67ca3e4 100644 --- a/src/nvim/help.c +++ b/src/nvim/help.c @@ -613,7 +613,7 @@ void cleanup_help_tags(int num_file, char **file) void prepare_help_buffer(void) { curbuf->b_help = true; - set_string_option_direct(kOptBuftype, "help", OPT_LOCAL, 0); + set_option_direct(kOptBuftype, STATIC_CSTR_AS_OPTVAL("help"), OPT_LOCAL, 0); // Always set these options after jumping to a help tag, because the // user may have an autocommand that gets in the way. @@ -622,13 +622,13 @@ void prepare_help_buffer(void) // Only set it when needed, buf_init_chartab() is some work. char *p = "!-~,^*,^|,^\",192-255"; if (strcmp(curbuf->b_p_isk, p) != 0) { - set_string_option_direct(kOptIskeyword, p, OPT_LOCAL, 0); + set_option_direct(kOptIskeyword, CSTR_AS_OPTVAL(p), OPT_LOCAL, 0); check_buf_options(curbuf); buf_init_chartab(curbuf, false); } // Don't use the global foldmethod. - set_string_option_direct(kOptFoldmethod, "manual", OPT_LOCAL, 0); + set_option_direct(kOptFoldmethod, STATIC_CSTR_AS_OPTVAL("manual"), OPT_LOCAL, 0); curbuf->b_p_ts = 8; // 'tabstop' is 8. curwin->w_p_list = false; // No list mode. diff --git a/src/nvim/highlight_group.c b/src/nvim/highlight_group.c index 75c23c5bc4..ccb093c116 100644 --- a/src/nvim/highlight_group.c +++ b/src/nvim/highlight_group.c @@ -201,8 +201,16 @@ static const char *highlight_init_both[] = { "default link SpecialComment Special", "default link Debug Special", "default link Ignore Normal", - "default link LspInlayHint NonText", - "default link SnippetTabstop Visual", + + // Built-in LSP + "default link LspCodeLens NonText", + "default link LspCodeLensSeparator LspCodeLens", + "default link LspInlayHint NonText", + "default link LspReferenceRead LspReferenceText", + "default link LspReferenceText Visual", + "default link LspReferenceWrite LspReferenceText", + "default link LspSignatureActiveParameter Visual", + "default link SnippetTabstop Visual", // Diagnostic "default link DiagnosticFloatingError DiagnosticError", @@ -223,7 +231,8 @@ static const char *highlight_init_both[] = { "default link DiagnosticUnnecessary Comment", // Treesitter standard groups - "default link @variable.builtin Special", + "default link @variable.builtin Special", + "default link @variable.parameter.builtin Special", "default link @constant Constant", "default link @constant.builtin Special", @@ -248,8 +257,9 @@ static const char *highlight_init_both[] = { "default link @type Type", "default link @type.builtin Special", - "default link @attribute Macro", - "default link @property Identifier", + "default link @attribute Macro", + "default link @attribute.builtin Special", + "default link @property Identifier", "default link @function Function", "default link @function.builtin Special", @@ -282,7 +292,8 @@ static const char *highlight_init_both[] = { "default link @diff.minus Removed", "default link @diff.delta Changed", - "default link @tag Tag", + "default link @tag Tag", + "default link @tag.builtin Special", // LSP semantic tokens "default link @lsp.type.class @type", @@ -290,18 +301,27 @@ static const char *highlight_init_both[] = { "default link @lsp.type.decorator @attribute", "default link @lsp.type.enum @type", "default link @lsp.type.enumMember @constant", + "default link @lsp.type.event @type", "default link @lsp.type.function @function", "default link @lsp.type.interface @type", + "default link @lsp.type.keyword @keyword", "default link @lsp.type.macro @constant.macro", "default link @lsp.type.method @function.method", + "default link @lsp.type.modifier @type.qualifier", "default link @lsp.type.namespace @module", + "default link @lsp.type.number @number", + "default link @lsp.type.operator @operator", "default link @lsp.type.parameter @variable.parameter", "default link @lsp.type.property @property", + "default link @lsp.type.regexp @string.regexp", + "default link @lsp.type.string @string", "default link @lsp.type.struct @type", "default link @lsp.type.type @type", "default link @lsp.type.typeParameter @type.definition", "default link @lsp.type.variable @variable", + "default link @lsp.mod.deprecated DiagnosticDeprecated", + NULL }; @@ -349,7 +369,7 @@ static const char *highlight_init_light[] = { "SpellLocal guisp=NvimDarkGreen gui=undercurl cterm=undercurl", "SpellRare guisp=NvimDarkCyan gui=undercurl cterm=undercurl", "StatusLine guifg=NvimLightGrey3 guibg=NvimDarkGrey3 cterm=reverse", - "StatusLineNC guifg=NvimDarkGrey3 guibg=NvimLightGrey3 cterm=bold", + "StatusLineNC guifg=NvimDarkGrey3 guibg=NvimLightGrey3 cterm=bold,underline", "Title guifg=NvimDarkGrey2 gui=bold cterm=bold", "Visual guibg=NvimLightGrey4 ctermfg=15 ctermbg=0", "WarningMsg guifg=NvimDarkYellow ctermfg=3", @@ -434,7 +454,7 @@ static const char *highlight_init_dark[] = { "SpellLocal guisp=NvimLightGreen gui=undercurl cterm=undercurl", "SpellRare guisp=NvimLightCyan gui=undercurl cterm=undercurl", "StatusLine guifg=NvimDarkGrey3 guibg=NvimLightGrey3 cterm=reverse", - "StatusLineNC guifg=NvimLightGrey3 guibg=NvimDarkGrey3 cterm=bold", + "StatusLineNC guifg=NvimLightGrey3 guibg=NvimDarkGrey3 cterm=bold,underline", "Title guifg=NvimLightGrey2 gui=bold cterm=bold", "Visual guibg=NvimDarkGrey4 ctermfg=0 ctermbg=15", "WarningMsg guifg=NvimLightYellow ctermfg=11", @@ -877,11 +897,13 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id) g->sg_link = link_id; g->sg_script_ctx = current_sctx; g->sg_script_ctx.sc_lnum += SOURCING_LNUM; + nlua_set_sctx(&g->sg_script_ctx); g->sg_set |= SG_LINK; if (is_default) { g->sg_deflink = link_id; g->sg_deflink_sctx = current_sctx; g->sg_deflink_sctx.sc_lnum += SOURCING_LNUM; + nlua_set_sctx(&g->sg_deflink_sctx); } } else { g->sg_link = 0; @@ -922,6 +944,7 @@ void set_hl_group(int id, HlAttrs attrs, Dict(highlight) *dict, int link_id) g->sg_script_ctx = current_sctx; g->sg_script_ctx.sc_lnum += SOURCING_LNUM; + nlua_set_sctx(&g->sg_script_ctx); g->sg_attr = hl_get_syn_attr(0, id, attrs); @@ -1149,9 +1172,8 @@ void do_highlight(const char *line, const bool forceit, const bool init) error = true; break; } - memcpy(key, key_start, key_len); - key[key_len] = NUL; - vim_strup(key); + vim_memcpy_up(key, key_start, key_len); + key[key_len] = '\0'; linep = skipwhite(linep); if (strcmp(key, "NONE") == 0) { @@ -1903,7 +1925,7 @@ static void set_hl_attr(int idx) at_en.cterm_bg_color = (int16_t)sgp->sg_cterm_bg; at_en.rgb_ae_attr = (int16_t)sgp->sg_gui; // FIXME(tarruda): The "unset value" for rgb is -1, but since hlgroup is - // initialized with 0(by garray functions), check for sg_rgb_{f,b}g_name + // initialized with 0 (by garray functions), check for sg_rgb_{f,b}g_name // before setting attr_entry->{f,g}g_color to a other than -1 at_en.rgb_fg_color = sgp->sg_rgb_fg_idx != kColorIdxNone ? sgp->sg_rgb_fg : -1; at_en.rgb_bg_color = sgp->sg_rgb_bg_idx != kColorIdxNone ? sgp->sg_rgb_bg : -1; @@ -1941,11 +1963,10 @@ int syn_name2id_len(const char *name, size_t len) return 0; } - // Avoid using stricmp() too much, it's slow on some systems */ + // Avoid using stricmp() too much, it's slow on some systems // Avoid alloc()/free(), these are slow too. - memcpy(name_u, name, len); + vim_memcpy_up(name_u, name, len); name_u[len] = '\0'; - vim_strup(name_u); // map_get(..., int) returns 0 when no key is present, which is // the expected value for missing highlight group. @@ -2462,7 +2483,7 @@ color_name_table_T color_name_table[] = { { "Cyan4", RGB_(0x0, 0x8b, 0x8b) }, { "DarkBlue", RGB_(0x00, 0x00, 0x8b) }, { "DarkCyan", RGB_(0x00, 0x8b, 0x8b) }, - { "DarkGoldenRod", RGB_(0xb8, 0x86, 0x0b) }, + { "DarkGoldenrod", RGB_(0xb8, 0x86, 0x0b) }, { "DarkGoldenrod1", RGB_(0xff, 0xb9, 0xf) }, { "DarkGoldenrod2", RGB_(0xee, 0xad, 0xe) }, { "DarkGoldenrod3", RGB_(0xcd, 0x95, 0xc) }, @@ -2536,7 +2557,7 @@ color_name_table_T color_name_table[] = { { "Gold2", RGB_(0xee, 0xc9, 0x0) }, { "Gold3", RGB_(0xcd, 0xad, 0x0) }, { "Gold4", RGB_(0x8b, 0x75, 0x0) }, - { "GoldenRod", RGB_(0xda, 0xa5, 0x20) }, + { "Goldenrod", RGB_(0xda, 0xa5, 0x20) }, { "Goldenrod1", RGB_(0xff, 0xc1, 0x25) }, { "Goldenrod2", RGB_(0xee, 0xb4, 0x22) }, { "Goldenrod3", RGB_(0xcd, 0x9b, 0x1d) }, @@ -2805,7 +2826,7 @@ color_name_table_T color_name_table[] = { { "LightGoldenrod2", RGB_(0xee, 0xdc, 0x82) }, { "LightGoldenrod3", RGB_(0xcd, 0xbe, 0x70) }, { "LightGoldenrod4", RGB_(0x8b, 0x81, 0x4c) }, - { "LightGoldenRodYellow", RGB_(0xfa, 0xfa, 0xd2) }, + { "LightGoldenrodYellow", RGB_(0xfa, 0xfa, 0xd2) }, { "LightGray", RGB_(0xd3, 0xd3, 0xd3) }, { "LightGreen", RGB_(0x90, 0xee, 0x90) }, { "LightGrey", RGB_(0xd3, 0xd3, 0xd3) }, @@ -2890,6 +2911,10 @@ color_name_table_T color_name_table[] = { // for foreground in light/dark color scheme. { "NvimDarkBlue", RGB_(0x00, 0x4c, 0x73) }, { "NvimDarkCyan", RGB_(0x00, 0x73, 0x73) }, + { "NvimDarkGray1", RGB_(0x07, 0x08, 0x0d) }, + { "NvimDarkGray2", RGB_(0x14, 0x16, 0x1b) }, + { "NvimDarkGray3", RGB_(0x2c, 0x2e, 0x33) }, + { "NvimDarkGray4", RGB_(0x4f, 0x52, 0x58) }, { "NvimDarkGreen", RGB_(0x00, 0x55, 0x23) }, { "NvimDarkGrey1", RGB_(0x07, 0x08, 0x0d) }, { "NvimDarkGrey2", RGB_(0x14, 0x16, 0x1b) }, @@ -2900,6 +2925,10 @@ color_name_table_T color_name_table[] = { { "NvimDarkYellow", RGB_(0x6b, 0x53, 0x00) }, { "NvimLightBlue", RGB_(0xa6, 0xdb, 0xff) }, { "NvimLightCyan", RGB_(0x8c, 0xf8, 0xf7) }, + { "NvimLightGray1", RGB_(0xee, 0xf1, 0xf8) }, + { "NvimLightGray2", RGB_(0xe0, 0xe2, 0xea) }, + { "NvimLightGray3", RGB_(0xc4, 0xc6, 0xcd) }, + { "NvimLightGray4", RGB_(0x9b, 0x9e, 0xa4) }, { "NvimLightGreen", RGB_(0xb3, 0xf6, 0xc0) }, { "NvimLightGrey1", RGB_(0xee, 0xf1, 0xf8) }, { "NvimLightGrey2", RGB_(0xe0, 0xe2, 0xea) }, @@ -2930,7 +2959,7 @@ color_name_table_T color_name_table[] = { { "Orchid2", RGB_(0xee, 0x7a, 0xe9) }, { "Orchid3", RGB_(0xcd, 0x69, 0xc9) }, { "Orchid4", RGB_(0x8b, 0x47, 0x89) }, - { "PaleGoldenRod", RGB_(0xee, 0xe8, 0xaa) }, + { "PaleGoldenrod", RGB_(0xee, 0xe8, 0xaa) }, { "PaleGreen", RGB_(0x98, 0xfb, 0x98) }, { "PaleGreen1", RGB_(0x9a, 0xff, 0x9a) }, { "PaleGreen2", RGB_(0x90, 0xee, 0x90) }, diff --git a/src/nvim/highlight_group.h b/src/nvim/highlight_group.h index 47d58d20f2..edf5fbde16 100644 --- a/src/nvim/highlight_group.h +++ b/src/nvim/highlight_group.h @@ -12,7 +12,7 @@ typedef struct { char *name; RgbValue color; } color_name_table_T; -extern color_name_table_T color_name_table[700]; +extern color_name_table_T color_name_table[708]; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "highlight_group.h.generated.h" diff --git a/src/nvim/indent.c b/src/nvim/indent.c index 14247b6d86..d635c7d7bf 100644 --- a/src/nvim/indent.c +++ b/src/nvim/indent.c @@ -177,7 +177,7 @@ colnr_T tabstop_start(colnr_T col, int ts, colnr_T *vts) colnr_T tabcol = 0; if (vts == NULL || vts[0] == 0) { - return ((col / ts) * ts); + return col - col % ts; } const int tabcount = vts[0]; @@ -189,7 +189,7 @@ colnr_T tabstop_start(colnr_T col, int ts, colnr_T *vts) } const int excess = (tabcol % vts[tabcount]); - return (excess + ((col - excess) / vts[tabcount]) * vts[tabcount]); + return col - (col - excess) % vts[tabcount]; } /// Find the number of tabs and spaces necessary to get from one column @@ -1105,7 +1105,7 @@ void ex_retab(exarg_T *eap) colnr_T *old_vts_ary = curbuf->b_p_vts_array; if (tabstop_count(old_vts_ary) > 0 || tabstop_count(new_vts_array) > 1) { - set_string_option_direct(kOptVartabstop, new_ts_str, OPT_LOCAL, 0); + set_option_direct(kOptVartabstop, CSTR_AS_OPTVAL(new_ts_str), OPT_LOCAL, 0); curbuf->b_p_vts_array = new_vts_array; xfree(old_vts_ary); } else { @@ -1116,7 +1116,7 @@ void ex_retab(exarg_T *eap) } xfree(new_ts_str); } - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); u_clearline(curbuf); } @@ -1160,7 +1160,7 @@ int get_expr_indent(void) curwin->w_cursor = save_pos; curwin->w_curswant = save_curswant; curwin->w_set_curswant = save_set_curswant; - check_cursor(); + check_cursor(curwin); State = save_State; // Reset did_throw, unless 'debug' has "throw" and inside a try/catch. diff --git a/src/nvim/indent_c.c b/src/nvim/indent_c.c index a660c9dead..65b5f46333 100644 --- a/src/nvim/indent_c.c +++ b/src/nvim/indent_c.c @@ -1197,7 +1197,7 @@ static int cin_is_cpp_baseclass(cpp_baseclass_cache_T *cached) s = line; } if (s == line) { - // don't recognize "case (foo):" as a baseclass */ + // don't recognize "case (foo):" as a baseclass if (cin_iscase(s, false)) { break; } diff --git a/src/nvim/input.c b/src/nvim/input.c index 7667c49452..e14bfe7539 100644 --- a/src/nvim/input.c +++ b/src/nvim/input.c @@ -14,6 +14,7 @@ #include "nvim/highlight_defs.h" #include "nvim/input.h" #include "nvim/keycodes.h" +#include "nvim/math.h" #include "nvim/mbyte.h" #include "nvim/memory.h" #include "nvim/message.h" @@ -21,6 +22,7 @@ #include "nvim/os/input.h" #include "nvim/state_defs.h" #include "nvim/ui.h" +#include "nvim/vim_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "input.c.generated.h" // IWYU pragma: export @@ -180,10 +182,9 @@ int get_number(int colon, bool *mouse_used) ui_cursor_goto(msg_row, msg_col); int c = safe_vgetc(); if (ascii_isdigit(c)) { - if (n > INT_MAX / 10) { + if (vim_append_digit_int(&n, c - '0') == FAIL) { return 0; } - n = n * 10 + c - '0'; msg_putchar(c); typed++; } else if (c == K_DEL || c == K_KDEL || c == K_BS || c == Ctrl_H) { diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 41b964323e..b557b9802e 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -253,6 +253,7 @@ static int ctrl_x_mode = CTRL_X_NORMAL; static int compl_matches = 0; ///< number of completion matches static char *compl_pattern = NULL; +static size_t compl_patternlen = 0; static Direction compl_direction = FORWARD; static Direction compl_shows_dir = FORWARD; static int compl_pending = 0; ///< > 1 for postponed CTRL-N @@ -567,6 +568,18 @@ static bool is_first_match(const compl_T *const match) return match == compl_first_match; } +static void do_autocmd_completedone(int c) +{ + save_v_event_T save_v_event; + dict_T *v_event = get_v_event(&save_v_event); + + tv_dict_add_str(v_event, S_LEN("reason"), (c == Ctrl_Y ? "accept" : "cancel")); + tv_dict_set_keys_readonly(v_event); + + ins_apply_autocmds(EVENT_COMPLETEDONE); + restore_v_event(v_event, &save_v_event); +} + /// Check that character "c" is part of the item currently being /// completed. Used to decide whether to abandon complete mode when the menu /// is visible. @@ -1104,11 +1117,11 @@ static dict_T *ins_compl_dict_alloc(compl_T *match) { // { word, abbr, menu, kind, info } dict_T *dict = tv_dict_alloc_lock(VAR_FIXED); - tv_dict_add_str(dict, S_LEN("word"), EMPTY_IF_NULL(match->cp_str)); - tv_dict_add_str(dict, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR])); - tv_dict_add_str(dict, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU])); - tv_dict_add_str(dict, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND])); - tv_dict_add_str(dict, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO])); + tv_dict_add_str(dict, S_LEN("word"), match->cp_str); + tv_dict_add_str(dict, S_LEN("abbr"), match->cp_text[CPT_ABBR]); + tv_dict_add_str(dict, S_LEN("menu"), match->cp_text[CPT_MENU]); + tv_dict_add_str(dict, S_LEN("kind"), match->cp_text[CPT_KIND]); + tv_dict_add_str(dict, S_LEN("info"), match->cp_text[CPT_INFO]); if (match->cp_user_data.v_type == VAR_UNKNOWN) { tv_dict_add_str(dict, S_LEN("user_data"), ""); } else { @@ -1307,26 +1320,30 @@ void ins_compl_show_pum(void) } } -/// used for set or update info -void compl_set_info(int pum_idx) +/// check selected is current match. +/// +/// @param selected the item which is selected. +/// @return bool return true when is current match otherwise is false. +bool compl_match_curr_select(int selected) { - compl_T *comp = compl_first_match; - char *pum_text = compl_match_array[pum_idx].pum_text; - - while (comp != NULL) { - if (pum_text == comp->cp_str - || pum_text == comp->cp_text[CPT_ABBR]) { - comp->cp_text[CPT_INFO] = compl_match_array[pum_idx].pum_info; - - // if comp is current match update completed_item value - if (comp == compl_curr_match) { - dict_T *dict = ins_compl_dict_alloc(compl_curr_match); - set_vim_var_dict(VV_COMPLETED_ITEM, dict); + if (selected < 0) { + return false; + } + compl_T *match = compl_first_match; + int selected_idx = -1, list_idx = 0; + do { + if (!match_at_original_text(match)) { + if (compl_curr_match != NULL + && compl_curr_match->cp_number == match->cp_number) { + selected_idx = list_idx; + break; } - break; + list_idx += 1; } - comp = comp->cp_next; - } + match = match->cp_next; + } while (match != NULL && !is_first_match(match)); + + return selected == selected_idx; } #define DICT_FIRST (1) ///< use just first element in "dict" @@ -1579,6 +1596,7 @@ static char *find_line_end(char *ptr) static void ins_compl_free(void) { XFREE_CLEAR(compl_pattern); + compl_patternlen = 0; XFREE_CLEAR(compl_leader); if (compl_first_match == NULL) { @@ -1613,6 +1631,7 @@ void ins_compl_clear(void) compl_started = false; compl_matches = 0; XFREE_CLEAR(compl_pattern); + compl_patternlen = 0; XFREE_CLEAR(compl_leader); edit_submode_extra = NULL; kv_destroy(compl_orig_extmarks); @@ -2103,7 +2122,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval) } // Trigger the CompleteDone event to give scripts a chance to act // upon the end of completion. - ins_apply_autocmds(EVENT_COMPLETEDONE); + do_autocmd_completedone(c); return retval; } @@ -2192,7 +2211,7 @@ bool ins_compl_prep(int c) } else if (ctrl_x_mode == CTRL_X_LOCAL_MSG) { // Trigger the CompleteDone event to give scripts a chance to act // upon the (possibly failed) completion. - ins_apply_autocmds(EVENT_COMPLETEDONE); + do_autocmd_completedone(c); } may_trigger_modechanged(); @@ -2435,8 +2454,9 @@ static void expand_by_function(int type, char *base) } textlock--; - curwin->w_cursor = pos; // restore the cursor position - validate_cursor(); + curwin->w_cursor = pos; // restore the cursor position + check_cursor(curwin); // make sure cursor position is valid, just in case + validate_cursor(curwin); if (!equalpos(curwin->w_cursor, pos)) { emsg(_(e_compldel)); goto theend; @@ -2730,72 +2750,6 @@ static void ins_compl_update_sequence_numbers(void) } } -static int info_add_completion_info(list_T *li) -{ - if (compl_first_match == NULL) { - return OK; - } - - bool forward = compl_dir_forward(); - compl_T *match = compl_first_match; - // There are four cases to consider here: - // 1) when just going forward through the menu, - // compl_first_match should point to the initial entry with - // number zero and CP_ORIGINAL_TEXT flag set - // 2) when just going backwards, - // compl-first_match should point to the last entry before - // the entry with the CP_ORIGINAL_TEXT flag set - // 3) when first going forwards and then backwards, e.g. - // pressing C-N, C-P, compl_first_match points to the - // last entry before the entry with the CP_ORIGINAL_TEXT - // flag set and next-entry moves opposite through the list - // compared to case 2, so pretend the direction is forward again - // 4) when first going backwards and then forwards, e.g. - // pressing C-P, C-N, compl_first_match points to the - // first entry with the CP_ORIGINAL_TEXT - // flag set and next-entry moves in opposite direction through the list - // compared to case 1, so pretend the direction is backwards again - // - // But only do this when the 'noselect' option is not active! - - if (!compl_no_select) { - if (forward && !match_at_original_text(match)) { - forward = false; - } else if (!forward && match_at_original_text(match)) { - forward = true; - } - } - - // Skip the element with the CP_ORIGINAL_TEXT flag at the beginning, in case of - // forward completion, or at the end, in case of backward completion. - match = (forward || match->cp_prev == NULL - ? match->cp_next - : (compl_no_select && match_at_original_text(match) - ? match->cp_prev - : match->cp_prev->cp_prev)); - - while (match != NULL && !match_at_original_text(match)) { - dict_T *di = tv_dict_alloc(); - - tv_list_append_dict(li, di); - tv_dict_add_str(di, S_LEN("word"), EMPTY_IF_NULL(match->cp_str)); - tv_dict_add_str(di, S_LEN("abbr"), EMPTY_IF_NULL(match->cp_text[CPT_ABBR])); - tv_dict_add_str(di, S_LEN("menu"), EMPTY_IF_NULL(match->cp_text[CPT_MENU])); - tv_dict_add_str(di, S_LEN("kind"), EMPTY_IF_NULL(match->cp_text[CPT_KIND])); - tv_dict_add_str(di, S_LEN("info"), EMPTY_IF_NULL(match->cp_text[CPT_INFO])); - if (match->cp_user_data.v_type == VAR_UNKNOWN) { - // Add an empty string for backwards compatibility - tv_dict_add_str(di, S_LEN("user_data"), ""); - } else { - tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data); - } - - match = forward ? match->cp_next : match->cp_prev; - } - - return OK; -} - /// Get complete information static void get_complete_info(list_T *what_list, dict_T *retdict) { @@ -2839,25 +2793,54 @@ static void get_complete_info(list_T *what_list, dict_T *retdict) ret = tv_dict_add_nr(retdict, S_LEN("pum_visible"), pum_visible()); } - if (ret == OK && (what_flag & CI_WHAT_ITEMS)) { - list_T *li = tv_list_alloc(get_compl_len()); - ret = tv_dict_add_list(retdict, S_LEN("items"), li); - if (ret == OK) { - ret = info_add_completion_info(li); + if (ret == OK && (what_flag & CI_WHAT_ITEMS || what_flag & CI_WHAT_SELECTED)) { + list_T *li = NULL; + int selected_idx = -1; + if (what_flag & CI_WHAT_ITEMS) { + li = tv_list_alloc(kListLenMayKnow); + ret = tv_dict_add_list(retdict, S_LEN("items"), li); } - } - - if (ret == OK && (what_flag & CI_WHAT_SELECTED)) { - if (compl_curr_match != NULL && compl_curr_match->cp_number == -1) { - ins_compl_update_sequence_numbers(); + if (ret == OK && what_flag & CI_WHAT_SELECTED) { + if (compl_curr_match != NULL && compl_curr_match->cp_number == -1) { + ins_compl_update_sequence_numbers(); + } } - ret = tv_dict_add_nr(retdict, S_LEN("selected"), - (compl_curr_match != NULL) - ? compl_curr_match->cp_number - 1 : -1); - win_T *wp = win_float_find_preview(); - if (wp != NULL) { - tv_dict_add_nr(retdict, S_LEN("preview_winid"), wp->handle); - tv_dict_add_nr(retdict, S_LEN("preview_bufnr"), wp->w_buffer->handle); + if (ret == OK && compl_first_match != NULL) { + int list_idx = 0; + compl_T *match = compl_first_match; + do { + if (!match_at_original_text(match)) { + if (what_flag & CI_WHAT_ITEMS) { + dict_T *di = tv_dict_alloc(); + tv_list_append_dict(li, di); + tv_dict_add_str(di, S_LEN("word"), match->cp_str); + tv_dict_add_str(di, S_LEN("abbr"), match->cp_text[CPT_ABBR]); + tv_dict_add_str(di, S_LEN("menu"), match->cp_text[CPT_MENU]); + tv_dict_add_str(di, S_LEN("kind"), match->cp_text[CPT_KIND]); + tv_dict_add_str(di, S_LEN("info"), match->cp_text[CPT_INFO]); + if (match->cp_user_data.v_type == VAR_UNKNOWN) { + // Add an empty string for backwards compatibility + tv_dict_add_str(di, S_LEN("user_data"), ""); + } else { + tv_dict_add_tv(di, S_LEN("user_data"), &match->cp_user_data); + } + } + if (compl_curr_match != NULL + && compl_curr_match->cp_number == match->cp_number) { + selected_idx = list_idx; + } + list_idx += 1; + } + match = match->cp_next; + } while (match != NULL && !is_first_match(match)); + } + if (ret == OK && (what_flag & CI_WHAT_SELECTED)) { + ret = tv_dict_add_nr(retdict, S_LEN("selected"), selected_idx); + win_T *wp = win_float_find_preview(); + if (wp != NULL) { + tv_dict_add_nr(retdict, S_LEN("preview_winid"), wp->handle); + tv_dict_add_nr(retdict, S_LEN("preview_bufnr"), wp->w_buffer->handle); + } } } @@ -2937,7 +2920,7 @@ static int process_next_cpt_value(ins_compl_next_state_T *st, int *compl_type_ar // buffer, so that word at start of buffer is found // correctly. st->first_match_pos.lnum = st->ins_buf->b_ml.ml_line_count; - st->first_match_pos.col = (colnr_T)strlen(ml_get(st->first_match_pos.lnum)); + st->first_match_pos.col = ml_get_len(st->first_match_pos.lnum); } st->last_match_pos = st->first_match_pos; compl_type = 0; @@ -3023,11 +3006,11 @@ done: static void get_next_include_file_completion(int compl_type) { find_pattern_in_path(compl_pattern, compl_direction, - strlen(compl_pattern), false, false, + compl_patternlen, false, false, ((compl_type == CTRL_X_PATH_DEFINES && !(compl_cont_status & CONT_SOL)) ? FIND_DEFINE : FIND_ANY), - 1, ACTION_EXPAND, 1, MAXLNUM); + 1, ACTION_EXPAND, 1, MAXLNUM, false); } /// Get the next set of words matching "compl_pattern" in dictionary or @@ -3106,8 +3089,7 @@ static void get_next_cmdline_completion(void) char **matches; int num_matches; if (expand_cmdline(&compl_xp, compl_pattern, - (int)strlen(compl_pattern), - &num_matches, &matches) == EXPAND_OK) { + (int)compl_patternlen, &num_matches, &matches) == EXPAND_OK) { ins_compl_add_matches(num_matches, matches, false); } } @@ -3249,8 +3231,8 @@ 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, compl_pattern, 1, - SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL); + NULL, compl_direction, compl_pattern, compl_patternlen, + 1, SEARCH_KEEP + SEARCH_NFMSG, RE_LAST, NULL); } msg_silent--; if (!compl_started || st->set_match_pos) { @@ -3934,7 +3916,8 @@ static bool ins_compl_use_match(int c) /// Get the pattern, column and length for normal completion (CTRL-N CTRL-P /// completion) -/// Sets the global variables: compl_col, compl_length and compl_pattern. +/// Sets the global variables: compl_col, compl_length, compl_pattern and +/// compl_patternlen. /// Uses the global variables: compl_cont_status and ctrl_x_mode static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) { @@ -3951,21 +3934,23 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) } } else if (compl_status_adding()) { char *prefix = "\\<"; + size_t prefixlen = STRLEN_LITERAL("\\<"); // we need up to 2 extra chars for the prefix - compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, compl_length) + 2); + compl_pattern = xmalloc(quote_meta(NULL, line + compl_col, + compl_length) + prefixlen); if (!vim_iswordp(line + compl_col) || (compl_col > 0 && (vim_iswordp(mb_prevptr(line, line + compl_col))))) { prefix = ""; + prefixlen = 0; } STRCPY(compl_pattern, prefix); - quote_meta(compl_pattern + strlen(prefix), - line + compl_col, compl_length); + quote_meta(compl_pattern + prefixlen, line + compl_col, compl_length); } else if (--startcol < 0 || !vim_iswordp(mb_prevptr(line, line + startcol + 1))) { // Match any word of at least two chars - compl_pattern = xstrdup("\\<\\k\\k"); + compl_pattern = xstrnsave(S_LEN("\\<\\k\\k")); compl_col += curs_col; compl_length = 0; } else { @@ -3997,6 +3982,8 @@ static int get_normal_compl_info(char *line, int startcol, colnr_T curs_col) } } + compl_patternlen = strlen(compl_pattern); + return OK; } @@ -4016,6 +4003,8 @@ static int get_wholeline_compl_info(char *line, colnr_T curs_col) compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); } + compl_patternlen = strlen(compl_pattern); + return OK; } @@ -4041,6 +4030,7 @@ static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col) compl_col += startcol; compl_length = (int)curs_col - startcol; compl_pattern = addstar(line + compl_col, (size_t)compl_length, EXPAND_FILES); + compl_patternlen = strlen(compl_pattern); return OK; } @@ -4050,7 +4040,8 @@ static int get_filename_compl_info(char *line, int startcol, colnr_T curs_col) static int get_cmdline_compl_info(char *line, colnr_T curs_col) { compl_pattern = xstrnsave(line, (size_t)curs_col); - set_cmd_context(&compl_xp, compl_pattern, (int)strlen(compl_pattern), curs_col, false); + compl_patternlen = (size_t)curs_col; + set_cmd_context(&compl_xp, compl_pattern, (int)compl_patternlen, curs_col, false); if (compl_xp.xp_context == EXPAND_UNSUCCESSFUL || compl_xp.xp_context == EXPAND_NOTHING) { // No completion possible, use an empty pattern to get a @@ -4096,7 +4087,8 @@ static int get_userdefined_compl_info(colnr_T curs_col) State = save_State; curwin->w_cursor = pos; // restore the cursor position - validate_cursor(); + check_cursor(curwin); // make sure cursor position is valid, just in case + validate_cursor(curwin); if (!equalpos(curwin->w_cursor, pos)) { emsg(_(e_compldel)); return FAIL; @@ -4135,6 +4127,7 @@ static int get_userdefined_compl_info(colnr_T curs_col) char *line = ml_get(curwin->w_cursor.lnum); compl_length = curs_col - compl_col; compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); + compl_patternlen = (size_t)compl_length; return OK; } @@ -4160,6 +4153,7 @@ static int get_spell_compl_info(int startcol, colnr_T curs_col) // Need to obtain "line" again, it may have become invalid. char *line = ml_get(curwin->w_cursor.lnum); compl_pattern = xstrnsave(line + compl_col, (size_t)compl_length); + compl_patternlen = (size_t)compl_length; return OK; } @@ -4355,6 +4349,7 @@ static int ins_compl_start(void) if (ins_compl_add(compl_orig_text, -1, NULL, NULL, false, NULL, 0, flags, false) != OK) { XFREE_CLEAR(compl_pattern); + compl_patternlen = 0; XFREE_CLEAR(compl_orig_text); kv_destroy(compl_orig_extmarks); return FAIL; @@ -4601,7 +4596,7 @@ void free_insexpand_stuff(void) static void spell_back_to_badword(void) { pos_T tpos = curwin->w_cursor; - spell_bad_len = spell_move_to(curwin, BACKWARD, true, true, NULL); + spell_bad_len = spell_move_to(curwin, BACKWARD, SMT_ALL, true, NULL); if (curwin->w_cursor.col != tpos.col) { start_arrow(&tpos); } diff --git a/src/nvim/lua/api_wrappers.c b/src/nvim/lua/api_wrappers.c new file mode 100644 index 0000000000..2b7b0c6471 --- /dev/null +++ b/src/nvim/lua/api_wrappers.c @@ -0,0 +1,18 @@ +#include <lauxlib.h> +#include <lua.h> +#include <lualib.h> + +#include "nvim/api/private/defs.h" +#include "nvim/api/private/dispatch.h" +#include "nvim/api/private/helpers.h" +#include "nvim/ex_docmd.h" +#include "nvim/ex_getln.h" +#include "nvim/func_attr.h" +#include "nvim/globals.h" +#include "nvim/lua/converter.h" +#include "nvim/lua/executor.h" +#include "nvim/memory.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "lua_api_c_bindings.generated.h" +#endif diff --git a/src/nvim/lua/base64.c b/src/nvim/lua/base64.c index c1f43a37d7..8fe918493a 100644 --- a/src/nvim/lua/base64.c +++ b/src/nvim/lua/base64.c @@ -45,12 +45,13 @@ static int nlua_base64_decode(lua_State *L) size_t src_len = 0; const char *src = lua_tolstring(L, 1, &src_len); - const char *ret = base64_decode(src, src_len); + size_t out_len = 0; + const char *ret = base64_decode(src, src_len, &out_len); if (ret == NULL) { return luaL_error(L, "Invalid input"); } - lua_pushstring(L, ret); + lua_pushlstring(L, ret, out_len); xfree((void *)ret); return 1; diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index bba771f8a5..38ccb03cfc 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -597,9 +597,9 @@ static bool typval_conv_special = false; /// @param[in] tv typval_T to convert. /// /// @return true in case of success, false otherwise. -bool nlua_push_typval(lua_State *lstate, typval_T *const tv, bool special) +bool nlua_push_typval(lua_State *lstate, typval_T *const tv, int flags) { - typval_conv_special = special; + typval_conv_special = (flags & kNluaPushSpecial); const int initial_size = lua_gettop(lstate); if (!lua_checkstack(lstate, initial_size + 2)) { @@ -662,7 +662,7 @@ static inline void nlua_create_typed_table(lua_State *lstate, const size_t narr, /// Convert given String to lua string /// /// Leaves converted string on top of the stack. -void nlua_push_String(lua_State *lstate, const String s, bool special) +void nlua_push_String(lua_State *lstate, const String s, int flags) FUNC_ATTR_NONNULL_ALL { lua_pushlstring(lstate, s.data, s.size); @@ -671,7 +671,7 @@ void nlua_push_String(lua_State *lstate, const String s, bool special) /// Convert given Integer to lua number /// /// Leaves converted number on top of the stack. -void nlua_push_Integer(lua_State *lstate, const Integer n, bool special) +void nlua_push_Integer(lua_State *lstate, const Integer n, int flags) FUNC_ATTR_NONNULL_ALL { lua_pushnumber(lstate, (lua_Number)n); @@ -680,10 +680,10 @@ void nlua_push_Integer(lua_State *lstate, const Integer n, bool special) /// Convert given Float to lua table /// /// Leaves converted table on top of the stack. -void nlua_push_Float(lua_State *lstate, const Float f, bool special) +void nlua_push_Float(lua_State *lstate, const Float f, int flags) FUNC_ATTR_NONNULL_ALL { - if (special) { + if (flags & kNluaPushSpecial) { nlua_create_typed_table(lstate, 0, 1, kObjectTypeFloat); nlua_push_val_idx(lstate); lua_pushnumber(lstate, (lua_Number)f); @@ -696,7 +696,7 @@ void nlua_push_Float(lua_State *lstate, const Float f, bool special) /// Convert given Float to lua boolean /// /// Leaves converted value on top of the stack. -void nlua_push_Boolean(lua_State *lstate, const Boolean b, bool special) +void nlua_push_Boolean(lua_State *lstate, const Boolean b, int flags) FUNC_ATTR_NONNULL_ALL { lua_pushboolean(lstate, b); @@ -705,21 +705,21 @@ void nlua_push_Boolean(lua_State *lstate, const Boolean b, bool special) /// Convert given Dictionary to lua table /// /// Leaves converted table on top of the stack. -void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special) +void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, int flags) FUNC_ATTR_NONNULL_ALL { - if (dict.size == 0 && special) { + if (dict.size == 0 && (flags & kNluaPushSpecial)) { nlua_create_typed_table(lstate, 0, 0, kObjectTypeDictionary); } else { lua_createtable(lstate, 0, (int)dict.size); - if (dict.size == 0 && !special) { + if (dict.size == 0 && !(flags & kNluaPushSpecial)) { nlua_pushref(lstate, nlua_global_refs->empty_dict_ref); lua_setmetatable(lstate, -2); } } for (size_t i = 0; i < dict.size; i++) { - nlua_push_String(lstate, dict.items[i].key, special); - nlua_push_Object(lstate, &dict.items[i].value, special); + nlua_push_String(lstate, dict.items[i].key, flags); + nlua_push_Object(lstate, &dict.items[i].value, flags); lua_rawset(lstate, -3); } } @@ -727,18 +727,18 @@ void nlua_push_Dictionary(lua_State *lstate, const Dictionary dict, bool special /// Convert given Array to lua table /// /// Leaves converted table on top of the stack. -void nlua_push_Array(lua_State *lstate, const Array array, bool special) +void nlua_push_Array(lua_State *lstate, const Array array, int flags) FUNC_ATTR_NONNULL_ALL { lua_createtable(lstate, (int)array.size, 0); for (size_t i = 0; i < array.size; i++) { - nlua_push_Object(lstate, &array.items[i], special); + nlua_push_Object(lstate, &array.items[i], flags); lua_rawseti(lstate, -2, (int)i + 1); } } #define GENERATE_INDEX_FUNCTION(type) \ - void nlua_push_##type(lua_State *lstate, const type item, bool special) \ + void nlua_push_##type(lua_State *lstate, const type item, int flags) \ FUNC_ATTR_NONNULL_ALL \ { \ lua_pushnumber(lstate, (lua_Number)(item)); \ @@ -753,12 +753,12 @@ GENERATE_INDEX_FUNCTION(Tabpage) /// Convert given Object to lua value /// /// Leaves converted value on top of the stack. -void nlua_push_Object(lua_State *lstate, Object *obj, bool special) +void nlua_push_Object(lua_State *lstate, Object *obj, int flags) FUNC_ATTR_NONNULL_ALL { switch (obj->type) { case kObjectTypeNil: - if (special) { + if (flags & kNluaPushSpecial) { lua_pushnil(lstate); } else { nlua_pushref(lstate, nlua_global_refs->nil_ref); @@ -766,13 +766,15 @@ void nlua_push_Object(lua_State *lstate, Object *obj, bool special) break; case kObjectTypeLuaRef: { nlua_pushref(lstate, obj->data.luaref); - api_free_luaref(obj->data.luaref); - obj->data.luaref = LUA_NOREF; + if (flags & kNluaPushFreeRefs) { + api_free_luaref(obj->data.luaref); + obj->data.luaref = LUA_NOREF; + } break; } #define ADD_TYPE(type, data_key) \ case kObjectType##type: { \ - nlua_push_##type(lstate, obj->data.data_key, special); \ + nlua_push_##type(lstate, obj->data.data_key, flags); \ break; \ } ADD_TYPE(Boolean, boolean) @@ -784,7 +786,7 @@ void nlua_push_Object(lua_State *lstate, Object *obj, bool special) #undef ADD_TYPE #define ADD_REMOTE_TYPE(type) \ case kObjectType##type: { \ - nlua_push_##type(lstate, (type)obj->data.integer, special); \ + nlua_push_##type(lstate, (type)obj->data.integer, flags); \ break; \ } ADD_REMOTE_TYPE(Buffer) @@ -1380,7 +1382,7 @@ void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table) lua_pushstring(L, field->str); if (field->type == kObjectTypeNil) { - nlua_push_Object(L, (Object *)mem, false); + nlua_push_Object(L, (Object *)mem, 0); } else if (field->type == kObjectTypeInteger) { lua_pushinteger(L, *(Integer *)mem); } else if (field->type == kObjectTypeBuffer || field->type == kObjectTypeWindow @@ -1391,11 +1393,11 @@ void nlua_push_keydict(lua_State *L, void *value, KeySetLink *table) } else if (field->type == kObjectTypeBoolean) { lua_pushboolean(L, *(Boolean *)mem); } else if (field->type == kObjectTypeString) { - nlua_push_String(L, *(String *)mem, false); + nlua_push_String(L, *(String *)mem, 0); } else if (field->type == kObjectTypeArray) { - nlua_push_Array(L, *(Array *)mem, false); + nlua_push_Array(L, *(Array *)mem, 0); } else if (field->type == kObjectTypeDictionary) { - nlua_push_Dictionary(L, *(Dictionary *)mem, false); + nlua_push_Dictionary(L, *(Dictionary *)mem, 0); } else if (field->type == kObjectTypeLuaRef) { nlua_pushref(L, *(LuaRef *)mem); } else { diff --git a/src/nvim/lua/converter.h b/src/nvim/lua/converter.h index a502df80d9..d1ba61bcee 100644 --- a/src/nvim/lua/converter.h +++ b/src/nvim/lua/converter.h @@ -9,6 +9,12 @@ #define nlua_pop_Window nlua_pop_handle #define nlua_pop_Tabpage nlua_pop_handle +/// Flags for nlua_push_*() functions. +enum { + kNluaPushSpecial = 0x01, ///< Use lua-special-tbl when necessary + kNluaPushFreeRefs = 0x02, ///< Free luarefs to elide an api_luarefs_free_*() later +}; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/converter.h.generated.h" #endif diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 1a9bd026b5..a76b8213e5 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -103,7 +103,7 @@ typedef struct { if (args[i].v_type == VAR_UNKNOWN) { \ lua_pushnil(lstate); \ } else { \ - nlua_push_typval(lstate, &args[i], special); \ + nlua_push_typval(lstate, &args[i], (special) ? kNluaPushSpecial : 0); \ } \ } @@ -325,7 +325,7 @@ static int nlua_thr_api_nvim__get_runtime(lua_State *lstate) } ArrayOf(String) ret = runtime_get_named_thread(is_lua, pat, all); - nlua_push_Array(lstate, ret, true); + nlua_push_Array(lstate, ret, kNluaPushSpecial); api_free_array(ret); api_free_array(pat); @@ -1210,7 +1210,7 @@ int nlua_call(lua_State *lstate) }); if (!ERROR_SET(&err)) { - nlua_push_typval(lstate, &rettv, false); + nlua_push_typval(lstate, &rettv, 0); } tv_clear(&rettv); @@ -1261,7 +1261,7 @@ static int nlua_rpc(lua_State *lstate, bool request) ArenaMem res_mem = NULL; Object result = rpc_send_call(chan_id, name, args, &res_mem, &err); if (!ERROR_SET(&err)) { - nlua_push_Object(lstate, &result, false); + nlua_push_Object(lstate, &result, 0); arena_mem_free(res_mem); } } else { @@ -1487,7 +1487,7 @@ static void nlua_typval_exec(const char *lcmd, size_t lcmd_len, const char *name } } -int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) +void nlua_source_str(const char *code, char *name) { const sctx_T save_current_sctx = current_sctx; current_sctx.sc_sid = SID_STR; @@ -1495,22 +1495,11 @@ int nlua_source_using_linegetter(LineGetter fgetline, void *cookie, char *name) current_sctx.sc_lnum = 0; estack_push(ETYPE_SCRIPT, name, 0); - garray_T ga; - char *line = NULL; - - 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); nlua_typval_exec(code, len, name, NULL, 0, false, NULL); estack_pop(); current_sctx = save_current_sctx; - ga_clear_strings(&ga); - xfree(code); - return OK; } /// Call a LuaCallable given some typvals @@ -1564,7 +1553,7 @@ Object nlua_exec(const String str, const Array args, LuaRetMode mode, Arena *are } for (size_t i = 0; i < args.size; i++) { - nlua_push_Object(lstate, &args.items[i], false); + nlua_push_Object(lstate, &args.items[i], 0); } if (nlua_pcall(lstate, (int)args.size, 1)) { @@ -1611,7 +1600,7 @@ Object nlua_call_ref(LuaRef ref, const char *name, Array args, LuaRetMode mode, nargs++; } for (size_t i = 0; i < args.size; i++) { - nlua_push_Object(lstate, &args.items[i], false); + nlua_push_Object(lstate, &args.items[i], 0); } if (nlua_pcall(lstate, nargs, 1)) { @@ -1767,7 +1756,7 @@ void ex_luado(exarg_T *const eap) lua_pushvalue(lstate, -1); const char *const old_line = ml_get_buf(curbuf, l); // Get length of old_line here as calling Lua code may free it. - const size_t old_line_len = strlen(old_line); + const colnr_T old_line_len = ml_get_buf_len(curbuf, l); lua_pushstring(lstate, old_line); lua_pushnumber(lstate, (lua_Number)l); if (nlua_pcall(lstate, 2, 1)) { @@ -1791,13 +1780,13 @@ void ex_luado(exarg_T *const eap) } } ml_replace(l, new_line_transformed, false); - inserted_bytes(l, 0, (int)old_line_len, (int)new_line_len); + inserted_bytes(l, 0, old_line_len, (int)new_line_len); } lua_pop(lstate, 1); } lua_pop(lstate, 1); - check_cursor(); + check_cursor(curwin); redraw_curbuf_later(UPD_NOT_VALID); } @@ -1909,6 +1898,9 @@ static void nlua_add_treesitter(lua_State *const lstate) FUNC_ATTR_NONNULL_ALL lua_pushcfunction(lstate, tslua_push_parser); lua_setfield(lstate, -2, "_create_ts_parser"); + lua_pushcfunction(lstate, tslua_push_querycursor); + lua_setfield(lstate, -2, "_create_ts_querycursor"); + lua_pushcfunction(lstate, tslua_add_language); lua_setfield(lstate, -2, "_ts_add_language"); @@ -2061,9 +2053,9 @@ char *nlua_register_table_as_callable(const typval_T *const arg) return name; } -void nlua_execute_on_key(int c) +void nlua_execute_on_key(int c, char *typed_buf, size_t typed_len) { - char buf[NUMBUFLEN]; + char buf[MB_MAXBYTES * 3 + 4]; size_t buf_len = special_to_buf(c, mod_mask, false, buf); lua_State *const lstate = global_lstate; @@ -2082,9 +2074,12 @@ void nlua_execute_on_key(int c) // [ vim, vim._on_key, buf ] lua_pushlstring(lstate, buf, buf_len); + // [ vim, vim._on_key, buf, typed_buf ] + lua_pushlstring(lstate, typed_buf, typed_len); + int save_got_int = got_int; got_int = false; // avoid interrupts when the key typed is Ctrl-C - if (nlua_pcall(lstate, 1, 0)) { + if (nlua_pcall(lstate, 2, 0)) { nlua_error(lstate, _("Error executing vim.on_key Lua callback: %.*s")); } diff --git a/src/nvim/lua/executor.h b/src/nvim/lua/executor.h index ebcd62122f..32fde3853b 100644 --- a/src/nvim/lua/executor.h +++ b/src/nvim/lua/executor.h @@ -12,7 +12,7 @@ #include "nvim/types_defs.h" #include "nvim/usercmd.h" // IWYU pragma: keep -// Generated by msgpack-gen.lua +// Generated by generators/gen_api_dispatch.lua void nlua_add_api_functions(lua_State *lstate) REAL_FATTR_NONNULL_ALL; typedef struct { @@ -43,7 +43,7 @@ typedef enum { kRetLuaref, ///< return value becomes a single Luaref, regardless of type (except NIL) } LuaRetMode; -/// To use with kRetNilBool for quick thuthyness check +/// To use with kRetNilBool for quick truthiness check #define LUARET_TRUTHY(res) ((res).type == kObjectTypeBoolean && (res).data.boolean == true) #ifdef INCLUDE_GENERATED_DECLARATIONS diff --git a/src/nvim/lua/stdlib.c b/src/nvim/lua/stdlib.c index 8f58fd1a1a..22ee0a1c98 100644 --- a/src/nvim/lua/stdlib.c +++ b/src/nvim/lua/stdlib.c @@ -107,15 +107,15 @@ static int regex_match_line(lua_State *lstate) } char *line = ml_get_buf(buf, rownr + 1); - size_t len = strlen(line); + colnr_T len = ml_get_buf_len(buf, rownr + 1); - if (start < 0 || (size_t)start > len) { + if (start < 0 || start > len) { return luaL_error(lstate, "invalid start"); } char save = NUL; if (end >= 0) { - if ((size_t)end > len || end < start) { + if (end > len || end < start) { return luaL_error(lstate, "invalid end"); } save = line[end]; @@ -449,7 +449,7 @@ int nlua_getvar(lua_State *lstate) if (di == NULL) { return 0; // nil } - nlua_push_typval(lstate, &di->di_tv, false); + nlua_push_typval(lstate, &di->di_tv, 0); return 1; } @@ -543,14 +543,27 @@ static int nlua_iconv(lua_State *lstate) return 1; } -// Update foldlevels (e.g., by evaluating 'foldexpr') for all lines in the current window without -// invoking other side effects. Unlike `zx`, it does not close manually opened folds and does not -// open folds under the cursor. +// Update foldlevels (e.g., by evaluating 'foldexpr') for the given line range in the given window, +// without invoking other side effects. Unlike `zx`, it does not close manually opened folds and +// does not open folds under the cursor. static int nlua_foldupdate(lua_State *lstate) { - curwin->w_foldinvalid = true; // recompute folds - foldUpdate(curwin, 1, (linenr_T)MAXLNUM); - curwin->w_foldinvalid = false; + handle_T window = (handle_T)luaL_checkinteger(lstate, 1); + win_T *win = handle_get_window(window); + if (!win) { + return luaL_error(lstate, "invalid window"); + } + // input is zero-based end-exclusive range + linenr_T top = (linenr_T)luaL_checkinteger(lstate, 2) + 1; + if (top < 1 || top > win->w_buffer->b_ml.ml_line_count) { + return luaL_error(lstate, "invalid top"); + } + linenr_T bot = (linenr_T)luaL_checkinteger(lstate, 3); + if (top > bot) { + return luaL_error(lstate, "invalid bot"); + } + + foldUpdate(win, top, bot); return 0; } diff --git a/src/nvim/lua/treesitter.c b/src/nvim/lua/treesitter.c index 25a753b179..e87cf756a8 100644 --- a/src/nvim/lua/treesitter.c +++ b/src/nvim/lua/treesitter.c @@ -33,15 +33,10 @@ #define TS_META_NODE "treesitter_node" #define TS_META_QUERY "treesitter_query" #define TS_META_QUERYCURSOR "treesitter_querycursor" +#define TS_META_QUERYMATCH "treesitter_querymatch" #define TS_META_TREECURSOR "treesitter_treecursor" typedef struct { - TSQueryCursor *cursor; - int predicated_match; - int max_match_id; -} TSLua_cursor; - -typedef struct { LuaRef cb; lua_State *lstate; bool lex; @@ -56,126 +51,44 @@ typedef struct { # include "lua/treesitter.c.generated.h" #endif -// TSParser -static struct luaL_Reg parser_meta[] = { - { "__gc", parser_gc }, - { "__tostring", parser_tostring }, - { "parse", parser_parse }, - { "reset", parser_reset }, - { "set_included_ranges", parser_set_ranges }, - { "included_ranges", parser_get_ranges }, - { "set_timeout", parser_set_timeout }, - { "timeout", parser_get_timeout }, - { "_set_logger", parser_set_logger }, - { "_logger", parser_get_logger }, - { NULL, NULL } -}; - -// TSTree -static struct luaL_Reg tree_meta[] = { - { "__gc", tree_gc }, - { "__tostring", tree_tostring }, - { "root", tree_root }, - { "edit", tree_edit }, - { "included_ranges", tree_get_ranges }, - { "copy", tree_copy }, - { NULL, NULL } -}; - -// TSNode -static struct luaL_Reg node_meta[] = { - { "__tostring", node_tostring }, - { "__eq", node_eq }, - { "__len", node_child_count }, - { "id", node_id }, - { "range", node_range }, - { "start", node_start }, - { "end_", node_end }, - { "type", node_type }, - { "symbol", node_symbol }, - { "field", node_field }, - { "named", node_named }, - { "missing", node_missing }, - { "extra", node_extra }, - { "has_changes", node_has_changes }, - { "has_error", node_has_error }, - { "sexpr", node_sexpr }, - { "child_count", node_child_count }, - { "named_child_count", node_named_child_count }, - { "child", node_child }, - { "named_child", node_named_child }, - { "descendant_for_range", node_descendant_for_range }, - { "named_descendant_for_range", node_named_descendant_for_range }, - { "parent", node_parent }, - { "iter_children", node_iter_children }, - { "_rawquery", node_rawquery }, - { "next_sibling", node_next_sibling }, - { "prev_sibling", node_prev_sibling }, - { "next_named_sibling", node_next_named_sibling }, - { "prev_named_sibling", node_prev_named_sibling }, - { "named_children", node_named_children }, - { "root", node_root }, - { "tree", node_tree }, - { "byte_length", node_byte_length }, - { "equal", node_equal }, - - { NULL, NULL } -}; - -// TSQuery -static struct luaL_Reg query_meta[] = { - { "__gc", query_gc }, - { "__tostring", query_tostring }, - { "inspect", query_inspect }, - { NULL, NULL } -}; +static PMap(cstr_t) langs = MAP_INIT; -// cursors are not exposed, but still needs garbage collection -static struct luaL_Reg querycursor_meta[] = { - { "__gc", querycursor_gc }, - { NULL, NULL } -}; +// TSLanguage -static struct luaL_Reg treecursor_meta[] = { - { "__gc", treecursor_gc }, - { NULL, NULL } -}; - -static kvec_t(TSQueryCursor *) cursors = KV_INITIAL_VALUE; -static PMap(cstr_t) langs = MAP_INIT; +int tslua_has_language(lua_State *L) +{ + const char *lang_name = luaL_checkstring(L, 1); + lua_pushboolean(L, map_has(cstr_t, &langs, lang_name)); + return 1; +} -static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) +static TSLanguage *load_language(lua_State *L, const char *path, const char *lang_name, + const char *symbol) { - if (luaL_newmetatable(L, tname)) { // [meta] - luaL_register(L, NULL, meta); + uv_lib_t lib; + if (uv_dlopen(path, &lib)) { + uv_dlclose(&lib); + luaL_error(L, "Failed to load parser for language '%s': uv_dlopen: %s", + lang_name, uv_dlerror(&lib)); + } - lua_pushvalue(L, -1); // [meta, meta] - lua_setfield(L, -2, "__index"); // [meta] + char symbol_buf[128]; + snprintf(symbol_buf, sizeof(symbol_buf), "tree_sitter_%s", symbol); + + TSLanguage *(*lang_parser)(void); + if (uv_dlsym(&lib, symbol_buf, (void **)&lang_parser)) { + uv_dlclose(&lib); + luaL_error(L, "Failed to load parser: uv_dlsym: %s", uv_dlerror(&lib)); } - lua_pop(L, 1); // [] (don't use it now) -} -/// Init the tslua library. -/// -/// All global state is stored in the registry of the lua_State. -void tslua_init(lua_State *L) -{ - // type metatables - build_meta(L, TS_META_PARSER, parser_meta); - build_meta(L, TS_META_TREE, tree_meta); - build_meta(L, TS_META_NODE, node_meta); - build_meta(L, TS_META_QUERY, query_meta); - build_meta(L, TS_META_QUERYCURSOR, querycursor_meta); - build_meta(L, TS_META_TREECURSOR, treecursor_meta); + TSLanguage *lang = lang_parser(); - ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree); -} + if (lang == NULL) { + uv_dlclose(&lib); + luaL_error(L, "Failed to load parser %s: internal error", path); + } -int tslua_has_language(lua_State *L) -{ - const char *lang_name = luaL_checkstring(L, 1); - lua_pushboolean(L, map_has(cstr_t, &langs, lang_name)); - return 1; + return lang; } // Creates the language into the internal language map. @@ -196,34 +109,7 @@ int tslua_add_language(lua_State *L) return 1; } -#define BUFSIZE 128 - char symbol_buf[BUFSIZE]; - snprintf(symbol_buf, BUFSIZE, "tree_sitter_%s", symbol_name); -#undef BUFSIZE - - uv_lib_t lib; - if (uv_dlopen(path, &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); - } - - TSLanguage *(*lang_parser)(void); - if (uv_dlsym(&lib, symbol_buf, (void **)&lang_parser)) { - snprintf(IObuff, IOSIZE, "Failed to load parser: uv_dlsym: %s", - uv_dlerror(&lib)); - uv_dlclose(&lib); - lua_pushstring(L, IObuff); - return lua_error(L); - } - - TSLanguage *lang = lang_parser(); - if (lang == NULL) { - uv_dlclose(&lib); - return luaL_error(L, "Failed to load parser %s: internal error", path); - } + TSLanguage *lang = load_language(L, path, lang_name, symbol_name); uint32_t lang_version = ts_language_version(lang); if (lang_version < TREE_SITTER_MIN_COMPATIBLE_LANGUAGE_VERSION @@ -254,14 +140,19 @@ int tslua_remove_lang(lua_State *L) return 1; } -int tslua_inspect_lang(lua_State *L) +static TSLanguage *lang_check(lua_State *L, int index) { - const char *lang_name = luaL_checkstring(L, 1); - + const char *lang_name = luaL_checkstring(L, index); TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); if (!lang) { - return luaL_error(L, "no such language: %s", lang_name); + luaL_error(L, "no such language: %s", lang_name); } + return lang; +} + +int tslua_inspect_lang(lua_State *L) +{ + TSLanguage *lang = lang_check(L, 1); lua_createtable(L, 0, 2); // [retval] @@ -295,28 +186,38 @@ int tslua_inspect_lang(lua_State *L) lua_setfield(L, -2, "fields"); // [retval] - uint32_t lang_version = ts_language_version(lang); - lua_pushinteger(L, lang_version); // [retval, version] + lua_pushinteger(L, ts_language_version(lang)); // [retval, version] lua_setfield(L, -2, "_abi_version"); return 1; } +// TSParser + +static struct luaL_Reg parser_meta[] = { + { "__gc", parser_gc }, + { "__tostring", parser_tostring }, + { "parse", parser_parse }, + { "reset", parser_reset }, + { "set_included_ranges", parser_set_ranges }, + { "included_ranges", parser_get_ranges }, + { "set_timeout", parser_set_timeout }, + { "timeout", parser_get_timeout }, + { "_set_logger", parser_set_logger }, + { "_logger", parser_get_logger }, + { NULL, NULL } +}; + int tslua_push_parser(lua_State *L) { - // Gather language name - const char *lang_name = luaL_checkstring(L, 1); - - TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); - if (!lang) { - return luaL_error(L, "no such language: %s", lang_name); - } + TSLanguage *lang = lang_check(L, 1); TSParser **parser = lua_newuserdata(L, sizeof(TSParser *)); *parser = ts_parser_new(); if (!ts_parser_set_language(*parser, lang)) { ts_parser_delete(*parser); + const char *lang_name = luaL_checkstring(L, 1); return luaL_error(L, "Failed to load language : %s", lang_name); } @@ -325,9 +226,11 @@ int tslua_push_parser(lua_State *L) return 1; } -static TSParser **parser_check(lua_State *L, uint16_t index) +static TSParser *parser_check(lua_State *L, uint16_t index) { - return luaL_checkudata(L, index, TS_META_PARSER); + TSParser **ud = luaL_checkudata(L, index, TS_META_PARSER); + luaL_argcheck(L, *ud, index, "TSParser expected"); + return *ud; } static void logger_gc(TSLogger logger) @@ -343,13 +246,9 @@ static void logger_gc(TSLogger logger) static int parser_gc(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } - - logger_gc(ts_parser_logger(*p)); - ts_parser_delete(*p); + TSParser *p = parser_check(L, 1); + logger_gc(ts_parser_logger(p)); + ts_parser_delete(p); return 0; } @@ -371,7 +270,7 @@ static const char *input_cb(void *payload, uint32_t byte_index, TSPoint position return ""; } char *line = ml_get_buf(bp, (linenr_T)position.row + 1); - size_t len = strlen(line); + size_t len = (size_t)ml_get_buf_len(bp, (linenr_T)position.row + 1); if (position.column > len) { *bytes_read = 0; return ""; @@ -422,14 +321,10 @@ static void push_ranges(lua_State *L, const TSRange *ranges, const size_t length static int parser_parse(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p || !(*p)) { - return 0; - } - + TSParser *p = parser_check(L, 1); TSTree *old_tree = NULL; if (!lua_isnil(L, 2)) { - TSLuaTree *ud = tree_check(L, 2); + TSLuaTree *ud = luaL_checkudata(L, 2, TS_META_TREE); old_tree = ud ? ud->tree : NULL; } @@ -445,7 +340,7 @@ static int parser_parse(lua_State *L) switch (lua_type(L, 3)) { case LUA_TSTRING: str = lua_tolstring(L, 3, &len); - new_tree = ts_parser_parse_string(*p, old_tree, str, (uint32_t)len); + new_tree = ts_parser_parse_string(p, old_tree, str, (uint32_t)len); break; case LUA_TNUMBER: @@ -461,7 +356,7 @@ static int parser_parse(lua_State *L) } input = (TSInput){ (void *)buf, input_cb, TSInputEncodingUTF8 }; - new_tree = ts_parser_parse(*p, old_tree, input); + new_tree = ts_parser_parse(p, old_tree, input); break; @@ -492,70 +387,14 @@ static int parser_parse(lua_State *L) static int parser_reset(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (p && *p) { - ts_parser_reset(*p); - } - + TSParser *p = parser_check(L, 1); + ts_parser_reset(p); return 0; } -static int tree_copy(lua_State *L) +static void range_err(lua_State *L) { - TSLuaTree *ud = tree_check(L, 1); - if (!ud) { - return 0; - } - - TSTree *copy = ts_tree_copy(ud->tree); - push_tree(L, copy); // [tree] - - return 1; -} - -static int tree_edit(lua_State *L) -{ - if (lua_gettop(L) < 10) { - lua_pushstring(L, "not enough args to tree:edit()"); - return lua_error(L); - } - - TSLuaTree *ud = tree_check(L, 1); - if (!ud) { - return 0; - } - - uint32_t start_byte = (uint32_t)luaL_checkint(L, 2); - uint32_t old_end_byte = (uint32_t)luaL_checkint(L, 3); - uint32_t new_end_byte = (uint32_t)luaL_checkint(L, 4); - TSPoint start_point = { (uint32_t)luaL_checkint(L, 5), (uint32_t)luaL_checkint(L, 6) }; - TSPoint old_end_point = { (uint32_t)luaL_checkint(L, 7), (uint32_t)luaL_checkint(L, 8) }; - TSPoint new_end_point = { (uint32_t)luaL_checkint(L, 9), (uint32_t)luaL_checkint(L, 10) }; - - TSInputEdit edit = { start_byte, old_end_byte, new_end_byte, - start_point, old_end_point, new_end_point }; - - ts_tree_edit(ud->tree, &edit); - - return 0; -} - -static int tree_get_ranges(lua_State *L) -{ - TSLuaTree *ud = tree_check(L, 1); - if (!ud) { - return 0; - } - - bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); - - uint32_t len; - TSRange *ranges = ts_tree_included_ranges(ud->tree, &len); - - push_ranges(L, ranges, len, include_bytes); - - xfree(ranges); - return 1; + luaL_error(L, "Ranges can only be made from 6 element long tables or nodes."); } // Use the top of the stack (without popping it) to create a TSRange, it can be @@ -567,7 +406,7 @@ static void range_from_lua(lua_State *L, TSRange *range) if (lua_istable(L, -1)) { // should be a table of 6 elements if (lua_objlen(L, -1) != 6) { - goto error; + range_err(L); } lua_rawgeti(L, -1, 1); // [ range, start_row] @@ -606,7 +445,7 @@ static void range_from_lua(lua_State *L, TSRange *range) .start_byte = start_byte, .end_byte = end_byte, }; - } else if (node_check(L, -1, &node)) { + } else if (node_check_opt(L, -1, &node)) { *range = (TSRange) { .start_point = ts_node_start_point(node), .end_point = ts_node_end_point(node), @@ -614,30 +453,19 @@ static void range_from_lua(lua_State *L, TSRange *range) .end_byte = ts_node_end_byte(node) }; } else { - goto error; + range_err(L); } - return; -error: - luaL_error(L, - "Ranges can only be made from 6 element long tables or nodes."); } static int parser_set_ranges(lua_State *L) { if (lua_gettop(L) < 2) { - return luaL_error(L, - "not enough args to parser:set_included_ranges()"); + return luaL_error(L, "not enough args to parser:set_included_ranges()"); } - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } + TSParser *p = parser_check(L, 1); - if (!lua_istable(L, 2)) { - return luaL_error(L, - "argument for parser:set_included_ranges() should be a table."); - } + luaL_argcheck(L, lua_istable(L, 2), 2, "table expected."); size_t tbl_len = lua_objlen(L, 2); TSRange *ranges = xmalloc(sizeof(TSRange) * tbl_len); @@ -650,7 +478,7 @@ static int parser_set_ranges(lua_State *L) } // This memcpies ranges, thus we can free it afterwards - ts_parser_set_included_ranges(*p, ranges, (uint32_t)tbl_len); + ts_parser_set_included_ranges(p, ranges, (uint32_t)tbl_len); xfree(ranges); return 0; @@ -658,15 +486,12 @@ static int parser_set_ranges(lua_State *L) static int parser_get_ranges(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } + TSParser *p = parser_check(L, 1); bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); uint32_t len; - const TSRange *ranges = ts_parser_included_ranges(*p, &len); + const TSRange *ranges = ts_parser_included_ranges(p, &len); push_ranges(L, ranges, len, include_bytes); return 1; @@ -674,28 +499,21 @@ static int parser_get_ranges(lua_State *L) static int parser_set_timeout(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } + TSParser *p = parser_check(L, 1); if (lua_gettop(L) < 2) { luaL_error(L, "integer expected"); } uint32_t timeout = (uint32_t)luaL_checkinteger(L, 2); - ts_parser_set_timeout_micros(*p, timeout); + ts_parser_set_timeout_micros(p, timeout); return 0; } static int parser_get_timeout(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } - - lua_pushinteger(L, (lua_Integer)ts_parser_timeout_micros(*p)); + TSParser *p = parser_check(L, 1); + lua_pushinteger(L, (lua_Integer)ts_parser_timeout_micros(p)); return 1; } @@ -719,22 +537,11 @@ static void logger_cb(void *payload, TSLogType logtype, const char *s) static int parser_set_logger(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } + TSParser *p = parser_check(L, 1); - if (!lua_isboolean(L, 2)) { - return luaL_argerror(L, 2, "boolean expected"); - } - - if (!lua_isboolean(L, 3)) { - return luaL_argerror(L, 3, "boolean expected"); - } - - if (!lua_isfunction(L, 4)) { - return luaL_argerror(L, 4, "function expected"); - } + luaL_argcheck(L, lua_isboolean(L, 2), 2, "boolean expected"); + luaL_argcheck(L, lua_isboolean(L, 3), 3, "boolean expected"); + luaL_argcheck(L, lua_isfunction(L, 4), 4, "function expected"); TSLuaLoggerOpts *opts = xmalloc(sizeof(TSLuaLoggerOpts)); lua_pushvalue(L, 4); @@ -752,18 +559,14 @@ static int parser_set_logger(lua_State *L) .log = logger_cb }; - ts_parser_set_logger(*p, logger); + ts_parser_set_logger(p, logger); return 0; } static int parser_get_logger(lua_State *L) { - TSParser **p = parser_check(L, 1); - if (!p) { - return 0; - } - - TSLogger logger = ts_parser_logger(*p); + TSParser *p = parser_check(L, 1); + TSLogger logger = ts_parser_logger(p); if (logger.log) { TSLuaLoggerOpts *opts = (TSLuaLoggerOpts *)logger.payload; lua_rawgeti(L, LUA_REGISTRYINDEX, opts->cb); @@ -774,7 +577,17 @@ static int parser_get_logger(lua_State *L) return 1; } -// Tree methods +// TSTree + +static struct luaL_Reg tree_meta[] = { + { "__gc", tree_gc }, + { "__tostring", tree_tostring }, + { "root", tree_root }, + { "edit", tree_edit }, + { "included_ranges", tree_get_ranges }, + { "copy", tree_copy }, + { NULL, NULL } +}; /// Push tree interface on to the lua stack. /// @@ -804,18 +617,58 @@ static void push_tree(lua_State *L, TSTree *tree) lua_setfenv(L, -2); // [udata] } -static TSLuaTree *tree_check(lua_State *L, int index) +static int tree_copy(lua_State *L) { - TSLuaTree *ud = luaL_checkudata(L, index, TS_META_TREE); - return ud; + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); + TSTree *copy = ts_tree_copy(ud->tree); + push_tree(L, copy); // [tree] + + return 1; } -static int tree_gc(lua_State *L) +static int tree_edit(lua_State *L) { - TSLuaTree *ud = tree_check(L, 1); - if (ud) { - ts_tree_delete(ud->tree); + if (lua_gettop(L) < 10) { + lua_pushstring(L, "not enough args to tree:edit()"); + return lua_error(L); } + + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); + + uint32_t start_byte = (uint32_t)luaL_checkint(L, 2); + uint32_t old_end_byte = (uint32_t)luaL_checkint(L, 3); + uint32_t new_end_byte = (uint32_t)luaL_checkint(L, 4); + TSPoint start_point = { (uint32_t)luaL_checkint(L, 5), (uint32_t)luaL_checkint(L, 6) }; + TSPoint old_end_point = { (uint32_t)luaL_checkint(L, 7), (uint32_t)luaL_checkint(L, 8) }; + TSPoint new_end_point = { (uint32_t)luaL_checkint(L, 9), (uint32_t)luaL_checkint(L, 10) }; + + TSInputEdit edit = { start_byte, old_end_byte, new_end_byte, + start_point, old_end_point, new_end_point }; + + ts_tree_edit(ud->tree, &edit); + + return 0; +} + +static int tree_get_ranges(lua_State *L) +{ + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); + + bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); + + uint32_t len; + TSRange *ranges = ts_tree_included_ranges(ud->tree, &len); + + push_ranges(L, ranges, len, include_bytes); + + xfree(ranges); + return 1; +} + +static int tree_gc(lua_State *L) +{ + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); + ts_tree_delete(ud->tree); return 0; } @@ -827,16 +680,66 @@ static int tree_tostring(lua_State *L) static int tree_root(lua_State *L) { - TSLuaTree *ud = tree_check(L, 1); - if (!ud) { - return 0; - } + TSLuaTree *ud = luaL_checkudata(L, 1, TS_META_TREE); TSNode root = ts_tree_root_node(ud->tree); push_node(L, root, 1); return 1; } -// Node methods +// TSTreeCursor + +static struct luaL_Reg treecursor_meta[] = { + { "__gc", treecursor_gc }, + { NULL, NULL } +}; + +static int treecursor_gc(lua_State *L) +{ + TSTreeCursor *cursor = luaL_checkudata(L, 1, TS_META_TREECURSOR); + ts_tree_cursor_delete(cursor); + return 0; +} + +// TSNode +static struct luaL_Reg node_meta[] = { + { "__tostring", node_tostring }, + { "__eq", node_eq }, + { "__len", node_child_count }, + { "id", node_id }, + { "range", node_range }, + { "start", node_start }, + { "end_", node_end }, + { "type", node_type }, + { "symbol", node_symbol }, + { "field", node_field }, + { "named", node_named }, + { "missing", node_missing }, + { "extra", node_extra }, + { "has_changes", node_has_changes }, + { "has_error", node_has_error }, + { "sexpr", node_sexpr }, + { "child_count", node_child_count }, + { "named_child_count", node_named_child_count }, + { "child", node_child }, + { "named_child", node_named_child }, + { "descendant_for_range", node_descendant_for_range }, + { "named_descendant_for_range", node_named_descendant_for_range }, + { "parent", node_parent }, + { "__has_ancestor", __has_ancestor }, + { "child_containing_descendant", node_child_containing_descendant }, + { "iter_children", node_iter_children }, + { "next_sibling", node_next_sibling }, + { "prev_sibling", node_prev_sibling }, + { "next_named_sibling", node_next_named_sibling }, + { "prev_named_sibling", node_prev_named_sibling }, + { "named_children", node_named_children }, + { "root", node_root }, + { "tree", node_tree }, + { "byte_length", node_byte_length }, + { "equal", node_equal }, + + { NULL, NULL } +}; /// Push node interface on to the Lua stack /// @@ -860,7 +763,7 @@ static void push_node(lua_State *L, TSNode node, int uindex) lua_setfenv(L, -2); // [udata] } -static bool node_check(lua_State *L, int index, TSNode *res) +static bool node_check_opt(lua_State *L, int index, TSNode *res) { TSNode *ud = luaL_checkudata(L, index, TS_META_NODE); if (ud) { @@ -870,12 +773,15 @@ static bool node_check(lua_State *L, int index, TSNode *res) return false; } +static TSNode node_check(lua_State *L, int index) +{ + TSNode *ud = luaL_checkudata(L, index, TS_META_NODE); + return *ud; +} + static int node_tostring(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushstring(L, "<node "); lua_pushstring(L, ts_node_type(node)); lua_pushstring(L, ">"); @@ -885,37 +791,22 @@ static int node_tostring(lua_State *L) static int node_eq(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - - TSNode node2; - if (!node_check(L, 2, &node2)) { - return 0; - } - + TSNode node = node_check(L, 1); + TSNode node2 = node_check(L, 2); lua_pushboolean(L, ts_node_eq(node, node2)); return 1; } static int node_id(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - + TSNode node = node_check(L, 1); lua_pushlstring(L, (const char *)&node.id, sizeof node.id); return 1; } static int node_range(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); bool include_bytes = (lua_gettop(L) >= 2) && lua_toboolean(L, 2); @@ -941,10 +832,7 @@ static int node_range(lua_State *L) static int node_start(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSPoint start = ts_node_start_point(node); uint32_t start_byte = ts_node_start_byte(node); lua_pushinteger(L, start.row); @@ -955,10 +843,7 @@ static int node_start(lua_State *L) static int node_end(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSPoint end = ts_node_end_point(node); uint32_t end_byte = ts_node_end_byte(node); lua_pushinteger(L, end.row); @@ -969,10 +854,7 @@ static int node_end(lua_State *L) static int node_child_count(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); uint32_t count = ts_node_child_count(node); lua_pushinteger(L, count); return 1; @@ -980,10 +862,7 @@ static int node_child_count(lua_State *L) static int node_named_child_count(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); uint32_t count = ts_node_named_child_count(node); lua_pushinteger(L, count); return 1; @@ -991,20 +870,14 @@ static int node_named_child_count(lua_State *L) static int node_type(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushstring(L, ts_node_type(node)); return 1; } static int node_symbol(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSSymbol symbol = ts_node_symbol(node); lua_pushinteger(L, symbol); return 1; @@ -1012,10 +885,7 @@ static int node_symbol(lua_State *L) static int node_field(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); size_t name_len; const char *field_name = luaL_checklstring(L, 2, &name_len); @@ -1042,20 +912,14 @@ static int node_field(lua_State *L) static int node_named(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_is_named(node)); return 1; } static int node_sexpr(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); char *allocated = ts_node_string(node); lua_pushstring(L, allocated); xfree(allocated); @@ -1064,50 +928,35 @@ static int node_sexpr(lua_State *L) static int node_missing(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_is_missing(node)); return 1; } static int node_extra(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_is_extra(node)); return 1; } static int node_has_changes(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_has_changes(node)); return 1; } static int node_has_error(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); lua_pushboolean(L, ts_node_has_error(node)); return 1; } static int node_child(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); uint32_t num = (uint32_t)lua_tointeger(L, 2); TSNode child = ts_node_child(node, num); @@ -1117,10 +966,7 @@ static int node_child(lua_State *L) static int node_named_child(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); uint32_t num = (uint32_t)lua_tointeger(L, 2); TSNode child = ts_node_named_child(node, num); @@ -1130,10 +976,7 @@ static int node_named_child(lua_State *L) static int node_descendant_for_range(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSPoint start = { (uint32_t)lua_tointeger(L, 2), (uint32_t)lua_tointeger(L, 3) }; TSPoint end = { (uint32_t)lua_tointeger(L, 4), @@ -1146,10 +989,7 @@ static int node_descendant_for_range(lua_State *L) static int node_named_descendant_for_range(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSPoint start = { (uint32_t)lua_tointeger(L, 2), (uint32_t)lua_tointeger(L, 3) }; TSPoint end = { (uint32_t)lua_tointeger(L, 4), @@ -1162,54 +1002,41 @@ static int node_named_descendant_for_range(lua_State *L) static int node_next_child(lua_State *L) { - TSTreeCursor *ud = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR); - if (!ud) { - return 0; - } - - TSNode source; - if (!node_check(L, lua_upvalueindex(2), &source)) { - return 0; - } + TSTreeCursor *cursor = luaL_checkudata(L, lua_upvalueindex(1), TS_META_TREECURSOR); + TSNode source = node_check(L, lua_upvalueindex(2)); // First call should return first child - if (ts_node_eq(source, ts_tree_cursor_current_node(ud))) { - if (ts_tree_cursor_goto_first_child(ud)) { + if (ts_node_eq(source, ts_tree_cursor_current_node(cursor))) { + if (ts_tree_cursor_goto_first_child(cursor)) { goto push; } else { - goto end; + return 0; } } - if (ts_tree_cursor_goto_next_sibling(ud)) { -push: - push_node(L, - ts_tree_cursor_current_node(ud), - lua_upvalueindex(2)); // [node] + if (!ts_tree_cursor_goto_next_sibling(cursor)) { + return 0; + } - const char *field = ts_tree_cursor_current_field_name(ud); +push: + push_node(L, ts_tree_cursor_current_node(cursor), lua_upvalueindex(2)); // [node] - if (field != NULL) { - lua_pushstring(L, ts_tree_cursor_current_field_name(ud)); - } else { - lua_pushnil(L); - } // [node, field_name_or_nil] - return 2; - } + const char *field = ts_tree_cursor_current_field_name(cursor); -end: - return 0; + if (field != NULL) { + lua_pushstring(L, ts_tree_cursor_current_field_name(cursor)); + } else { + lua_pushnil(L); + } // [node, field_name_or_nil] + return 2; } static int node_iter_children(lua_State *L) { - TSNode source; - if (!node_check(L, 1, &source)) { - return 0; - } + TSNode node = node_check(L, 1); TSTreeCursor *ud = lua_newuserdata(L, sizeof(TSTreeCursor)); // [udata] - *ud = ts_tree_cursor_new(source); + *ud = ts_tree_cursor_new(node); lua_getfield(L, LUA_REGISTRYINDEX, TS_META_TREECURSOR); // [udata, mt] lua_setmetatable(L, -2); // [udata] @@ -1219,30 +1046,60 @@ static int node_iter_children(lua_State *L) return 1; } -static int treecursor_gc(lua_State *L) +static int node_parent(lua_State *L) { - TSTreeCursor *ud = luaL_checkudata(L, 1, TS_META_TREECURSOR); - ts_tree_cursor_delete(ud); - return 0; + TSNode node = node_check(L, 1); + TSNode parent = ts_node_parent(node); + push_node(L, parent, 1); + return 1; } -static int node_parent(lua_State *L) +static int __has_ancestor(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; + TSNode descendant = node_check(L, 1); + if (lua_type(L, 2) != LUA_TTABLE) { + lua_pushboolean(L, false); + return 1; } - TSNode parent = ts_node_parent(node); - push_node(L, parent, 1); + int const pred_len = (int)lua_objlen(L, 2); + + TSNode node = ts_tree_root_node(descendant.tree); + while (!ts_node_is_null(node)) { + char const *node_type = ts_node_type(node); + size_t node_type_len = strlen(node_type); + + for (int i = 3; i <= pred_len; i++) { + lua_rawgeti(L, 2, i); + if (lua_type(L, -1) == LUA_TSTRING) { + size_t check_len; + char const *check_str = lua_tolstring(L, -1, &check_len); + if (node_type_len == check_len && memcmp(node_type, check_str, check_len) == 0) { + lua_pushboolean(L, true); + return 1; + } + } + lua_pop(L, 1); + } + + node = ts_node_child_containing_descendant(node, descendant); + } + + lua_pushboolean(L, false); + return 1; +} + +static int node_child_containing_descendant(lua_State *L) +{ + TSNode node = node_check(L, 1); + TSNode descendant = node_check(L, 2); + TSNode child = ts_node_child_containing_descendant(node, descendant); + push_node(L, child, 1); return 1; } static int node_next_sibling(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSNode sibling = ts_node_next_sibling(node); push_node(L, sibling, 1); return 1; @@ -1250,10 +1107,7 @@ static int node_next_sibling(lua_State *L) static int node_prev_sibling(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSNode sibling = ts_node_prev_sibling(node); push_node(L, sibling, 1); return 1; @@ -1261,10 +1115,7 @@ static int node_prev_sibling(lua_State *L) static int node_next_named_sibling(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSNode sibling = ts_node_next_named_sibling(node); push_node(L, sibling, 1); return 1; @@ -1272,10 +1123,7 @@ static int node_next_named_sibling(lua_State *L) static int node_prev_named_sibling(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } + TSNode node = node_check(L, 1); TSNode sibling = ts_node_prev_named_sibling(node); push_node(L, sibling, 1); return 1; @@ -1283,10 +1131,7 @@ static int node_prev_named_sibling(lua_State *L) static int node_named_children(lua_State *L) { - TSNode source; - if (!node_check(L, 1, &source)) { - return 0; - } + TSNode source = node_check(L, 1); TSTreeCursor cursor = ts_tree_cursor_new(source); lua_newtable(L); @@ -1308,11 +1153,7 @@ static int node_named_children(lua_State *L) static int node_root(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - + TSNode node = node_check(L, 1); TSNode root = ts_tree_root_node(node.tree); push_node(L, root, 1); return 1; @@ -1320,215 +1161,196 @@ static int node_root(lua_State *L) static int node_tree(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - + node_check(L, 1); lua_getfenv(L, 1); // [udata, reftable] lua_rawgeti(L, -1, 1); // [udata, reftable, tree_udata] - return 1; } static int node_byte_length(lua_State *L) { - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } - + TSNode node = node_check(L, 1); uint32_t start_byte = ts_node_start_byte(node); uint32_t end_byte = ts_node_end_byte(node); - lua_pushinteger(L, end_byte - start_byte); return 1; } static int node_equal(lua_State *L) { - TSNode node1; - if (!node_check(L, 1, &node1)) { - return 0; - } - - TSNode node2; - if (!node_check(L, 2, &node2)) { - return luaL_error(L, "TSNode expected"); - } - + TSNode node1 = node_check(L, 1); + TSNode node2 = node_check(L, 2); lua_pushboolean(L, ts_node_eq(node1, node2)); return 1; } -/// assumes the match table being on top of the stack -static void set_match(lua_State *L, TSQueryMatch *match, int nodeidx) -{ - // [match] - for (size_t i = 0; i < match->capture_count; i++) { - lua_rawgeti(L, -1, (int)match->captures[i].index + 1); // [match, captures] - if (lua_isnil(L, -1)) { // [match, nil] - lua_pop(L, 1); // [match] - lua_createtable(L, 1, 0); // [match, captures] - } - push_node(L, match->captures[i].node, nodeidx); // [match, captures, node] - lua_rawseti(L, -2, (int)lua_objlen(L, -2) + 1); // [match, captures] - lua_rawseti(L, -2, (int)match->captures[i].index + 1); // [match] - } -} +// TSQueryCursor -static int query_next_match(lua_State *L) -{ - TSLua_cursor *ud = lua_touserdata(L, lua_upvalueindex(1)); - TSQueryCursor *cursor = ud->cursor; - - TSQuery *query = query_check(L, lua_upvalueindex(3)); - TSQueryMatch match; - if (ts_query_cursor_next_match(cursor, &match)) { - lua_pushinteger(L, match.pattern_index + 1); // [index] - lua_createtable(L, (int)ts_query_capture_count(query), 0); // [index, match] - set_match(L, &match, lua_upvalueindex(2)); - return 2; - } - return 0; -} +static struct luaL_Reg querycursor_meta[] = { + { "remove_match", querycursor_remove_match }, + { "next_capture", querycursor_next_capture }, + { "next_match", querycursor_next_match }, + { "__gc", querycursor_gc }, + { NULL, NULL } +}; -static int query_next_capture(lua_State *L) +int tslua_push_querycursor(lua_State *L) { - // Upvalues are: - // [ cursor, node, query, current_match ] - TSLua_cursor *ud = lua_touserdata(L, lua_upvalueindex(1)); - TSQueryCursor *cursor = ud->cursor; - - TSQuery *query = query_check(L, lua_upvalueindex(3)); - - if (ud->predicated_match > -1) { - lua_getfield(L, lua_upvalueindex(4), "active"); - bool active = lua_toboolean(L, -1); - lua_pop(L, 1); - if (!active) { - ts_query_cursor_remove_match(cursor, (uint32_t)ud->predicated_match); - } - ud->predicated_match = -1; - } + TSNode node = node_check(L, 1); - TSQueryMatch match; - uint32_t capture_index; - if (ts_query_cursor_next_capture(cursor, &match, &capture_index)) { - TSQueryCapture capture = match.captures[capture_index]; - - // TODO(vigoux): handle capture quantifiers here - lua_pushinteger(L, capture.index + 1); // [index] - push_node(L, capture.node, lua_upvalueindex(2)); // [index, node] - - // Now check if we need to run the predicates - uint32_t n_pred; - ts_query_predicates_for_pattern(query, match.pattern_index, &n_pred); - - if (n_pred > 0 && (ud->max_match_id < (int)match.id)) { - ud->max_match_id = (int)match.id; - - // Create a new cleared match table - lua_createtable(L, (int)ts_query_capture_count(query), 2); // [index, node, match] - set_match(L, &match, lua_upvalueindex(2)); - lua_pushinteger(L, match.pattern_index + 1); - lua_setfield(L, -2, "pattern"); - - if (match.capture_count > 1) { - ud->predicated_match = (int)match.id; - lua_pushboolean(L, false); - lua_setfield(L, -2, "active"); - } - - // Set current_match to the new match - lua_replace(L, lua_upvalueindex(4)); // [index, node] - lua_pushvalue(L, lua_upvalueindex(4)); // [index, node, match] - return 3; - } - return 2; - } - return 0; -} - -static int node_rawquery(lua_State *L) -{ - TSNode node; - if (!node_check(L, 1, &node)) { - return 0; - } TSQuery *query = query_check(L, 2); - - TSQueryCursor *cursor; - if (kv_size(cursors) > 0) { - cursor = kv_pop(cursors); - } else { - cursor = ts_query_cursor_new(); - } - - ts_query_cursor_set_max_start_depth(cursor, UINT32_MAX); - ts_query_cursor_set_match_limit(cursor, 256); + TSQueryCursor *cursor = ts_query_cursor_new(); ts_query_cursor_exec(cursor, query, node); - bool captures = lua_toboolean(L, 3); - - if (lua_gettop(L) >= 4) { - uint32_t start = (uint32_t)luaL_checkinteger(L, 4); - uint32_t end = lua_gettop(L) >= 5 ? (uint32_t)luaL_checkinteger(L, 5) : MAXLNUM; + if (lua_gettop(L) >= 3) { + uint32_t start = (uint32_t)luaL_checkinteger(L, 3); + uint32_t end = lua_gettop(L) >= 4 ? (uint32_t)luaL_checkinteger(L, 4) : MAXLNUM; ts_query_cursor_set_point_range(cursor, (TSPoint){ start, 0 }, (TSPoint){ end, 0 }); } - if (lua_gettop(L) >= 6 && !lua_isnil(L, 6)) { - if (!lua_istable(L, 6)) { - return luaL_error(L, "table expected"); - } - lua_pushnil(L); - // stack: [dict, ..., nil] - while (lua_next(L, 6)) { - // stack: [dict, ..., key, value] + if (lua_gettop(L) >= 5 && !lua_isnil(L, 5)) { + luaL_argcheck(L, lua_istable(L, 5), 5, "table expected"); + lua_pushnil(L); // [dict, ..., nil] + while (lua_next(L, 5)) { + // [dict, ..., key, value] if (lua_type(L, -2) == LUA_TSTRING) { char *k = (char *)lua_tostring(L, -2); if (strequal("max_start_depth", k)) { uint32_t max_start_depth = (uint32_t)lua_tointeger(L, -1); ts_query_cursor_set_max_start_depth(cursor, max_start_depth); + } else if (strequal("match_limit", k)) { + uint32_t match_limit = (uint32_t)lua_tointeger(L, -1); + ts_query_cursor_set_match_limit(cursor, match_limit); } } - lua_pop(L, 1); // pop the value; lua_next will pop the key. - // stack: [dict, ..., key] + // pop the value; lua_next will pop the key. + lua_pop(L, 1); // [dict, ..., key] } } - TSLua_cursor *ud = lua_newuserdata(L, sizeof(*ud)); // [udata] - ud->cursor = cursor; - ud->predicated_match = -1; - ud->max_match_id = -1; + TSQueryCursor **ud = lua_newuserdata(L, sizeof(*ud)); // [node, query, ..., udata] + *ud = cursor; + lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERYCURSOR); // [node, query, ..., udata, meta] + lua_setmetatable(L, -2); // [node, query, ..., udata] - lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERYCURSOR); - lua_setmetatable(L, -2); // [udata] - lua_pushvalue(L, 1); // [udata, node] + // Copy the fenv which contains the nodes tree. + lua_getfenv(L, 1); // [udata, reftable] + lua_setfenv(L, -2); // [udata] - // include query separately, as to keep a ref to it for gc - lua_pushvalue(L, 2); // [udata, node, query] + return 1; +} - if (captures) { - // placeholder for match state - lua_createtable(L, (int)ts_query_capture_count(query), 2); // [u, n, q, match] - lua_pushcclosure(L, query_next_capture, 4); // [closure] - } else { - lua_pushcclosure(L, query_next_match, 3); // [closure] +static int querycursor_remove_match(lua_State *L) +{ + TSQueryCursor *cursor = querycursor_check(L, 1); + uint32_t match_id = (uint32_t)luaL_checkinteger(L, 2); + ts_query_cursor_remove_match(cursor, match_id); + return 0; +} + +static int querycursor_next_capture(lua_State *L) +{ + TSQueryCursor *cursor = querycursor_check(L, 1); + TSQueryMatch match; + uint32_t capture_index; + if (!ts_query_cursor_next_capture(cursor, &match, &capture_index)) { + return 0; + } + + TSQueryCapture capture = match.captures[capture_index]; + + // Handle capture quantifiers here + lua_pushinteger(L, capture.index + 1); // [index] + push_node(L, capture.node, 1); // [index, node] + push_querymatch(L, &match, 1); + + return 3; +} + +static int querycursor_next_match(lua_State *L) +{ + TSQueryCursor *cursor = querycursor_check(L, 1); + + TSQueryMatch match; + if (!ts_query_cursor_next_match(cursor, &match)) { + return 0; } + push_querymatch(L, &match, 1); + return 1; } +static TSQueryCursor *querycursor_check(lua_State *L, int index) +{ + TSQueryCursor **ud = luaL_checkudata(L, index, TS_META_QUERYCURSOR); + luaL_argcheck(L, *ud, index, "TSQueryCursor expected"); + return *ud; +} + static int querycursor_gc(lua_State *L) { - TSLua_cursor *ud = luaL_checkudata(L, 1, TS_META_QUERYCURSOR); - kv_push(cursors, ud->cursor); - ud->cursor = NULL; + TSQueryCursor *cursor = querycursor_check(L, 1); + ts_query_cursor_delete(cursor); return 0; } -// Query methods +// TSQueryMatch + +static struct luaL_Reg querymatch_meta[] = { + { "info", querymatch_info }, + { "captures", querymatch_captures }, + { NULL, NULL } +}; + +static void push_querymatch(lua_State *L, TSQueryMatch *match, int uindex) +{ + TSQueryMatch *ud = lua_newuserdata(L, sizeof(TSQueryMatch)); // [udata] + *ud = *match; + lua_getfield(L, LUA_REGISTRYINDEX, TS_META_QUERYMATCH); // [udata, meta] + lua_setmetatable(L, -2); // [udata] + + // Copy the fenv which contains the nodes tree. + lua_getfenv(L, uindex); // [udata, reftable] + lua_setfenv(L, -2); // [udata] +} + +static int querymatch_info(lua_State *L) +{ + TSQueryMatch *match = luaL_checkudata(L, 1, TS_META_QUERYMATCH); + lua_pushinteger(L, match->id); + lua_pushinteger(L, match->pattern_index + 1); + return 2; +} + +static int querymatch_captures(lua_State *L) +{ + TSQueryMatch *match = luaL_checkudata(L, 1, TS_META_QUERYMATCH); + lua_newtable(L); // [match, nodes, captures] + for (size_t i = 0; i < match->capture_count; i++) { + TSQueryCapture capture = match->captures[i]; + int index = (int)capture.index + 1; + + lua_rawgeti(L, -1, index); // [match, node, captures] + if (lua_isnil(L, -1)) { // [match, node, captures, nil] + lua_pop(L, 1); // [match, node, captures] + lua_newtable(L); // [match, node, captures, nodes] + } + push_node(L, capture.node, 1); // [match, node, captures, nodes, node] + lua_rawseti(L, -2, (int)lua_objlen(L, -2) + 1); // [match, node, captures, nodes] + lua_rawseti(L, -2, index); // [match, node, captures] + } + return 1; +} + +// TSQuery + +static struct luaL_Reg query_meta[] = { + { "__gc", query_gc }, + { "__tostring", query_tostring }, + { "inspect", query_inspect }, + { NULL, NULL } +}; int tslua_parse_query(lua_State *L) { @@ -1536,15 +1358,12 @@ int tslua_parse_query(lua_State *L) return luaL_error(L, "string expected"); } - const char *lang_name = lua_tostring(L, 1); - TSLanguage *lang = pmap_get(cstr_t)(&langs, lang_name); - if (!lang) { - return luaL_error(L, "no such language: %s", lang_name); - } + TSLanguage *lang = lang_check(L, 1); size_t len; const char *src = lua_tolstring(L, 2, &len); + tslua_query_parse_count++; uint32_t error_offset; TSQueryError error_type; TSQuery *query = ts_query_new(lang, src, (uint32_t)len, &error_offset, &error_type); @@ -1638,16 +1457,13 @@ static void query_err_string(const char *src, int error_offset, TSQueryError err static TSQuery *query_check(lua_State *L, int index) { TSQuery **ud = luaL_checkudata(L, index, TS_META_QUERY); + luaL_argcheck(L, *ud, index, "TSQuery expected"); return *ud; } static int query_gc(lua_State *L) { TSQuery *query = query_check(L, 1); - if (!query) { - return 0; - } - ts_query_delete(query); return 0; } @@ -1661,9 +1477,6 @@ static int query_tostring(lua_State *L) static int query_inspect(lua_State *L) { TSQuery *query = query_check(L, 1); - if (!query) { - return 0; - } // TSQueryInfo lua_createtable(L, 0, 2); // [retval] @@ -1718,3 +1531,33 @@ static int query_inspect(lua_State *L) return 1; } + +// Library init + +static void build_meta(lua_State *L, const char *tname, const luaL_Reg *meta) +{ + if (luaL_newmetatable(L, tname)) { // [meta] + luaL_register(L, NULL, meta); + + lua_pushvalue(L, -1); // [meta, meta] + lua_setfield(L, -2, "__index"); // [meta] + } + lua_pop(L, 1); // [] (don't use it now) +} + +/// Init the tslua library. +/// +/// All global state is stored in the registry of the lua_State. +void tslua_init(lua_State *L) +{ + // type metatables + build_meta(L, TS_META_PARSER, parser_meta); + build_meta(L, TS_META_TREE, tree_meta); + build_meta(L, TS_META_NODE, node_meta); + build_meta(L, TS_META_QUERY, query_meta); + build_meta(L, TS_META_QUERYCURSOR, querycursor_meta); + build_meta(L, TS_META_QUERYMATCH, querymatch_meta); + build_meta(L, TS_META_TREECURSOR, treecursor_meta); + + ts_set_allocator(xmalloc, xcalloc, xrealloc, xfree); +} diff --git a/src/nvim/lua/treesitter.h b/src/nvim/lua/treesitter.h index 4ef9a10602..14df06e184 100644 --- a/src/nvim/lua/treesitter.h +++ b/src/nvim/lua/treesitter.h @@ -1,7 +1,12 @@ #pragma once #include <lua.h> // IWYU pragma: keep +#include <stdint.h> + +#include "nvim/macros_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "lua/treesitter.h.generated.h" #endif + +EXTERN uint64_t tslua_query_parse_count INIT( = 0); diff --git a/src/nvim/main.c b/src/nvim/main.c index ea189aaa0c..30b6b6e86b 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -14,7 +14,9 @@ #include <string.h> #ifdef ENABLE_ASAN_UBSAN # include <sanitizer/asan_interface.h> -# include <sanitizer/ubsan_interface.h> +# ifndef MSWIN +# include <sanitizer/ubsan_interface.h> +# endif #endif #include "auto/config.h" // IWYU pragma: keep @@ -61,6 +63,7 @@ #include "nvim/log.h" #include "nvim/lua/executor.h" #include "nvim/lua/secure.h" +#include "nvim/lua/treesitter.h" #include "nvim/macros_defs.h" #include "nvim/main.h" #include "nvim/mark.h" @@ -353,6 +356,12 @@ int main(int argc, char **argv) ui_client_channel_id = rv; } + if (ui_client_channel_id) { + time_finish(); + ui_client_run(remote_ui); // NORETURN + } + assert(!ui_client_channel_id && !use_builtin_ui); + TIME_MSG("expanding arguments"); if (params.diff_mode && params.window_count == -1) { @@ -395,12 +404,6 @@ int main(int argc, char **argv) input_start(); } - if (ui_client_channel_id) { - time_finish(); - ui_client_run(remote_ui); // NORETURN - } - assert(!ui_client_channel_id && !use_builtin_ui); - // Wait for UIs to set up Nvim or show early messages // and prompts (--cmd, swapfile dialog, …). bool use_remote_ui = (embedded_mode && !headless_mode); @@ -639,7 +642,7 @@ int main(int argc, char **argv) // WORKAROUND(mhi): #3023 if (cb_flags & CB_UNNAMEDMASK) { - eval_has_provider("clipboard"); + eval_has_provider("clipboard", false); } if (params.luaf != NULL) { @@ -1573,7 +1576,7 @@ static void handle_quickfix(mparm_T *paramp) { if (paramp->edit_type == EDIT_QF) { if (paramp->use_ef != NULL) { - set_string_option_direct(kOptErrorfile, paramp->use_ef, 0, SID_CARG); + set_option_direct(kOptErrorfile, CSTR_AS_OPTVAL(paramp->use_ef), 0, SID_CARG); } vim_snprintf(IObuff, IOSIZE, "cfile %s", p_ef); if (qf_init(NULL, p_ef, p_efm, true, IObuff, p_menc) < 0) { diff --git a/src/nvim/mapping.c b/src/nvim/mapping.c index 43a4c10ea7..9320390d68 100644 --- a/src/nvim/mapping.c +++ b/src/nvim/mapping.c @@ -347,7 +347,7 @@ static void set_maparg_rhs(const char *const orig_rhs, const size_t orig_rhs_len if (rhs_lua == LUA_NOREF) { mapargs->orig_rhs_len = orig_rhs_len; mapargs->orig_rhs = xcalloc(mapargs->orig_rhs_len + 1, sizeof(char)); - xstrlcpy(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len + 1); + xmemcpyz(mapargs->orig_rhs, orig_rhs, mapargs->orig_rhs_len); if (STRICMP(orig_rhs, "<nop>") == 0) { // "<Nop>" means nothing mapargs->rhs = xcalloc(1, sizeof(char)); // single NUL-char mapargs->rhs_len = 0; @@ -477,7 +477,7 @@ static int str_to_mapargs(const char *strargs, bool is_unmap, MapArguments *mapa return 1; } char lhs_to_replace[256]; - xstrlcpy(lhs_to_replace, to_parse, orig_lhs_len + 1); + xmemcpyz(lhs_to_replace, to_parse, orig_lhs_len); size_t orig_rhs_len = strlen(rhs_start); if (!set_maparg_lhs_rhs(lhs_to_replace, orig_lhs_len, @@ -1812,8 +1812,7 @@ int makemap(FILE *fd, buf_T *buf) iemsg(_("E228: makemap: Illegal mode")); return FAIL; } - do { - // do this twice if c2 is set, 3 times with c3 */ + do { // do this twice if c2 is set, 3 times with c3 // When outputting <> form, need to make sure that 'cpo' // is set to the Vim default. if (!did_cpo) { diff --git a/src/nvim/mark.c b/src/nvim/mark.c index 34e35a8277..6ce42bb7fe 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -588,7 +588,7 @@ MarkMoveRes mark_move_to(fmark_T *fm, MarkMove flags) } if (res & kMarkSwitchedBuf || res & kMarkChangedCursor) { - check_cursor(); + check_cursor(curwin); } end: return res; @@ -1243,11 +1243,11 @@ void mark_adjust_buf(buf_T *buf, linenr_T line1, linenr_T line2, linenr_T amount if (win != curwin || by_api) { if (win->w_topline >= line1 && win->w_topline <= line2) { if (amount == MAXLNUM) { // topline is deleted - if (line1 <= 1) { - win->w_topline = 1; + if (by_api && amount_after > line1 - line2 - 1) { + // api: if the deleted region was replaced with new contents, topline will + // get adjusted later as an effect of the adjusted cursor in fix_cursor() } else { - // api: if the deleted region was replaced with new contents, display that - win->w_topline = (by_api && amount_after > line1 - line2 - 1) ? line1 : line1 - 1; + win->w_topline = MAX(line1 - 1, 1); } } else if (win->w_topline > line1) { // keep topline on the same line, unless inserting just @@ -1715,7 +1715,7 @@ void mark_mb_adjustpos(buf_T *buf, pos_T *lp) { if (lp->col > 0 || lp->coladd > 1) { const char *const p = ml_get_buf(buf, lp->lnum); - if (*p == NUL || (int)strlen(p) < lp->col) { + if (*p == NUL || ml_get_buf_len(buf, lp->lnum) < lp->col) { lp->col = 0; } else { lp->col -= utf_head_off(p, p + lp->col); diff --git a/src/nvim/marktree.c b/src/nvim/marktree.c index 0ebebf409e..34d6cd118f 100644 --- a/src/nvim/marktree.c +++ b/src/nvim/marktree.c @@ -460,7 +460,7 @@ static void meta_describe_key(uint32_t *meta_inc, MTKey k) meta_describe_key_inc(meta_inc, &k); } -// if x is internal, asumes x->meta[..] of children are correct +// if x is internal, assumes x->meta[..] of children are correct static void meta_describe_node(uint32_t *meta_node, MTNode *x) { memset(meta_node, 0, kMTMetaCount * sizeof(meta_node[0])); @@ -1425,7 +1425,7 @@ bool marktree_itr_get_ext(MarkTree *b, MTPos p, MarkTreeIter *itr, bool last, bo } if (meta_filter) { if (!meta_has(itr->x->meta[itr->i], meta_filter)) { - // this takes us to the interal position after the first rejected node + // this takes us to the internal position after the first rejected node break; } } diff --git a/src/nvim/match.c b/src/nvim/match.c index c8837969b6..580d7d1069 100644 --- a/src/nvim/match.c +++ b/src/nvim/match.c @@ -100,7 +100,7 @@ static int match_add(win_T *wp, const char *const grp, const char *const pat, in // Build new match. matchitem_T *m = xcalloc(1, sizeof(matchitem_T)); - if (pos_list != NULL) { + if (tv_list_len(pos_list) > 0) { m->mit_pos_array = xcalloc((size_t)tv_list_len(pos_list), sizeof(llpos_T)); m->mit_pos_count = tv_list_len(pos_list); } @@ -533,7 +533,7 @@ void prepare_search_hl(win_T *wp, match_T *search_hl, linenr_T lnum) for (shl->first_lnum = lnum; shl->first_lnum > wp->w_topline; shl->first_lnum--) { - if (hasFoldingWin(wp, shl->first_lnum - 1, NULL, NULL, true, NULL)) { + if (hasFolding(wp, shl->first_lnum - 1, NULL, NULL)) { break; } } @@ -1103,7 +1103,7 @@ void f_matchaddpos(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) list_T *l; l = argvars[1].vval.v_list; - if (l == NULL) { + if (tv_list_len(l) == 0) { return; } diff --git a/src/nvim/math.c b/src/nvim/math.c index 9a0825823c..1ccf4d7806 100644 --- a/src/nvim/math.c +++ b/src/nvim/math.c @@ -1,10 +1,16 @@ // uncrustify:off #include <math.h> // uncrustify:on +#include <limits.h> #include <stdint.h> #include <string.h> +#ifdef HAVE_BITSCANFORWARD64 +# include <intrin.h> // Required for _BitScanForward64 +#endif + #include "nvim/math.h" +#include "nvim/vim_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "math.c.generated.h" @@ -52,6 +58,10 @@ int xctz(uint64_t x) // Use compiler builtin if possible. #if defined(__clang__) || (defined(__GNUC__) && (__GNUC__ >= 4)) return __builtin_ctzll(x); +#elif defined(HAVE_BITSCANFORWARD64) + unsigned long index; + _BitScanForward64(&index, x); + return (int)index; #else int count = 0; // Set x's trailing zeroes to ones and zero the rest. @@ -66,3 +76,31 @@ int xctz(uint64_t x) return count; #endif } + +/// Count number of set bits in bit field. +int popcount(uint64_t x) +{ + // Use compiler builtin if possible. +#if defined(__clang__) || defined(__GNUC__) + return __builtin_popcountll(x); +#else + int count = 0; + for (; x != 0; x >>= 1) { + if (x & 1) { + count++; + } + } + return count; +#endif +} + +/// For overflow detection, add a digit safely to an int value. +int vim_append_digit_int(int *value, int digit) +{ + int x = *value; + if (x > ((INT_MAX - digit) / 10)) { + return FAIL; + } + *value = x * 10 + digit; + return OK; +} diff --git a/src/nvim/mbyte.c b/src/nvim/mbyte.c index c7a56209e4..a345795bbe 100644 --- a/src/nvim/mbyte.c +++ b/src/nvim/mbyte.c @@ -59,6 +59,7 @@ #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/move.h" #include "nvim/option_vars.h" #include "nvim/optionstr.h" #include "nvim/os/os.h" @@ -2878,6 +2879,7 @@ void f_setcellwidths(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } xfree(cw_table_save); + changed_window_setting_all(); redraw_all_later(UPD_NOT_VALID); } diff --git a/src/nvim/mbyte_defs.h b/src/nvim/mbyte_defs.h index 8670a0595d..7f2d1ba6ce 100644 --- a/src/nvim/mbyte_defs.h +++ b/src/nvim/mbyte_defs.h @@ -10,7 +10,7 @@ enum { /// character of up to 6 bytes, or one 16-bit character of up to three bytes /// plus six following composing characters of three bytes each. MB_MAXBYTES = 21, - /// max length of an unicode char + /// Maximum length of a Unicode character, excluding composing characters. MB_MAXCHAR = 6, }; diff --git a/src/nvim/memfile.c b/src/nvim/memfile.c index fb9f2eb8df..a1713edb66 100644 --- a/src/nvim/memfile.c +++ b/src/nvim/memfile.c @@ -677,7 +677,7 @@ static int mf_trans_add(memfile_T *mfp, bhdr_T *hp) /// The old number When not found. blocknr_T mf_trans_del(memfile_T *mfp, blocknr_T old_nr) { - blocknr_T *num = map_ref(int64_t, int64_t)(&mfp->mf_trans, old_nr, false); + blocknr_T *num = map_ref(int64_t, int64_t)(&mfp->mf_trans, old_nr, NULL); if (num == NULL) { // not found return old_nr; } diff --git a/src/nvim/memline.c b/src/nvim/memline.c index 6b2f26b2d8..5acf4f0c37 100644 --- a/src/nvim/memline.c +++ b/src/nvim/memline.c @@ -30,6 +30,10 @@ // changed (lines appended/deleted/changed) or when it is flushed it gets a // positive number. Use mf_trans_del() to get the new number, before calling // mf_get(). +// +// "Mom, can we get ropes?" +// "We have ropes at home." +// Ropes at home: #include <assert.h> #include <errno.h> @@ -1174,7 +1178,7 @@ void ml_recover(bool checkext) } else { for (idx = 1; idx <= lnum; idx++) { // Need to copy one line, fetching the other one may flush it. - p = xstrdup(ml_get(idx)); + p = xstrnsave(ml_get(idx), (size_t)ml_get_len(idx)); int i = strcmp(p, ml_get(idx + lnum)); xfree(p); if (i != 0) { @@ -1192,7 +1196,7 @@ void ml_recover(bool checkext) ml_delete(curbuf->b_ml.ml_line_count, false); } curbuf->b_flags |= BF_RECOVERED; - check_cursor(); + check_cursor(curwin); recoverymode = false; if (got_int) { @@ -1834,6 +1838,28 @@ char *ml_get_pos(const pos_T *pos) return ml_get_buf(curbuf, pos->lnum) + pos->col; } +/// @return length (excluding the NUL) of the given line. +colnr_T ml_get_len(linenr_T lnum) +{ + return ml_get_buf_len(curbuf, lnum); +} + +/// @return length (excluding the NUL) of the text after position "pos". +colnr_T ml_get_pos_len(pos_T *pos) +{ + return ml_get_buf_len(curbuf, pos->lnum) - pos->col; +} + +/// @return length (excluding the NUL) of the given line in the given buffer. +colnr_T ml_get_buf_len(buf_T *buf, linenr_T lnum) +{ + if (*ml_get_buf(buf, lnum) == NUL) { + return 0; + } + + return buf->b_ml.ml_line_len - 1; +} + /// @return codepoint at pos. pos must be either valid or have col set to MAXCOL! int gchar_pos(pos_T *pos) FUNC_ATTR_NONNULL_ARG(1) @@ -1865,6 +1891,7 @@ static char *ml_get_buf_impl(buf_T *buf, linenr_T lnum, bool will_change) ml_flush_line(buf, false); errorret: STRCPY(questions, "???"); + buf->b_ml.ml_line_len = 4; buf->b_ml.ml_line_lnum = lnum; return questions; } @@ -1873,6 +1900,7 @@ errorret: } if (buf->b_ml.ml_mfp == NULL) { // there are no lines + buf->b_ml.ml_line_len = 1; return ""; } @@ -1903,8 +1931,14 @@ errorret: DataBlock *dp = hp->bh_data; - char *ptr = (char *)dp + (dp->db_index[lnum - buf->b_ml.ml_locked_low] & DB_INDEX_MASK); - buf->b_ml.ml_line_ptr = ptr; + int idx = lnum - buf->b_ml.ml_locked_low; + unsigned start = (dp->db_index[idx] & DB_INDEX_MASK); + // The text ends where the previous line starts. The first line ends + // at the end of the block. + unsigned end = idx == 0 ? dp->db_txt_end : (dp->db_index[idx - 1] & DB_INDEX_MASK); + + buf->b_ml.ml_line_ptr = (char *)dp + start; + buf->b_ml.ml_line_len = (colnr_T)(end - start); buf->b_ml.ml_line_lnum = lnum; buf->b_ml.ml_flags &= ~(ML_LINE_DIRTY | ML_ALLOCATED); } @@ -1922,7 +1956,8 @@ errorret: #ifdef ML_GET_ALLOC_LINES if ((buf->b_ml.ml_flags & (ML_LINE_DIRTY | ML_ALLOCATED)) == 0) { // make sure the text is in allocated memory - buf->b_ml.ml_line_ptr = xstrdup(buf->b_ml.ml_line_ptr); + buf->b_ml.ml_line_ptr = xmemdup(buf->b_ml.ml_line_ptr, + (size_t)buf->b_ml.ml_line_len); buf->b_ml.ml_flags |= ML_ALLOCATED; if (will_change) { // can't make the change in the data block @@ -2468,6 +2503,7 @@ int ml_replace_buf(buf_T *buf, linenr_T lnum, char *line, bool copy, bool noallo } buf->b_ml.ml_line_ptr = line; + buf->b_ml.ml_line_len = (colnr_T)strlen(line) + 1; buf->b_ml.ml_line_lnum = lnum; buf->b_ml.ml_flags = (buf->b_ml.ml_flags | ML_LINE_DIRTY) & ~ML_EMPTY; if (noalloc) { @@ -2765,7 +2801,7 @@ static void ml_flush_line(buf_T *buf, bool noalloc) } else { // text of previous line follows old_len = (int)(dp->db_index[idx - 1] & DB_INDEX_MASK) - start; } - colnr_T new_len = (colnr_T)strlen(new_line) + 1; + colnr_T new_len = buf->b_ml.ml_line_len; int extra = new_len - old_len; // negative if lines gets smaller // if new line fits in data block, replace directly @@ -3456,7 +3492,7 @@ static char *findswapname(buf_T *buf, char **dirp, char *old_fname, bool *found_ char *const name = xmalloc(name_len); memcpy(name, sw_msg_1, sw_msg_1_len + 1); - home_replace(NULL, fname, &name[sw_msg_1_len], fname_len, true); + home_replace(NULL, fname, name + sw_msg_1_len, fname_len, true); xstrlcat(name, sw_msg_2, name_len); int dialog_result = do_dialog(VIM_WARNING, @@ -3734,7 +3770,7 @@ static void ml_updatechunk(buf_T *buf, linenr_T line, int len, int updtype) // First line in empty buffer from ml_flush_line() -- reset buf->b_ml.ml_usedchunks = 1; buf->b_ml.ml_chunksize[0].mlcs_numlines = 1; - buf->b_ml.ml_chunksize[0].mlcs_totalsize = (int)strlen(buf->b_ml.ml_line_ptr) + 1; + buf->b_ml.ml_chunksize[0].mlcs_totalsize = buf->b_ml.ml_line_len; return; } @@ -4050,14 +4086,14 @@ void goto_byte(int cnt) if (lnum < 1) { // past the end curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; curwin->w_curswant = MAXCOL; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } else { curwin->w_cursor.lnum = lnum; curwin->w_cursor.col = (colnr_T)boff; curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; } - check_cursor(); + check_cursor(curwin); // Make sure the cursor is on the first byte of a multi-byte char. mb_adjust_cursor(); @@ -4107,7 +4143,7 @@ int dec(pos_T *lp) if (lp->col == MAXCOL) { // past end of line char *p = ml_get(lp->lnum); - lp->col = (colnr_T)strlen(p); + lp->col = ml_get_len(lp->lnum); lp->col -= utf_head_off(p, p + lp->col); return 0; } @@ -4123,7 +4159,7 @@ int dec(pos_T *lp) // there is a prior line lp->lnum--; char *p = ml_get(lp->lnum); - lp->col = (colnr_T)strlen(p); + lp->col = ml_get_len(lp->lnum); lp->col -= utf_head_off(p, p + lp->col); return 1; } diff --git a/src/nvim/memline_defs.h b/src/nvim/memline_defs.h index 1a217c96d4..f675a2b15f 100644 --- a/src/nvim/memline_defs.h +++ b/src/nvim/memline_defs.h @@ -56,6 +56,7 @@ typedef struct { #define ML_ALLOCATED 0x10 // ml_line_ptr is an allocated copy int ml_flags; + colnr_T ml_line_len; // length of the cached line + NUL linenr_T ml_line_lnum; // line number of cached line, 0 if not valid char *ml_line_ptr; // pointer to cached line size_t ml_line_offset; // cached byte offset of ml_line_lnum diff --git a/src/nvim/memory.c b/src/nvim/memory.c index 37e53e4453..789535e270 100644 --- a/src/nvim/memory.c +++ b/src/nvim/memory.c @@ -202,7 +202,7 @@ void *xmallocz(size_t size) } void *ret = xmalloc(total_size); - ((char *)ret)[size] = 0; + ((char *)ret)[size] = '\0'; return ret; } @@ -222,6 +222,20 @@ void *xmemdupz(const void *data, size_t len) return memcpy(xmallocz(len), data, len); } +/// Copies `len` bytes of `src` to `dst` and zero terminates it. +/// +/// @see {xstrlcpy} +/// @param[out] dst Buffer to store the result. +/// @param[in] src Buffer to be copied. +/// @param[in] len Number of bytes to be copied. +void *xmemcpyz(void *dst, const void *src, size_t len) + FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET +{ + memcpy(dst, src, len); + ((char *)dst)[len] = '\0'; + return dst; +} + #ifndef HAVE_STRNLEN size_t xstrnlen(const char *s, size_t n) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_PURE diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 4ca2a61ab1..ab28eeca1c 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -1478,11 +1478,11 @@ void execute_menu(const exarg_T *eap, vimmenu_T *menu, int mode_idx) // Activate visual mode VIsual_active = true; VIsual_reselect = true; - check_cursor(); + check_cursor(curwin); VIsual = curwin->w_cursor; curwin->w_cursor = tpos; - check_cursor(); + check_cursor(curwin); // Adjust the cursor to make sure it is in the correct pos // for exclusive mode diff --git a/src/nvim/message.c b/src/nvim/message.c index 175e3b5d03..10b90bde29 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -134,7 +134,7 @@ bool keep_msg_more = false; // keep_msg was set by msgmore() // Extended msg state, currently used for external UIs with ext_messages static const char *msg_ext_kind = NULL; -static Array msg_ext_chunks = ARRAY_DICT_INIT; +static Array *msg_ext_chunks = NULL; static garray_T msg_ext_last_chunk = GA_INIT(sizeof(char), 40); static sattr_T msg_ext_last_attr = -1; static size_t msg_ext_cur_len = 0; @@ -1191,7 +1191,15 @@ void wait_return(int redraw) check_timestamps(false); } - hit_return_msg(); + // if cmdheight=0, we need to scroll in the first line of msg_grid upon the screen + if (p_ch == 0 && !ui_has(kUIMessages) && !msg_scrolled) { + msg_grid_validate(); + msg_scroll_up(false, true); + msg_scrolled++; + cmdline_row = Rows - 1; + } + + hit_return_msg(true); do { // Remember "got_int", if it is set vgetc() probably returns a @@ -1240,7 +1248,7 @@ void wait_return(int redraw) got_int = false; } else if (c != K_IGNORE) { c = K_IGNORE; - hit_return_msg(); + hit_return_msg(false); } } else if (msg_scrolled > Rows - 2 && (c == 'j' || c == 'd' || c == 'f' @@ -1265,7 +1273,7 @@ void wait_return(int redraw) } else if (vim_strchr("\r\n ", c) == NULL && c != Ctrl_C) { // Put the character back in the typeahead buffer. Don't use the // stuff buffer, because lmaps wouldn't work. - ins_char_typebuf(vgetc_char, vgetc_mod_mask); + ins_char_typebuf(vgetc_char, vgetc_mod_mask, true); do_redraw = true; // need a redraw even though there is // typeahead } @@ -1313,14 +1321,19 @@ void wait_return(int redraw) } /// Write the hit-return prompt. -static void hit_return_msg(void) +/// +/// @param newline_sb if starting a new line, add it to the scrollback. +static void hit_return_msg(bool newline_sb) { int save_p_more = p_more; - p_more = false; // don't want to see this message when scrolling back + if (!newline_sb) { + p_more = false; + } if (msg_didout) { // start on a new line msg_putchar('\n'); } + p_more = false; // don't want to see this message when scrolling back msg_ext_set_kind("return_prompt"); if (got_int) { msg_puts(_("Interrupt: ")); @@ -2118,6 +2131,9 @@ void msg_printf_attr(const int attr, const char *const fmt, ...) static void msg_ext_emit_chunk(void) { + if (msg_ext_chunks == NULL) { + msg_ext_init_chunks(); + } // Color was changed or a message flushed, end current chunk. if (msg_ext_last_attr == -1) { return; // no chunk @@ -2127,7 +2143,7 @@ static void msg_ext_emit_chunk(void) msg_ext_last_attr = -1; String text = ga_take_string(&msg_ext_last_chunk); ADD(chunk, STRING_OBJ(text)); - ADD(msg_ext_chunks, ARRAY_OBJ(chunk)); + ADD(*msg_ext_chunks, ARRAY_OBJ(chunk)); } /// The display part of msg_puts_len(). @@ -2146,7 +2162,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) msg_ext_last_attr = attr; } // Concat pieces with the same highlight - size_t len = strnlen(str, (size_t)maxlen); + size_t len = maxlen < 0 ? strlen(str) : strnlen(str, (size_t)maxlen); ga_concat_len(&msg_ext_last_chunk, str, len); msg_ext_cur_len += len; return; @@ -2281,7 +2297,7 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse) } msg_cursor_goto(msg_row, msg_col); - if (p_more && !recurse && !(s == sb_str + 1 && *sb_str == '\n')) { + if (p_more && !recurse) { store_sb_text(&sb_str, s, attr, &sb_col, false); } @@ -2713,7 +2729,7 @@ static bool do_more_prompt(int typed_char) // If headless mode is enabled and no input is required, this variable // will be true. However If server mode is enabled, the message "--more--" // should be displayed. - bool no_need_more = headless_mode && !embedded_mode; + bool no_need_more = headless_mode && !embedded_mode && !ui_active(); // We get called recursively when a timer callback outputs a message. In // that case don't show another prompt. Also when at the hit-Enter prompt @@ -2968,7 +2984,7 @@ void repeat_message(void) msg_col = 0; msg_clr_eos(); } - hit_return_msg(); + hit_return_msg(false); msg_row = Rows - 1; } } @@ -3043,6 +3059,16 @@ bool msg_end(void) return true; } +/// Clear "msg_ext_chunks" before flushing so that ui_flush() does not re-emit +/// the same message recursively. +static Array *msg_ext_init_chunks(void) +{ + Array *tofree = msg_ext_chunks; + msg_ext_chunks = xcalloc(1, sizeof(*msg_ext_chunks)); + msg_ext_cur_len = 0; + return tofree; +} + void msg_ext_ui_flush(void) { if (!ui_has(kUIMessages)) { @@ -3051,17 +3077,16 @@ void msg_ext_ui_flush(void) } msg_ext_emit_chunk(); - if (msg_ext_chunks.size > 0) { - ui_call_msg_show(cstr_as_string(msg_ext_kind), - msg_ext_chunks, msg_ext_overwrite); + if (msg_ext_chunks->size > 0) { + Array *tofree = msg_ext_init_chunks(); + ui_call_msg_show(cstr_as_string(msg_ext_kind), *tofree, msg_ext_overwrite); + api_free_array(*tofree); + xfree(tofree); if (!msg_ext_overwrite) { msg_ext_visible++; } - msg_ext_kind = NULL; - api_free_array(msg_ext_chunks); - msg_ext_chunks = (Array)ARRAY_DICT_INIT; - msg_ext_cur_len = 0; msg_ext_overwrite = false; + msg_ext_kind = NULL; } } @@ -3071,10 +3096,10 @@ void msg_ext_flush_showmode(void) // separate event. Still reuse the same chunking logic, for simplicity. if (ui_has(kUIMessages)) { msg_ext_emit_chunk(); - ui_call_msg_showmode(msg_ext_chunks); - api_free_array(msg_ext_chunks); - msg_ext_chunks = (Array)ARRAY_DICT_INIT; - msg_ext_cur_len = 0; + Array *tofree = msg_ext_init_chunks(); + ui_call_msg_showmode(*tofree); + api_free_array(*tofree); + xfree(tofree); } } @@ -3390,9 +3415,7 @@ int do_dialog(int type, const char *title, const char *message, const char *butt int retval = 0; int i; - if (silent_mode // No dialogs in silent mode ("ex -s") - || !ui_active() // Without a UI Nvim waits for input forever. - ) { + if (silent_mode) { // No dialogs in silent mode ("ex -s") return dfltbutton; // return default option } @@ -3409,6 +3432,12 @@ int do_dialog(int type, const char *title, const char *message, const char *butt char *hotkeys = msg_show_console_dialog(message, buttons, dfltbutton); while (true) { + // Without a UI Nvim waits for input forever. + if (!ui_active() && !input_available()) { + retval = dfltbutton; + break; + } + // Get a typed character directly from the user. int c = get_keystroke(NULL); switch (c) { @@ -3426,7 +3455,7 @@ int do_dialog(int type, const char *title, const char *message, const char *butt } if (c == ':' && ex_cmd) { retval = dfltbutton; - ins_char_typebuf(':', 0); + ins_char_typebuf(':', 0, false); break; } diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index 506a428243..f393b0fd0f 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -467,7 +467,7 @@ bool do_mouse(oparg_T *oap, int c, int dir, int count, bool fixindent) if (regname == '.') { insert_reg(regname, true); } else { - if (regname == 0 && eval_has_provider("clipboard")) { + if (regname == 0 && eval_has_provider("clipboard", false)) { regname = '*'; } if ((State & REPLACE_FLAG) && !yank_register_mline(regname)) { @@ -771,7 +771,7 @@ popupexit: // move VIsual to the right column start_visual = curwin->w_cursor; // save the cursor pos curwin->w_cursor = end_visual; - coladvance(end_visual.col); + coladvance(curwin, end_visual.col); VIsual = curwin->w_cursor; curwin->w_cursor = start_visual; // restore the cursor } else { @@ -819,7 +819,7 @@ popupexit: // Middle mouse click: Put text before cursor. if (which_button == MOUSE_MIDDLE) { int c2; - if (regname == 0 && eval_has_provider("clipboard")) { + if (regname == 0 && eval_has_provider("clipboard", false)) { regname = '*'; } if (yank_register_mline(regname)) { @@ -1024,7 +1024,7 @@ void do_mousescroll(cmdarg_T *cap) // Vertical scrolling if ((State & MODE_NORMAL) && shift_or_ctrl) { // whole page up or down - onepage(cap->arg ? FORWARD : BACKWARD, 1); + pagescroll(cap->arg ? FORWARD : BACKWARD, 1, false); } else { if (shift_or_ctrl) { // whole page up or down @@ -1430,7 +1430,7 @@ retnomove: break; } first = false; - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); + hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) { curwin->w_topfill++; } else { @@ -1460,7 +1460,7 @@ retnomove: if (curwin->w_topfill > 0) { curwin->w_topfill--; } else { - if (hasFolding(curwin->w_topline, NULL, &curwin->w_topline) + if (hasFolding(curwin, curwin->w_topline, NULL, &curwin->w_topline) && curwin->w_topline == curbuf->b_ml.ml_line_count) { break; } @@ -1515,7 +1515,7 @@ retnomove: curwin->w_curswant = col; curwin->w_set_curswant = false; // May still have been true - if (coladvance(col) == FAIL) { // Mouse click beyond end of line + if (coladvance(curwin, col) == FAIL) { // Mouse click beyond end of line if (inclusive != NULL) { *inclusive = true; } @@ -1548,7 +1548,7 @@ static bool do_mousescroll_horiz(colnr_T leftcol) // When the line of the cursor is too short, move the cursor to the // longest visible line. - if (!virtual_active() + if (!virtual_active(curwin) && leftcol > scroll_line_len(curwin->w_cursor.lnum)) { curwin->w_cursor.lnum = find_longest_lnum(); curwin->w_cursor.col = 0; @@ -1621,23 +1621,28 @@ bool mouse_comp_pos(win_T *win, int *rowp, int *colp, linenr_T *lnump) } if (win->w_skipcol > 0 && lnum == win->w_topline) { - // Adjust for 'smoothscroll' clipping the top screen lines. - // A similar formula is used in curs_columns(). int width1 = win->w_width_inner - win_col_off(win); - int skip_lines = 0; - if (win->w_skipcol > width1) { - skip_lines = (win->w_skipcol - width1) / (width1 + win_col_off2(win)) + 1; - } else if (win->w_skipcol > 0) { - skip_lines = 1; + + if (width1 > 0) { + int skip_lines = 0; + + // Adjust for 'smoothscroll' clipping the top screen lines. + // A similar formula is used in curs_columns(). + if (win->w_skipcol > width1) { + skip_lines = (win->w_skipcol - width1) / (width1 + win_col_off2(win)) + 1; + } else if (win->w_skipcol > 0) { + skip_lines = 1; + } + + count -= skip_lines; } - count -= skip_lines; } if (count > row) { break; // Position is in this buffer line. } - hasFoldingWin(win, lnum, NULL, &lnum, true, NULL); + hasFolding(win, lnum, NULL, &lnum); if (lnum == win->w_buffer->b_ml.ml_line_count) { retval = true; @@ -1883,33 +1888,7 @@ static void mouse_check_grid(colnr_T *vcolp, int *flagsp) const size_t off = gp->line_offset[click_row] + (size_t)click_col; colnr_T col_from_screen = gp->vcols[off]; - if (col_from_screen == MAXCOL) { - // When clicking after end of line, still need to set correct curswant - size_t off_l = gp->line_offset[click_row] + (size_t)start_col; - if (gp->vcols[off_l] < MAXCOL) { - // Binary search to find last char in line - size_t off_r = off; - while (off_l < off_r) { - size_t off_m = (off_l + off_r + 1) / 2; - if (gp->vcols[off_m] < MAXCOL) { - off_l = off_m; - } else { - off_r = off_m - 1; - } - } - colnr_T eol_vcol = gp->vcols[off_r]; - assert(eol_vcol < MAXCOL); - if (eol_vcol < 0) { - // Empty line or whole line before w_leftcol, - // with columns before buffer text - eol_vcol = curwin->w_leftcol - 1; - } - *vcolp = eol_vcol + (int)(off - off_r); - } else { - // Empty line or whole line before w_leftcol - *vcolp = click_col - start_col + curwin->w_leftcol; - } - } else if (col_from_screen >= 0) { + if (col_from_screen >= 0) { // Use the virtual column from vcols[], it is accurate also after // concealed characters. *vcolp = col_from_screen; diff --git a/src/nvim/move.c b/src/nvim/move.c index 551aa1bd4d..418ece09ed 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -36,6 +36,7 @@ #include "nvim/message.h" #include "nvim/mouse.h" #include "nvim/move.h" +#include "nvim/normal.h" #include "nvim/option.h" #include "nvim/option_vars.h" #include "nvim/plines.h" @@ -77,13 +78,14 @@ int adjust_plines_for_skipcol(win_T *wp) /// Return how many lines "lnum" will take on the screen, taking into account /// whether it is the first line, whether w_skipcol is non-zero and limiting to /// the window height. -static int plines_correct_topline(win_T *wp, linenr_T lnum, linenr_T *nextp, bool *foldedp) +static int plines_correct_topline(win_T *wp, linenr_T lnum, linenr_T *nextp, bool limit_winheight, + bool *foldedp) { int n = plines_win_full(wp, lnum, nextp, foldedp, true, false); if (lnum == wp->w_topline) { n -= adjust_plines_for_skipcol(wp); } - if (n > wp->w_height_inner) { + if (limit_winheight && n > wp->w_height_inner) { return wp->w_height_inner; } return n; @@ -110,7 +112,7 @@ static void comp_botline(win_T *wp) for (; lnum <= wp->w_buffer->b_ml.ml_line_count; lnum++) { linenr_T last = lnum; bool folded; - int n = plines_correct_topline(wp, lnum, &last, &folded); + int n = plines_correct_topline(wp, lnum, &last, true, &folded); if (lnum <= wp->w_cursor.lnum && last >= wp->w_cursor.lnum) { wp->w_cline_row = done; wp->w_cline_height = n; @@ -182,20 +184,23 @@ static void redraw_for_cursorcolumn(win_T *wp) // When current buffer's cursor moves in Visual mode, redraw it with UPD_INVERTED. if (VIsual_active && wp->w_buffer == curbuf) { - redraw_curbuf_later(UPD_INVERTED); + redraw_buf_later(curbuf, UPD_INVERTED); } } /// Calculates how much the 'listchars' "precedes" or 'smoothscroll' "<<<" /// marker overlaps with buffer text for window "wp". /// Parameter "extra2" should be the padding on the 2nd line, not the first -/// line. +/// line. When "extra2" is -1 calculate the padding. /// Returns the number of columns of overlap with buffer text, excluding the /// extra padding on the ledge. int sms_marker_overlap(win_T *wp, int extra2) { + if (extra2 == -1) { + extra2 = win_col_off(wp) - win_col_off2(wp); + } // There is no marker overlap when in showbreak mode, thus no need to - // account for it. See grid_put_linebuf(). + // account for it. See wlv_put_linebuf(). if (*get_showbreak_value(wp) != NUL) { return 0; } @@ -239,7 +244,7 @@ static void reset_skipcol(win_T *wp) redraw_later(wp, UPD_SOME_VALID); } -// Update curwin->w_topline to move the cursor onto the screen. +// Update wp->w_topline to move the cursor onto the screen. void update_topline(win_T *wp) { bool check_botline = false; @@ -281,6 +286,7 @@ void update_topline(win_T *wp) } wp->w_topline = 1; wp->w_botline = 2; + wp->w_skipcol = 0; wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; wp->w_viewport_invalid = true; wp->w_scbind_pos = 1; @@ -294,7 +300,7 @@ void update_topline(win_T *wp) // scrolling down is never needed. if (wp->w_cursor.lnum < wp->w_topline) { check_topline = true; - } else if (check_top_offset()) { + } else if (check_top_offset(wp)) { check_topline = true; } else if (wp->w_skipcol > 0 && wp->w_cursor.lnum == wp->w_topline) { colnr_T vcol; @@ -302,7 +308,7 @@ void update_topline(win_T *wp) // Check that the cursor position is visible. Add columns for // the marker displayed in the top-left if needed. getvvcol(wp, &wp->w_cursor, &vcol, NULL, NULL); - int overlap = sms_marker_overlap(wp, win_col_off(wp) - win_col_off2(wp)); + int overlap = sms_marker_overlap(wp, -1); if (wp->w_skipcol + overlap > vcol) { check_topline = true; } @@ -332,7 +338,7 @@ void update_topline(win_T *wp) if (lnum >= wp->w_buffer->b_ml.ml_line_count || n >= halfheight) { break; } - hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL); + hasFolding(wp, lnum, NULL, &lnum); } } else { n = wp->w_topline + *so_ptr - wp->w_cursor.lnum; @@ -342,14 +348,14 @@ void update_topline(win_T *wp) // cursor in the middle of the window. Otherwise put the cursor // near the top of the window. if (n >= halfheight) { - scroll_cursor_halfway(false, false); + scroll_cursor_halfway(wp, false, false); } else { - scroll_cursor_top(scrolljump_value(), false); + scroll_cursor_top(wp, scrolljump_value(wp), false); check_botline = true; } } else { // Make sure topline is the first line of a fold. - hasFoldingWin(wp, wp->w_topline, &wp->w_topline, NULL, true, NULL); + hasFolding(wp, wp->w_topline, &wp->w_topline, NULL); check_botline = true; } } @@ -377,7 +383,7 @@ void update_topline(win_T *wp) int n = wp->w_empty_rows; loff.lnum = wp->w_cursor.lnum; // In a fold go to its last line. - hasFoldingWin(wp, loff.lnum, NULL, &loff.lnum, true, NULL); + hasFolding(wp, loff.lnum, NULL, &loff.lnum); loff.fill = 0; n += wp->w_filler_rows; loff.height = 0; @@ -411,15 +417,15 @@ void update_topline(win_T *wp) if (lnum <= 0 || line_count > wp->w_height_inner + 1) { break; } - hasFolding(lnum, &lnum, NULL); + hasFolding(wp, lnum, &lnum, NULL); } } else { line_count = wp->w_cursor.lnum - wp->w_botline + 1 + (int)(*so_ptr); } if (line_count <= wp->w_height_inner + 1) { - scroll_cursor_bot(scrolljump_value(), false); + scroll_cursor_bot(wp, scrolljump_value(wp), false); } else { - scroll_cursor_halfway(false, false); + scroll_cursor_halfway(wp, false, false); } } } @@ -443,40 +449,37 @@ void update_topline(win_T *wp) // May need to set w_skipcol when cursor in w_topline. if (wp->w_cursor.lnum == wp->w_topline) { - validate_cursor(); + validate_cursor(wp); } } *so_ptr = save_so; } -// Return the scrolljump value to use for the current window. -// When 'scrolljump' is positive use it as-is. -// When 'scrolljump' is negative use it as a percentage of the window height. -static int scrolljump_value(void) +/// Return the scrolljump value to use for the window "wp". +/// When 'scrolljump' is positive use it as-is. +/// When 'scrolljump' is negative use it as a percentage of the window height. +static int scrolljump_value(win_T *wp) { - int result = p_sj >= 0 ? (int)p_sj : (curwin->w_height_inner * (int)(-p_sj)) / 100; + int result = p_sj >= 0 ? (int)p_sj : (wp->w_height_inner * (int)(-p_sj)) / 100; return result; } -// Return true when there are not 'scrolloff' lines above the cursor for the -// current window. -static bool check_top_offset(void) +/// Return true when there are not 'scrolloff' lines above the cursor for window "wp". +static bool check_top_offset(win_T *wp) { - int so = get_scrolloff_value(curwin); - if (curwin->w_cursor.lnum < curwin->w_topline + so - || hasAnyFolding(curwin)) { + int so = get_scrolloff_value(wp); + if (wp->w_cursor.lnum < wp->w_topline + so || hasAnyFolding(wp)) { lineoff_T loff; - loff.lnum = curwin->w_cursor.lnum; + loff.lnum = wp->w_cursor.lnum; loff.fill = 0; - int n = curwin->w_topfill; // always have this context + int n = wp->w_topfill; // always have this context // Count the visible screen lines above the cursor line. while (n < so) { - topline_back(curwin, &loff); + topline_back(wp, &loff); // Stop when included a line above the window. - if (loff.lnum < curwin->w_topline - || (loff.lnum == curwin->w_topline - && loff.fill > 0)) { + if (loff.lnum < wp->w_topline + || (loff.lnum == wp->w_topline && loff.fill > 0)) { break; } n += loff.height; @@ -491,7 +494,7 @@ static bool check_top_offset(void) /// Update w_curswant. void update_curswant_force(void) { - validate_virtcol(); + validate_virtcol(curwin); curwin->w_curswant = curwin->w_virtcol; curwin->w_set_curswant = false; } @@ -536,12 +539,7 @@ void check_cursor_moved(win_T *wp) // Call this function when some window settings have changed, which require // the cursor position, botline and topline to be recomputed and the window to // be redrawn. E.g, when changing the 'wrap' option or folding. -void changed_window_setting(void) -{ - changed_window_setting_win(curwin); -} - -void changed_window_setting_win(win_T *wp) +void changed_window_setting(win_T *wp) { wp->w_lines_valid = 0; changed_line_abv_curs_win(wp); @@ -549,13 +547,21 @@ void changed_window_setting_win(win_T *wp) redraw_later(wp, UPD_NOT_VALID); } +/// Call changed_window_setting() for every window. +void changed_window_setting_all(void) +{ + FOR_ALL_TAB_WINDOWS(tp, wp) { + changed_window_setting(wp); + } +} + // Set wp->w_topline to a certain number. void set_topline(win_T *wp, linenr_T lnum) { linenr_T prev_topline = wp->w_topline; // go to first of folded lines - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); // Approximate the value of w_botline wp->w_botline += lnum - wp->w_topline; wp->w_topline = lnum; @@ -595,7 +601,7 @@ void changed_line_abv_curs_win(win_T *wp) |VALID_CHEIGHT|VALID_TOPLINE); } -// Make sure the value of curwin->w_botline is valid. +// Make sure the value of wp->w_botline is valid. void validate_botline(win_T *wp) { if (!(wp->w_valid & VALID_BOTLINE)) { @@ -614,21 +620,21 @@ void approximate_botline_win(win_T *wp) wp->w_valid &= ~VALID_BOTLINE; } -// Return true if curwin->w_wrow and curwin->w_wcol are valid. -int cursor_valid(void) +// Return true if wp->w_wrow and wp->w_wcol are valid. +int cursor_valid(win_T *wp) { - check_cursor_moved(curwin); - return (curwin->w_valid & (VALID_WROW|VALID_WCOL)) == (VALID_WROW|VALID_WCOL); + check_cursor_moved(wp); + return (wp->w_valid & (VALID_WROW|VALID_WCOL)) == (VALID_WROW|VALID_WCOL); } // Validate cursor position. Makes sure w_wrow and w_wcol are valid. // w_topline must be valid, you may need to call update_topline() first! -void validate_cursor(void) +void validate_cursor(win_T *wp) { - check_cursor(); - check_cursor_moved(curwin); - if ((curwin->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) { - curs_columns(curwin, true); + check_cursor_lnum(wp); + check_cursor_moved(wp); + if ((wp->w_valid & (VALID_WCOL|VALID_WROW)) != (VALID_WCOL|VALID_WROW)) { + curs_columns(wp, true); } } @@ -671,7 +677,7 @@ static void curs_rows(win_T *wp) } else { linenr_T last = lnum; bool folded; - int n = plines_correct_topline(wp, lnum, &last, &folded); + int n = plines_correct_topline(wp, lnum, &last, true, &folded); lnum = last + 1; if (folded && lnum > wp->w_cursor.lnum) { break; @@ -692,26 +698,19 @@ static void curs_rows(win_T *wp) } else if (i > wp->w_lines_valid) { // a line that is too long to fit on the last screen line wp->w_cline_height = 0; - wp->w_cline_folded = hasFoldingWin(wp, wp->w_cursor.lnum, NULL, - NULL, true, NULL); + wp->w_cline_folded = hasFolding(wp, wp->w_cursor.lnum, NULL, NULL); } else { wp->w_cline_height = wp->w_lines[i].wl_size; wp->w_cline_folded = wp->w_lines[i].wl_folded; } } - redraw_for_cursorline(curwin); + redraw_for_cursorline(wp); wp->w_valid |= VALID_CROW|VALID_CHEIGHT; } -// Validate curwin->w_virtcol only. -void validate_virtcol(void) -{ - validate_virtcol_win(curwin); -} - // Validate wp->w_virtcol only. -void validate_virtcol_win(win_T *wp) +void validate_virtcol(win_T *wp) { check_cursor_moved(wp); @@ -724,49 +723,48 @@ void validate_virtcol_win(win_T *wp) wp->w_valid |= VALID_VIRTCOL; } -// Validate curwin->w_cline_height only. -void validate_cheight(void) +// Validate wp->w_cline_height only. +void validate_cheight(win_T *wp) { - check_cursor_moved(curwin); + check_cursor_moved(wp); - if (curwin->w_valid & VALID_CHEIGHT) { + if (wp->w_valid & VALID_CHEIGHT) { return; } - curwin->w_cline_height = plines_win_full(curwin, curwin->w_cursor.lnum, - NULL, &curwin->w_cline_folded, - true, true); - curwin->w_valid |= VALID_CHEIGHT; + wp->w_cline_height = plines_win_full(wp, wp->w_cursor.lnum, + NULL, &wp->w_cline_folded, + true, true); + wp->w_valid |= VALID_CHEIGHT; } // Validate w_wcol and w_virtcol only. -void validate_cursor_col(void) +void validate_cursor_col(win_T *wp) { - validate_virtcol(); + validate_virtcol(wp); - if (curwin->w_valid & VALID_WCOL) { + if (wp->w_valid & VALID_WCOL) { return; } - colnr_T col = curwin->w_virtcol; - colnr_T off = curwin_col_off(); + colnr_T col = wp->w_virtcol; + colnr_T off = win_col_off(wp); col += off; - int width = curwin->w_width_inner - off + curwin_col_off2(); + int width = wp->w_width_inner - off + win_col_off2(wp); - // long line wrapping, adjust curwin->w_wrow - if (curwin->w_p_wrap && col >= (colnr_T)curwin->w_width_inner - && width > 0) { + // long line wrapping, adjust wp->w_wrow + if (wp->w_p_wrap && col >= (colnr_T)wp->w_width_inner && width > 0) { // use same formula as what is used in curs_columns() - col -= ((col - curwin->w_width_inner) / width + 1) * width; + col -= ((col - wp->w_width_inner) / width + 1) * width; } - if (col > (int)curwin->w_leftcol) { - col -= curwin->w_leftcol; + if (col > (int)wp->w_leftcol) { + col -= wp->w_leftcol; } else { col = 0; } - curwin->w_wcol = col; + wp->w_wcol = col; - curwin->w_valid |= VALID_WCOL; + wp->w_valid |= VALID_WCOL; } // Compute offset of a window, occupied by absolute or relative line number, @@ -779,11 +777,6 @@ int win_col_off(win_T *wp) + win_fdccol_count(wp) + (wp->w_scwidth * SIGN_WIDTH); } -int curwin_col_off(void) -{ - return win_col_off(curwin); -} - // Return the difference in column offset for the second screen line of a // wrapped line. It's positive if 'number' or 'relativenumber' is on and 'n' // is in 'cpoptions'. @@ -796,11 +789,6 @@ int win_col_off2(win_T *wp) return 0; } -int curwin_col_off2(void) -{ - return win_col_off2(curwin); -} - // Compute wp->w_wcol and wp->w_virtcol. // Also updates wp->w_wrow and wp->w_cline_row. // Also updates wp->w_leftcol. @@ -896,7 +884,7 @@ void curs_columns(win_T *wp, int may_scroll) // middle of window. int new_leftcol; if (p_ss == 0 || diff >= width1 / 2 || off_right >= off_left) { - new_leftcol = curwin->w_wcol - extra - width1 / 2; + new_leftcol = wp->w_wcol - extra - width1 / 2; } else { if (diff < p_ss) { assert(p_ss <= INT_MAX); @@ -984,9 +972,9 @@ void curs_columns(win_T *wp, int may_scroll) n = plines - wp->w_height_inner + 1; } if (n > 0) { - curwin->w_skipcol = width1 + (n - 1) * width2; + wp->w_skipcol = width1 + (n - 1) * width2; } else { - curwin->w_skipcol = 0; + wp->w_skipcol = 0; } } else if (extra == 1) { // less than 'scrolloff' lines above, decrease skipcol @@ -1063,8 +1051,8 @@ void textpos2screenpos(win_T *wp, pos_T *pos, int *rowp, int *scolp, int *ccolp, linenr_T lnum = pos->lnum; if (lnum >= wp->w_topline && lnum <= wp->w_botline) { - is_folded = hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); - row = plines_m_win(wp, wp->w_topline, lnum - 1, false); + is_folded = hasFolding(wp, lnum, &lnum, NULL); + row = plines_m_win(wp, wp->w_topline, lnum - 1, INT_MAX); // "row" should be the screen line where line "lnum" begins, which can // be negative if "lnum" is "w_topline" and "w_skipcol" is non-zero. row -= adjust_plines_for_skipcol(wp); @@ -1207,162 +1195,261 @@ void f_virtcol2col(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) rettv->vval.v_number = virtcol2col(wp, lnum, screencol); } -/// Scroll the current window down by "line_count" logical lines. "CTRL-Y" +/// Make sure the cursor is in the visible part of the topline after scrolling +/// the screen with 'smoothscroll'. +static void cursor_correct_sms(win_T *wp) +{ + if (!wp->w_p_sms || !wp->w_p_wrap || wp->w_cursor.lnum != wp->w_topline) { + return; + } + + int so = get_scrolloff_value(wp); + int width1 = wp->w_width_inner - win_col_off(wp); + int width2 = width1 + win_col_off2(wp); + int so_cols = so == 0 ? 0 : width1 + (so - 1) * width2; + int space_cols = (wp->w_height_inner - 1) * width2; + int size = so == 0 ? 0 : win_linetabsize(wp, wp->w_topline, + ml_get_buf(wp->w_buffer, wp->w_topline), + (colnr_T)MAXCOL); + + if (wp->w_topline == 1 && wp->w_skipcol == 0) { + so_cols = 0; // Ignore 'scrolloff' at top of buffer. + } else if (so_cols > space_cols / 2) { + so_cols = space_cols / 2; // Not enough room: put cursor in the middle. + } + + // Not enough screen lines in topline: ignore 'scrolloff'. + while (so_cols > size && so_cols - width2 >= width1 && width1 > 0) { + so_cols -= width2; + } + if (so_cols >= width1 && so_cols > size) { + so_cols -= width1; + } + + // If there is no marker or we have non-zero scrolloff, just ignore it. + int overlap = (wp->w_skipcol == 0 || so_cols != 0) ? 0 : sms_marker_overlap(wp, -1); + int top = wp->w_skipcol + overlap + so_cols; + int bot = wp->w_skipcol + width1 + (wp->w_height_inner - 1) * width2 - so_cols; + + validate_virtcol(wp); + colnr_T col = wp->w_virtcol; + + if (col < top) { + if (col < width1) { + col += width1; + } + while (width2 > 0 && col < top) { + col += width2; + } + } else { + while (width2 > 0 && col >= bot) { + col -= width2; + } + } + + if (col != wp->w_virtcol) { + wp->w_curswant = col; + coladvance(wp, wp->w_curswant); + // validate_virtcol() marked various things as valid, but after + // moving the cursor they need to be recomputed + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); + } +} + +/// Scroll "count" lines up or down, and redraw. +void scroll_redraw(int up, linenr_T count) +{ + linenr_T prev_topline = curwin->w_topline; + int prev_skipcol = curwin->w_skipcol; + int prev_topfill = curwin->w_topfill; + linenr_T prev_lnum = curwin->w_cursor.lnum; + + bool moved = up + ? scrollup(curwin, count, true) + : scrolldown(curwin, count, true); + + if (get_scrolloff_value(curwin) > 0) { + // Adjust the cursor position for 'scrolloff'. Mark w_topline as + // valid, otherwise the screen jumps back at the end of the file. + cursor_correct(curwin); + check_cursor_moved(curwin); + curwin->w_valid |= VALID_TOPLINE; + + // If moved back to where we were, at least move the cursor, otherwise + // we get stuck at one position. Don't move the cursor up if the + // first line of the buffer is already on the screen + while (curwin->w_topline == prev_topline + && curwin->w_skipcol == prev_skipcol + && curwin->w_topfill == prev_topfill) { + if (up) { + if (curwin->w_cursor.lnum > prev_lnum + || cursor_down(1L, false) == FAIL) { + break; + } + } else { + if (curwin->w_cursor.lnum < prev_lnum + || prev_topline == 1L + || cursor_up(1L, false) == FAIL) { + break; + } + } + // Mark w_topline as valid, otherwise the screen jumps back at the + // end of the file. + check_cursor_moved(curwin); + curwin->w_valid |= VALID_TOPLINE; + } + } + + if (moved) { + curwin->w_viewport_invalid = true; + } + + cursor_correct_sms(curwin); + if (curwin->w_cursor.lnum != prev_lnum) { + coladvance(curwin, curwin->w_curswant); + } + redraw_later(curwin, UPD_VALID); +} + +/// Scroll a window down by "line_count" logical lines. "CTRL-Y" /// /// @param line_count number of lines to scroll /// @param byfold if true, count a closed fold as one line -bool scrolldown(linenr_T line_count, int byfold) +bool scrolldown(win_T *wp, linenr_T line_count, int byfold) { int done = 0; // total # of physical lines done int width1 = 0; int width2 = 0; - bool do_sms = curwin->w_p_wrap && curwin->w_p_sms; + bool do_sms = wp->w_p_wrap && wp->w_p_sms; if (do_sms) { - width1 = curwin->w_width_inner - curwin_col_off(); - width2 = width1 + curwin_col_off2(); + width1 = wp->w_width_inner - win_col_off(wp); + width2 = width1 + win_col_off2(wp); } // Make sure w_topline is at the first of a sequence of folded lines. - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); - validate_cursor(); // w_wrow needs to be valid + hasFolding(wp, wp->w_topline, &wp->w_topline, NULL); + validate_cursor(wp); // w_wrow needs to be valid for (int todo = line_count; todo > 0; todo--) { - if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline) - && curwin->w_topfill < curwin->w_height_inner - 1) { - curwin->w_topfill++; + if (wp->w_topfill < win_get_fill(wp, wp->w_topline) + && wp->w_topfill < wp->w_height_inner - 1) { + wp->w_topfill++; done++; } else { // break when at the very top - if (curwin->w_topline == 1 && (!do_sms || curwin->w_skipcol < width1)) { + if (wp->w_topline == 1 && (!do_sms || wp->w_skipcol < width1)) { break; } - if (do_sms && curwin->w_skipcol >= width1) { + if (do_sms && wp->w_skipcol >= width1) { // scroll a screen line down - if (curwin->w_skipcol >= width1 + width2) { - curwin->w_skipcol -= width2; + if (wp->w_skipcol >= width1 + width2) { + wp->w_skipcol -= width2; } else { - curwin->w_skipcol -= width1; + wp->w_skipcol -= width1; } - redraw_later(curwin, UPD_NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); done++; } else { // scroll a text line down - curwin->w_topline--; - curwin->w_skipcol = 0; - curwin->w_topfill = 0; + wp->w_topline--; + wp->w_skipcol = 0; + wp->w_topfill = 0; // A sequence of folded lines only counts for one logical line linenr_T first; - if (hasFolding(curwin->w_topline, &first, NULL)) { + if (hasFolding(wp, wp->w_topline, &first, NULL)) { done++; if (!byfold) { - todo -= curwin->w_topline - first - 1; + todo -= wp->w_topline - first - 1; } - curwin->w_botline -= curwin->w_topline - first; - curwin->w_topline = first; + wp->w_botline -= wp->w_topline - first; + wp->w_topline = first; } else { if (do_sms) { - int size = win_linetabsize(curwin, curwin->w_topline, - ml_get(curwin->w_topline), MAXCOL); + int size = win_linetabsize(wp, wp->w_topline, + ml_get_buf(wp->w_buffer, wp->w_topline), MAXCOL); if (size > width1) { - curwin->w_skipcol = width1; + wp->w_skipcol = width1; size -= width1; - redraw_later(curwin, UPD_NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } while (size > width2) { - curwin->w_skipcol += width2; + wp->w_skipcol += width2; size -= width2; } done++; } else { - done += plines_win_nofill(curwin, curwin->w_topline, true); + done += plines_win_nofill(wp, wp->w_topline, true); } } } } - curwin->w_botline--; // approximate w_botline - invalidate_botline(curwin); + wp->w_botline--; // approximate w_botline + invalidate_botline(wp); } - curwin->w_wrow += done; // keep w_wrow updated - curwin->w_cline_row += done; // keep w_cline_row updated + wp->w_wrow += done; // keep w_wrow updated + wp->w_cline_row += done; // keep w_cline_row updated - if (curwin->w_cursor.lnum == curwin->w_topline) { - curwin->w_cline_row = 0; + if (wp->w_cursor.lnum == wp->w_topline) { + wp->w_cline_row = 0; } - check_topfill(curwin, true); + check_topfill(wp, true); // Compute the row number of the last row of the cursor line // and move the cursor onto the displayed part of the window. - int wrow = curwin->w_wrow; - if (curwin->w_p_wrap && curwin->w_width_inner != 0) { - validate_virtcol(); - validate_cheight(); - wrow += curwin->w_cline_height - 1 - - curwin->w_virtcol / curwin->w_width_inner; + int wrow = wp->w_wrow; + if (wp->w_p_wrap && wp->w_width_inner != 0) { + validate_virtcol(wp); + validate_cheight(wp); + wrow += wp->w_cline_height - 1 - + wp->w_virtcol / wp->w_width_inner; } bool moved = false; - while (wrow >= curwin->w_height_inner && curwin->w_cursor.lnum > 1) { + while (wrow >= wp->w_height_inner && wp->w_cursor.lnum > 1) { linenr_T first; - if (hasFolding(curwin->w_cursor.lnum, &first, NULL)) { + if (hasFolding(wp, wp->w_cursor.lnum, &first, NULL)) { wrow--; if (first == 1) { - curwin->w_cursor.lnum = 1; + wp->w_cursor.lnum = 1; } else { - curwin->w_cursor.lnum = first - 1; + wp->w_cursor.lnum = first - 1; } } else { - wrow -= plines_win(curwin, curwin->w_cursor.lnum--, true); + wrow -= plines_win(wp, wp->w_cursor.lnum--, true); } - curwin->w_valid &= + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); moved = true; } if (moved) { // Move cursor to first line of closed fold. - foldAdjustCursor(); - coladvance(curwin->w_curswant); + foldAdjustCursor(wp); + coladvance(wp, wp->w_curswant); } - - if (curwin->w_cursor.lnum == curwin->w_topline && do_sms) { - int so = get_scrolloff_value(curwin); - colnr_T scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2; - - // make sure the cursor is in the visible text - validate_virtcol(); - colnr_T col = curwin->w_virtcol - curwin->w_skipcol + scrolloff_cols; - int row = 0; - if (col >= width1) { - col -= width1; - row++; - } - if (col > width2 && width2 > 0) { - row += (int)col / width2; - } - if (row >= curwin->w_height_inner) { - curwin->w_curswant = curwin->w_virtcol - (row - curwin->w_height_inner + 1) * width2; - coladvance(curwin->w_curswant); - } + if (wp->w_cursor.lnum < wp->w_topline) { + wp->w_cursor.lnum = wp->w_topline; } + return moved; } -/// Scroll the current window up by "line_count" logical lines. "CTRL-E" +/// Scroll a window up by "line_count" logical lines. "CTRL-E" /// /// @param line_count number of lines to scroll /// @param byfold if true, count a closed fold as one line -bool scrollup(linenr_T line_count, bool byfold) +bool scrollup(win_T *wp, linenr_T line_count, bool byfold) { - linenr_T topline = curwin->w_topline; - linenr_T botline = curwin->w_botline; - bool do_sms = curwin->w_p_wrap && curwin->w_p_sms; + linenr_T topline = wp->w_topline; + linenr_T botline = wp->w_botline; + bool do_sms = wp->w_p_wrap && wp->w_p_sms; - if (do_sms || (byfold && hasAnyFolding(curwin)) || win_may_fill(curwin)) { - int width1 = curwin->w_width_inner - curwin_col_off(); - int width2 = width1 + curwin_col_off2(); + if (do_sms || (byfold && hasAnyFolding(wp)) || win_may_fill(wp)) { + int width1 = wp->w_width_inner - win_col_off(wp); + int width2 = width1 + win_col_off2(wp); int size = 0; - const colnr_T prev_skipcol = curwin->w_skipcol; + const colnr_T prev_skipcol = wp->w_skipcol; if (do_sms) { - size = linetabsize(curwin, curwin->w_topline); + size = linetabsize(wp, wp->w_topline); } // diff mode: first consume "topfill" @@ -1370,120 +1457,80 @@ bool scrollup(linenr_T line_count, bool byfold) // the line, then advance to the next line. // folding: count each sequence of folded lines as one logical line. for (int todo = line_count; todo > 0; todo--) { - if (curwin->w_topfill > 0) { - curwin->w_topfill--; + if (wp->w_topfill > 0) { + wp->w_topfill--; } else { - linenr_T lnum = curwin->w_topline; + linenr_T lnum = wp->w_topline; if (byfold) { // for a closed fold: go to the last line in the fold - hasFolding(lnum, NULL, &lnum); + hasFolding(wp, lnum, NULL, &lnum); } - if (lnum == curwin->w_topline && do_sms) { + if (lnum == wp->w_topline && do_sms) { // 'smoothscroll': increase "w_skipcol" until it goes over // the end of the line, then advance to the next line. - int add = curwin->w_skipcol > 0 ? width2 : width1; - curwin->w_skipcol += add; - if (curwin->w_skipcol >= size) { - if (lnum == curbuf->b_ml.ml_line_count) { + int add = wp->w_skipcol > 0 ? width2 : width1; + wp->w_skipcol += add; + if (wp->w_skipcol >= size) { + if (lnum == wp->w_buffer->b_ml.ml_line_count) { // at the last screen line, can't scroll further - curwin->w_skipcol -= add; + wp->w_skipcol -= add; break; } lnum++; } } else { - if (lnum >= curbuf->b_ml.ml_line_count) { + if (lnum >= wp->w_buffer->b_ml.ml_line_count) { break; } lnum++; } - if (lnum > curwin->w_topline) { + if (lnum > wp->w_topline) { // approximate w_botline - curwin->w_botline += lnum - curwin->w_topline; - curwin->w_topline = lnum; - curwin->w_topfill = win_get_fill(curwin, lnum); - curwin->w_skipcol = 0; + wp->w_botline += lnum - wp->w_topline; + wp->w_topline = lnum; + wp->w_topfill = win_get_fill(wp, lnum); + wp->w_skipcol = 0; if (todo > 1 && do_sms) { - size = linetabsize(curwin, curwin->w_topline); + size = linetabsize(wp, wp->w_topline); } } } } - if (prev_skipcol > 0 || curwin->w_skipcol > 0) { + if (prev_skipcol > 0 || wp->w_skipcol > 0) { // need to redraw more, because wl_size of the (new) topline may // now be invalid - redraw_later(curwin, UPD_NOT_VALID); + redraw_later(wp, UPD_NOT_VALID); } } else { - curwin->w_topline += line_count; - curwin->w_botline += line_count; // approximate w_botline + wp->w_topline += line_count; + wp->w_botline += line_count; // approximate w_botline } - if (curwin->w_topline > curbuf->b_ml.ml_line_count) { - curwin->w_topline = curbuf->b_ml.ml_line_count; + if (wp->w_topline > wp->w_buffer->b_ml.ml_line_count) { + wp->w_topline = wp->w_buffer->b_ml.ml_line_count; } - if (curwin->w_botline > curbuf->b_ml.ml_line_count + 1) { - curwin->w_botline = curbuf->b_ml.ml_line_count + 1; + if (wp->w_botline > wp->w_buffer->b_ml.ml_line_count + 1) { + wp->w_botline = wp->w_buffer->b_ml.ml_line_count + 1; } - check_topfill(curwin, false); + check_topfill(wp, false); - if (hasAnyFolding(curwin)) { + if (hasAnyFolding(wp)) { // Make sure w_topline is at the first of a sequence of folded lines. - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); + hasFolding(wp, wp->w_topline, &wp->w_topline, NULL); } - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - if (curwin->w_cursor.lnum < curwin->w_topline) { - curwin->w_cursor.lnum = curwin->w_topline; - curwin->w_valid &= + wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); + if (wp->w_cursor.lnum < wp->w_topline) { + wp->w_cursor.lnum = wp->w_topline; + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); - coladvance(curwin->w_curswant); - } - - if (curwin->w_cursor.lnum == curwin->w_topline && do_sms && curwin->w_skipcol > 0) { - int col_off = curwin_col_off(); - int col_off2 = curwin_col_off2(); - - int width1 = curwin->w_width_inner - col_off; - int width2 = width1 + col_off2; - int extra2 = col_off - col_off2; - int so = get_scrolloff_value(curwin); - colnr_T scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2; - int space_cols = (curwin->w_height_inner - 1) * width2; - - // If we have non-zero scrolloff, just ignore the marker as we are - // going past it anyway. - int overlap = scrolloff_cols != 0 ? 0 : sms_marker_overlap(curwin, extra2); - - // Make sure the cursor is in a visible part of the line, taking - // 'scrolloff' into account, but using screen lines. - // If there are not enough screen lines put the cursor in the middle. - if (scrolloff_cols > space_cols / 2) { - scrolloff_cols = space_cols / 2; - } - validate_virtcol(); - if (curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) { - colnr_T col = curwin->w_virtcol; - - if (col < width1) { - col += width1; - } - while (col < curwin->w_skipcol + overlap + scrolloff_cols) { - col += width2; - } - curwin->w_curswant = col; - coladvance(curwin->w_curswant); - - // validate_virtcol() marked various things as valid, but after - // moving the cursor they need to be recomputed - curwin->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW|VALID_VIRTCOL); - } + coladvance(wp, wp->w_curswant); } - bool moved = topline != curwin->w_topline || botline != curwin->w_botline; + bool moved = topline != wp->w_topline || botline != wp->w_botline; return moved; } @@ -1496,16 +1543,16 @@ void adjust_skipcol(void) return; } - int width1 = curwin->w_width_inner - curwin_col_off(); + int width1 = curwin->w_width_inner - win_col_off(curwin); if (width1 <= 0) { return; // no text will be displayed } - int width2 = width1 + curwin_col_off2(); + int width2 = width1 + win_col_off2(curwin); int so = get_scrolloff_value(curwin); colnr_T scrolloff_cols = so == 0 ? 0 : width1 + (so - 1) * width2; bool scrolled = false; - validate_cheight(); + validate_cheight(curwin); if (curwin->w_cline_height == curwin->w_height_inner // w_cline_height may be capped at w_height_inner, check there aren't // actually more lines. @@ -1515,8 +1562,8 @@ void adjust_skipcol(void) return; } - validate_virtcol(); - int overlap = sms_marker_overlap(curwin, curwin_col_off() - curwin_col_off2()); + validate_virtcol(curwin); + int overlap = sms_marker_overlap(curwin, -1); while (curwin->w_skipcol > 0 && curwin->w_virtcol < curwin->w_skipcol + overlap + scrolloff_cols) { // scroll a screen line down @@ -1528,12 +1575,24 @@ void adjust_skipcol(void) scrolled = true; } if (scrolled) { - validate_virtcol(); + validate_virtcol(curwin); redraw_later(curwin, UPD_NOT_VALID); return; // don't scroll in the other direction now } - colnr_T col = curwin->w_virtcol - curwin->w_skipcol + scrolloff_cols; int row = 0; + colnr_T col = curwin->w_virtcol + scrolloff_cols; + + // Avoid adjusting for 'scrolloff' beyond the text line height. + if (scrolloff_cols > 0) { + int size = win_linetabsize(curwin, curwin->w_topline, + ml_get(curwin->w_topline), (colnr_T)MAXCOL); + size = width1 + width2 * ((size - width1 + width2 - 1) / width2); + while (col > size) { + col -= width2; + } + } + col -= curwin->w_skipcol; + if (col >= width1) { col -= width1; row++; @@ -1572,22 +1631,7 @@ void check_topfill(win_T *wp, bool down) } } } - win_check_anchored_floats(curwin); -} - -// Use as many filler lines as possible for w_topline. Make sure w_topline -// is still visible. -static void max_topfill(void) -{ - int n = plines_win_nofill(curwin, curwin->w_topline, true); - if (n >= curwin->w_height_inner) { - curwin->w_topfill = 0; - } else { - curwin->w_topfill = win_get_fill(curwin, curwin->w_topline); - if (curwin->w_topfill + n > curwin->w_height_inner) { - curwin->w_topfill = curwin->w_height_inner - n; - } - } + win_check_anchored_floats(wp); } // Scroll the screen one line down, but don't do it if it would move the @@ -1601,7 +1645,7 @@ void scrolldown_clamp(void) return; } - validate_cursor(); // w_wrow needs to be valid + validate_cursor(curwin); // w_wrow needs to be valid // Compute the row number of the last row of the cursor line // and make sure it doesn't go off the screen. Make sure the cursor @@ -1613,8 +1657,8 @@ void scrolldown_clamp(void) end_row += plines_win_nofill(curwin, curwin->w_topline - 1, true); } if (curwin->w_p_wrap && curwin->w_width_inner != 0) { - validate_cheight(); - validate_virtcol(); + validate_cheight(curwin); + validate_virtcol(curwin); end_row += curwin->w_cline_height - 1 - curwin->w_virtcol / curwin->w_width_inner; } @@ -1626,7 +1670,7 @@ void scrolldown_clamp(void) curwin->w_topline--; curwin->w_topfill = 0; } - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); + hasFolding(curwin, curwin->w_topline, &curwin->w_topline, NULL); curwin->w_botline--; // approximate w_botline curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); } @@ -1641,7 +1685,7 @@ void scrollup_clamp(void) return; } - validate_cursor(); // w_wrow needs to be valid + validate_cursor(curwin); // w_wrow needs to be valid // Compute the row number of the first row of the cursor line // and make sure it doesn't go off the screen. Make sure the cursor @@ -1650,14 +1694,14 @@ void scrollup_clamp(void) - plines_win_nofill(curwin, curwin->w_topline, true) - curwin->w_topfill); if (curwin->w_p_wrap && curwin->w_width_inner != 0) { - validate_virtcol(); + validate_virtcol(curwin); start_row -= curwin->w_virtcol / curwin->w_width_inner; } if (start_row >= get_scrolloff_value(curwin)) { if (curwin->w_topfill > 0) { curwin->w_topfill--; } else { - hasFolding(curwin->w_topline, NULL, &curwin->w_topline); + hasFolding(curwin, curwin->w_topline, NULL, &curwin->w_topline); curwin->w_topline++; } curwin->w_botline++; // approximate w_botline @@ -1681,7 +1725,7 @@ static void topline_back_winheight(win_T *wp, lineoff_T *lp, int winheight) lp->fill = 0; if (lp->lnum < 1) { lp->height = MAXCOL; - } else if (hasFolding(lp->lnum, &lp->lnum, NULL)) { + } else if (hasFolding(wp, lp->lnum, &lp->lnum, NULL)) { // Add a closed fold lp->height = 1; } else { @@ -1711,7 +1755,7 @@ static void botline_forw(win_T *wp, lineoff_T *lp) assert(wp->w_buffer != 0); if (lp->lnum > wp->w_buffer->b_ml.ml_line_count) { lp->height = MAXCOL; - } else if (hasFoldingWin(wp, lp->lnum, NULL, &lp->lnum, true, NULL)) { + } else if (hasFolding(wp, lp->lnum, NULL, &lp->lnum)) { // Add a closed fold lp->height = 1; } else { @@ -1720,37 +1764,15 @@ static void botline_forw(win_T *wp, lineoff_T *lp) } } -// Switch from including filler lines below lp->lnum to including filler -// lines above loff.lnum + 1. This keeps pointing to the same line. -// When there are no filler lines nothing changes. -static void botline_topline(lineoff_T *lp) -{ - if (lp->fill > 0) { - lp->lnum++; - lp->fill = win_get_fill(curwin, lp->lnum) - lp->fill + 1; - } -} - -// Switch from including filler lines above lp->lnum to including filler -// lines below loff.lnum - 1. This keeps pointing to the same line. -// When there are no filler lines nothing changes. -static void topline_botline(lineoff_T *lp) -{ - if (lp->fill > 0) { - lp->fill = win_get_fill(curwin, lp->lnum) - lp->fill + 1; - lp->lnum--; - } -} - // Recompute topline to put the cursor at the top of the window. // Scroll at least "min_scroll" lines. // If "always" is true, always set topline (for "zt"). -void scroll_cursor_top(int min_scroll, int always) +void scroll_cursor_top(win_T *wp, int min_scroll, int always) { - linenr_T old_topline = curwin->w_topline; - int old_skipcol = curwin->w_skipcol; - linenr_T old_topfill = curwin->w_topfill; - int off = get_scrolloff_value(curwin); + linenr_T old_topline = wp->w_topline; + int old_skipcol = wp->w_skipcol; + linenr_T old_topfill = wp->w_topfill; + int off = get_scrolloff_value(wp); if (mouse_dragging > 0) { off = mouse_dragging - 1; @@ -1761,54 +1783,54 @@ void scroll_cursor_top(int min_scroll, int always) // - (part of) the cursor line is moved off the screen or // - moved at least 'scrolljump' lines and // - at least 'scrolloff' lines above and below the cursor - validate_cheight(); + validate_cheight(wp); int scrolled = 0; - int used = curwin->w_cline_height; // includes filler lines above - if (curwin->w_cursor.lnum < curwin->w_topline) { + int used = wp->w_cline_height; // includes filler lines above + if (wp->w_cursor.lnum < wp->w_topline) { scrolled = used; } linenr_T top; // just above displayed lines linenr_T bot; // just below displayed lines - if (hasFolding(curwin->w_cursor.lnum, &top, &bot)) { + if (hasFolding(wp, wp->w_cursor.lnum, &top, &bot)) { top--; bot++; } else { - top = curwin->w_cursor.lnum - 1; - bot = curwin->w_cursor.lnum + 1; + top = wp->w_cursor.lnum - 1; + bot = wp->w_cursor.lnum + 1; } linenr_T new_topline = top + 1; // "used" already contains the number of filler lines above, don't add it // again. // Hide filler lines above cursor line by adding them to "extra". - int extra = win_get_fill(curwin, curwin->w_cursor.lnum); + int extra = win_get_fill(wp, wp->w_cursor.lnum); // Check if the lines from "top" to "bot" fit in the window. If they do, // set new_topline and advance "top" and "bot" to include more lines. while (top > 0) { - int i = hasFolding(top, &top, NULL) + int i = hasFolding(wp, top, &top, NULL) ? 1 // count one logical line for a sequence of folded lines - : plines_win_nofill(curwin, top, true); - if (top < curwin->w_topline) { + : plines_win_nofill(wp, top, true); + if (top < wp->w_topline) { scrolled += i; } // If scrolling is needed, scroll at least 'sj' lines. - if ((new_topline >= curwin->w_topline || scrolled > min_scroll) && extra >= off) { + if ((new_topline >= wp->w_topline || scrolled > min_scroll) && extra >= off) { break; } used += i; - if (extra + i <= off && bot < curbuf->b_ml.ml_line_count) { - if (hasFolding(bot, NULL, &bot)) { + if (extra + i <= off && bot < wp->w_buffer->b_ml.ml_line_count) { + if (hasFolding(wp, bot, NULL, &bot)) { // count one logical line for a sequence of folded lines used++; } else { - used += plines_win(curwin, bot, true); + used += plines_win(wp, bot, true); } } - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { break; } @@ -1821,43 +1843,43 @@ void scroll_cursor_top(int min_scroll, int always) // If we don't have enough space, put cursor in the middle. // This makes sure we get the same position when using "k" and "j" // in a small window. - if (used > curwin->w_height_inner) { - scroll_cursor_halfway(false, false); + if (used > wp->w_height_inner) { + scroll_cursor_halfway(wp, false, false); } else { // If "always" is false, only adjust topline to a lower value, higher // value may happen with wrapping lines. - if (new_topline < curwin->w_topline || always) { - curwin->w_topline = new_topline; + if (new_topline < wp->w_topline || always) { + wp->w_topline = new_topline; } - if (curwin->w_topline > curwin->w_cursor.lnum) { - curwin->w_topline = curwin->w_cursor.lnum; + if (wp->w_topline > wp->w_cursor.lnum) { + wp->w_topline = wp->w_cursor.lnum; } - curwin->w_topfill = win_get_fill(curwin, curwin->w_topline); - if (curwin->w_topfill > 0 && extra > off) { - curwin->w_topfill -= extra - off; - if (curwin->w_topfill < 0) { - curwin->w_topfill = 0; + wp->w_topfill = win_get_fill(wp, wp->w_topline); + if (wp->w_topfill > 0 && extra > off) { + wp->w_topfill -= extra - off; + if (wp->w_topfill < 0) { + wp->w_topfill = 0; } } - check_topfill(curwin, false); - if (curwin->w_topline != old_topline) { - reset_skipcol(curwin); - } else if (curwin->w_topline == curwin->w_cursor.lnum) { - validate_virtcol(); - if (curwin->w_skipcol >= curwin->w_virtcol) { + check_topfill(wp, false); + if (wp->w_topline != old_topline) { + reset_skipcol(wp); + } else if (wp->w_topline == wp->w_cursor.lnum) { + validate_virtcol(wp); + if (wp->w_skipcol >= wp->w_virtcol) { // TODO(vim): if the line doesn't fit may optimize w_skipcol instead // of making it zero - reset_skipcol(curwin); + reset_skipcol(wp); } } - if (curwin->w_topline != old_topline - || curwin->w_skipcol != old_skipcol - || curwin->w_topfill != old_topfill) { - curwin->w_valid &= + if (wp->w_topline != old_topline + || wp->w_skipcol != old_skipcol + || wp->w_topfill != old_topfill) { + wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); } - curwin->w_valid |= VALID_TOPLINE; - curwin->w_viewport_invalid = true; + wp->w_valid |= VALID_TOPLINE; + wp->w_viewport_invalid = true; } } @@ -1886,79 +1908,76 @@ void set_empty_rows(win_T *wp, int used) /// When scrolling scroll at least "min_scroll" lines. /// If "set_topbot" is true, set topline and botline first (for "zb"). /// This is messy stuff!!! -void scroll_cursor_bot(int min_scroll, bool set_topbot) +void scroll_cursor_bot(win_T *wp, int min_scroll, bool set_topbot) { lineoff_T loff; - linenr_T old_topline = curwin->w_topline; - int old_skipcol = curwin->w_skipcol; - int old_topfill = curwin->w_topfill; - linenr_T old_botline = curwin->w_botline; - int old_valid = curwin->w_valid; - int old_empty_rows = curwin->w_empty_rows; - linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number - bool do_sms = curwin->w_p_wrap && curwin->w_p_sms; + linenr_T old_topline = wp->w_topline; + int old_skipcol = wp->w_skipcol; + int old_topfill = wp->w_topfill; + linenr_T old_botline = wp->w_botline; + int old_valid = wp->w_valid; + int old_empty_rows = wp->w_empty_rows; + linenr_T cln = wp->w_cursor.lnum; // Cursor Line Number + bool do_sms = wp->w_p_wrap && wp->w_p_sms; if (set_topbot) { - bool set_skipcol = false; - int used = 0; - curwin->w_botline = cln + 1; + wp->w_botline = cln + 1; + loff.lnum = cln + 1; loff.fill = 0; - for (curwin->w_topline = curwin->w_botline; - curwin->w_topline > 1; - curwin->w_topline = loff.lnum) { - loff.lnum = curwin->w_topline; - topline_back_winheight(curwin, &loff, false); + while (true) { + topline_back_winheight(wp, &loff, false); if (loff.height == MAXCOL) { break; } - if (used + loff.height > curwin->w_height_inner) { + if (used + loff.height > wp->w_height_inner) { if (do_sms) { // 'smoothscroll' and 'wrap' are set. The above line is // too long to show in its entirety, so we show just a part // of it. - if (used < curwin->w_height_inner) { - int plines_offset = used + loff.height - curwin->w_height_inner; - used = curwin->w_height_inner; - curwin->w_topfill = loff.fill; - curwin->w_topline = loff.lnum; - curwin->w_skipcol = skipcol_from_plines(curwin, plines_offset); - set_skipcol = true; + if (used < wp->w_height_inner) { + int plines_offset = used + loff.height - wp->w_height_inner; + used = wp->w_height_inner; + wp->w_topfill = loff.fill; + wp->w_topline = loff.lnum; + wp->w_skipcol = skipcol_from_plines(wp, plines_offset); } } break; } + wp->w_topfill = loff.fill; + wp->w_topline = loff.lnum; used += loff.height; - curwin->w_topfill = loff.fill; - } - set_empty_rows(curwin, used); - curwin->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; - if (curwin->w_topline != old_topline - || curwin->w_topfill != old_topfill - || set_skipcol - || curwin->w_skipcol != 0) { - curwin->w_valid &= ~(VALID_WROW|VALID_CROW); - if (set_skipcol) { - redraw_later(curwin, UPD_NOT_VALID); + } + + set_empty_rows(wp, used); + wp->w_valid |= VALID_BOTLINE|VALID_BOTLINE_AP; + if (wp->w_topline != old_topline + || wp->w_topfill != old_topfill + || wp->w_skipcol != old_skipcol + || wp->w_skipcol != 0) { + wp->w_valid &= ~(VALID_WROW|VALID_CROW); + if (wp->w_skipcol != old_skipcol) { + redraw_later(wp, UPD_NOT_VALID); } else { - reset_skipcol(curwin); + reset_skipcol(wp); } } } else { - validate_botline(curwin); + validate_botline(wp); } // The lines of the cursor line itself are always used. - int used = plines_win_nofill(curwin, cln, true); + int used = plines_win_nofill(wp, cln, true); int scrolled = 0; // If the cursor is on or below botline, we will at least scroll by the // height of the cursor line, which is "used". Correct for empty lines, // which are really part of botline. - if (cln >= curwin->w_botline) { + if (cln >= wp->w_botline) { scrolled = used; - if (cln == curwin->w_botline) { - scrolled -= curwin->w_empty_rows; + if (cln == wp->w_botline) { + scrolled -= wp->w_empty_rows; } if (do_sms) { // 'smoothscroll' and 'wrap' are set. @@ -1966,21 +1985,23 @@ void scroll_cursor_bot(int min_scroll, bool set_topbot) // occupies. If it is occupying more than the entire window, we // need to scroll the additional clipped lines to scroll past the // top line before we can move on to the other lines. - int top_plines = plines_win_nofill(curwin, curwin->w_topline, false); - int skip_lines = 0; - int width1 = curwin->w_width_inner - curwin_col_off(); + int top_plines = plines_win_nofill(wp, wp->w_topline, false); + int width1 = wp->w_width_inner - win_col_off(wp); + if (width1 > 0) { - int width2 = width1 + curwin_col_off2(); - // similar formula is used in curs_columns() - if (curwin->w_skipcol > width1) { - skip_lines += (curwin->w_skipcol - width1) / width2 + 1; - } else if (curwin->w_skipcol > 0) { + int width2 = width1 + win_col_off2(wp); + int skip_lines = 0; + + // A similar formula is used in curs_columns(). + if (wp->w_skipcol > width1) { + skip_lines += (wp->w_skipcol - width1) / width2 + 1; + } else if (wp->w_skipcol > 0) { skip_lines = 1; } top_plines -= skip_lines; - if (top_plines > curwin->w_height_inner) { - scrolled += (top_plines - curwin->w_height_inner); + if (top_plines > wp->w_height_inner) { + scrolled += (top_plines - wp->w_height_inner); } } } @@ -1992,67 +2013,67 @@ void scroll_cursor_bot(int min_scroll, bool set_topbot) // - scrolled nothing or at least 'sj' lines // - at least 'so' lines below the cursor // - lines between botline and cursor have been counted - if (!hasFolding(curwin->w_cursor.lnum, &loff.lnum, &boff.lnum)) { + if (!hasFolding(wp, wp->w_cursor.lnum, &loff.lnum, &boff.lnum)) { loff.lnum = cln; boff.lnum = cln; } loff.fill = 0; boff.fill = 0; - int fill_below_window = win_get_fill(curwin, curwin->w_botline) - curwin->w_filler_rows; + int fill_below_window = win_get_fill(wp, wp->w_botline) - wp->w_filler_rows; int extra = 0; - int so = get_scrolloff_value(curwin); + int so = get_scrolloff_value(wp); while (loff.lnum > 1) { // Stop when scrolled nothing or at least "min_scroll", found "extra" // context for 'scrolloff' and counted all lines below the window. if ((((scrolled <= 0 || scrolled >= min_scroll) && extra >= (mouse_dragging > 0 ? mouse_dragging - 1 : so)) - || boff.lnum + 1 > curbuf->b_ml.ml_line_count) - && loff.lnum <= curwin->w_botline - && (loff.lnum < curwin->w_botline + || boff.lnum + 1 > wp->w_buffer->b_ml.ml_line_count) + && loff.lnum <= wp->w_botline + && (loff.lnum < wp->w_botline || loff.fill >= fill_below_window)) { break; } // Add one line above - topline_back(curwin, &loff); + topline_back(wp, &loff); if (loff.height == MAXCOL) { used = MAXCOL; } else { used += loff.height; } - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { break; } - if (loff.lnum >= curwin->w_botline - && (loff.lnum > curwin->w_botline + if (loff.lnum >= wp->w_botline + && (loff.lnum > wp->w_botline || loff.fill <= fill_below_window)) { // Count screen lines that are below the window. scrolled += loff.height; - if (loff.lnum == curwin->w_botline + if (loff.lnum == wp->w_botline && loff.fill == 0) { - scrolled -= curwin->w_empty_rows; + scrolled -= wp->w_empty_rows; } } - if (boff.lnum < curbuf->b_ml.ml_line_count) { + if (boff.lnum < wp->w_buffer->b_ml.ml_line_count) { // Add one line below - botline_forw(curwin, &boff); + botline_forw(wp, &boff); used += boff.height; - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { break; } if (extra < (mouse_dragging > 0 ? mouse_dragging - 1 : so) || scrolled < min_scroll) { extra += boff.height; - if (boff.lnum >= curwin->w_botline - || (boff.lnum + 1 == curwin->w_botline - && boff.fill > curwin->w_filler_rows)) { + if (boff.lnum >= wp->w_botline + || (boff.lnum + 1 == wp->w_botline + && boff.fill > wp->w_filler_rows)) { // Count screen lines that are below the window. scrolled += boff.height; - if (boff.lnum == curwin->w_botline + if (boff.lnum == wp->w_botline && boff.fill == 0) { - scrolled -= curwin->w_empty_rows; + scrolled -= wp->w_empty_rows; } } } @@ -2060,77 +2081,82 @@ void scroll_cursor_bot(int min_scroll, bool set_topbot) } linenr_T line_count; - // curwin->w_empty_rows is larger, no need to scroll + // wp->w_empty_rows is larger, no need to scroll if (scrolled <= 0) { line_count = 0; // more than a screenfull, don't scroll but redraw - } else if (used > curwin->w_height_inner) { + } else if (used > wp->w_height_inner) { line_count = used; // scroll minimal number of lines } else { line_count = 0; - boff.fill = curwin->w_topfill; - boff.lnum = curwin->w_topline - 1; + boff.fill = wp->w_topfill; + boff.lnum = wp->w_topline - 1; int i; - for (i = 0; i < scrolled && boff.lnum < curwin->w_botline;) { - botline_forw(curwin, &boff); + for (i = 0; i < scrolled && boff.lnum < wp->w_botline;) { + botline_forw(wp, &boff); i += boff.height; line_count++; } - if (i < scrolled) { // below curwin->w_botline, don't scroll + if (i < scrolled) { // below wp->w_botline, don't scroll line_count = 9999; } } // Scroll up if the cursor is off the bottom of the screen a bit. // Otherwise put it at 1/2 of the screen. - if (line_count >= curwin->w_height_inner && line_count > min_scroll) { - scroll_cursor_halfway(false, true); + if (line_count >= wp->w_height_inner && line_count > min_scroll) { + scroll_cursor_halfway(wp, false, true); } else if (line_count > 0) { if (do_sms) { - scrollup(scrolled, true); // TODO(vim): + scrollup(wp, scrolled, true); // TODO(vim): } else { - scrollup(line_count, true); + scrollup(wp, line_count, true); } } // If topline didn't change we need to restore w_botline and w_empty_rows // (we changed them). // If topline did change, update_screen() will set botline. - if (curwin->w_topline == old_topline && curwin->w_skipcol == old_skipcol && set_topbot) { - curwin->w_botline = old_botline; - curwin->w_empty_rows = old_empty_rows; - curwin->w_valid = old_valid; + if (wp->w_topline == old_topline && wp->w_skipcol == old_skipcol && set_topbot) { + wp->w_botline = old_botline; + wp->w_empty_rows = old_empty_rows; + wp->w_valid = old_valid; + } + wp->w_valid |= VALID_TOPLINE; + wp->w_viewport_invalid = true; + + // Make sure cursor is still visible after adjusting skipcol for "zb". + if (set_topbot) { + cursor_correct_sms(wp); } - curwin->w_valid |= VALID_TOPLINE; - curwin->w_viewport_invalid = true; } /// Recompute topline to put the cursor halfway across the window /// /// @param atend if true, also put the cursor halfway to the end of the file. /// -void scroll_cursor_halfway(bool atend, bool prefer_above) +void scroll_cursor_halfway(win_T *wp, bool atend, bool prefer_above) { - linenr_T old_topline = curwin->w_topline; - lineoff_T loff = { .lnum = curwin->w_cursor.lnum }; - lineoff_T boff = { .lnum = curwin->w_cursor.lnum }; - hasFolding(loff.lnum, &loff.lnum, &boff.lnum); - int used = plines_win_nofill(curwin, loff.lnum, true); + linenr_T old_topline = wp->w_topline; + lineoff_T loff = { .lnum = wp->w_cursor.lnum }; + lineoff_T boff = { .lnum = wp->w_cursor.lnum }; + hasFolding(wp, loff.lnum, &loff.lnum, &boff.lnum); + int used = plines_win_nofill(wp, loff.lnum, true); loff.fill = 0; boff.fill = 0; linenr_T topline = loff.lnum; colnr_T skipcol = 0; int want_height; - bool do_sms = curwin->w_p_wrap && curwin->w_p_sms; + bool do_sms = wp->w_p_wrap && wp->w_p_sms; if (do_sms) { // 'smoothscroll' and 'wrap' are set if (atend) { - want_height = (curwin->w_height_inner - used) / 2; + want_height = (wp->w_height_inner - used) / 2; used = 0; } else { - want_height = curwin->w_height_inner; + want_height = wp->w_height_inner; } } @@ -2139,20 +2165,20 @@ void scroll_cursor_halfway(bool atend, bool prefer_above) // If using smoothscroll, we can precisely scroll to the // exact point where the cursor is halfway down the screen. if (do_sms) { - topline_back_winheight(curwin, &loff, false); + topline_back_winheight(wp, &loff, false); if (loff.height == MAXCOL) { break; } used += loff.height; - if (!atend && boff.lnum < curbuf->b_ml.ml_line_count) { - botline_forw(curwin, &boff); + if (!atend && boff.lnum < wp->w_buffer->b_ml.ml_line_count) { + botline_forw(wp, &boff); used += boff.height; } if (used > want_height) { if (used - loff.height < want_height) { topline = loff.lnum; topfill = loff.fill; - skipcol = skipcol_from_plines(curwin, used - want_height); + skipcol = skipcol_from_plines(wp, used - want_height); } break; } @@ -2176,10 +2202,10 @@ void scroll_cursor_halfway(bool atend, bool prefer_above) ? (round == 2 && below < above) : (round == 1 && below <= above)) { // add a line below the cursor - if (boff.lnum < curbuf->b_ml.ml_line_count) { - botline_forw(curwin, &boff); + if (boff.lnum < wp->w_buffer->b_ml.ml_line_count) { + botline_forw(wp, &boff); used += boff.height; - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { done = true; break; } @@ -2196,13 +2222,13 @@ void scroll_cursor_halfway(bool atend, bool prefer_above) ? (round == 1 && below >= above) : (round == 1 && below > above)) { // add a line above the cursor - topline_back(curwin, &loff); + topline_back(wp, &loff); if (loff.height == MAXCOL) { used = MAXCOL; } else { used += loff.height; } - if (used > curwin->w_height_inner) { + if (used > wp->w_height_inner) { done = true; break; } @@ -2216,51 +2242,51 @@ void scroll_cursor_halfway(bool atend, bool prefer_above) } } - if (!hasFolding(topline, &curwin->w_topline, NULL) - && (curwin->w_topline != topline || skipcol != 0 || curwin->w_skipcol != 0)) { - curwin->w_topline = topline; + if (!hasFolding(wp, topline, &wp->w_topline, NULL) + && (wp->w_topline != topline || skipcol != 0 || wp->w_skipcol != 0)) { + wp->w_topline = topline; if (skipcol != 0) { - curwin->w_skipcol = skipcol; - redraw_later(curwin, UPD_NOT_VALID); + wp->w_skipcol = skipcol; + redraw_later(wp, UPD_NOT_VALID); } else if (do_sms) { - reset_skipcol(curwin); + reset_skipcol(wp); } } - curwin->w_topfill = topfill; - if (old_topline > curwin->w_topline + curwin->w_height_inner) { - curwin->w_botfill = false; + wp->w_topfill = topfill; + if (old_topline > wp->w_topline + wp->w_height_inner) { + wp->w_botfill = false; } - check_topfill(curwin, false); - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); - curwin->w_valid |= VALID_TOPLINE; + check_topfill(wp, false); + wp->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); + wp->w_valid |= VALID_TOPLINE; } // Correct the cursor position so that it is in a part of the screen at least // 'so' lines from the top and bottom, if possible. // If not possible, put it at the same position as scroll_cursor_halfway(). // When called topline must be valid! -void cursor_correct(void) +void cursor_correct(win_T *wp) { // How many lines we would like to have above/below the cursor depends on // whether the first/last line of the file is on screen. - int above_wanted = get_scrolloff_value(curwin); - int below_wanted = get_scrolloff_value(curwin); + int above_wanted = get_scrolloff_value(wp); + int below_wanted = get_scrolloff_value(wp); if (mouse_dragging > 0) { above_wanted = mouse_dragging - 1; below_wanted = mouse_dragging - 1; } - if (curwin->w_topline == 1) { + if (wp->w_topline == 1) { above_wanted = 0; - int max_off = curwin->w_height_inner / 2; + int max_off = wp->w_height_inner / 2; if (below_wanted > max_off) { below_wanted = max_off; } } - validate_botline(curwin); - if (curwin->w_botline == curbuf->b_ml.ml_line_count + 1 + validate_botline(wp); + if (wp->w_botline == wp->w_buffer->b_ml.ml_line_count + 1 && mouse_dragging == 0) { below_wanted = 0; - int max_off = (curwin->w_height_inner - 1) / 2; + int max_off = (wp->w_height_inner - 1) / 2; if (above_wanted > max_off) { above_wanted = max_off; } @@ -2268,18 +2294,18 @@ void cursor_correct(void) // If there are sufficient file-lines above and below the cursor, we can // return now. - linenr_T cln = curwin->w_cursor.lnum; // Cursor Line Number - if (cln >= curwin->w_topline + above_wanted - && cln < curwin->w_botline - below_wanted - && !hasAnyFolding(curwin)) { + linenr_T cln = wp->w_cursor.lnum; // Cursor Line Number + if (cln >= wp->w_topline + above_wanted + && cln < wp->w_botline - below_wanted + && !hasAnyFolding(wp)) { return; } - if (curwin->w_p_sms && !curwin->w_p_wrap) { + if (wp->w_p_sms && !wp->w_p_wrap) { // 'smoothscroll' is active - if (curwin->w_cline_height == curwin->w_height_inner) { + if (wp->w_cline_height == wp->w_height_inner) { // The cursor line just fits in the window, don't scroll. - reset_skipcol(curwin); + reset_skipcol(wp); return; } // TODO(vim): If the cursor line doesn't fit in the window then only adjust w_skipcol. @@ -2289,419 +2315,236 @@ void cursor_correct(void) // the top and the bottom until: // - the desired context lines are found // - the lines from the top is past the lines from the bottom - linenr_T topline = curwin->w_topline; - linenr_T botline = curwin->w_botline - 1; + linenr_T topline = wp->w_topline; + linenr_T botline = wp->w_botline - 1; // count filler lines as context - int above = curwin->w_topfill; // screen lines above topline - int below = curwin->w_filler_rows; // screen lines below botline + int above = wp->w_topfill; // screen lines above topline + int below = wp->w_filler_rows; // screen lines below botline while ((above < above_wanted || below < below_wanted) && topline < botline) { if (below < below_wanted && (below <= above || above >= above_wanted)) { - if (hasFolding(botline, &botline, NULL)) { + if (hasFolding(wp, botline, &botline, NULL)) { below++; } else { - below += plines_win(curwin, botline, true); + below += plines_win(wp, botline, true); } botline--; } if (above < above_wanted && (above < below || below >= below_wanted)) { - if (hasFolding(topline, NULL, &topline)) { + if (hasFolding(wp, topline, NULL, &topline)) { above++; } else { - above += plines_win_nofill(curwin, topline, true); + above += plines_win_nofill(wp, topline, true); } // Count filler lines below this line as context. if (topline < botline) { - above += win_get_fill(curwin, topline + 1); + above += win_get_fill(wp, topline + 1); } topline++; } } if (topline == botline || botline == 0) { - curwin->w_cursor.lnum = topline; + wp->w_cursor.lnum = topline; } else if (topline > botline) { - curwin->w_cursor.lnum = botline; + wp->w_cursor.lnum = botline; } else { - if (cln < topline && curwin->w_topline > 1) { - curwin->w_cursor.lnum = topline; - curwin->w_valid &= + if (cln < topline && wp->w_topline > 1) { + wp->w_cursor.lnum = topline; + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW); } - if (cln > botline && curwin->w_botline <= curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = botline; - curwin->w_valid &= + if (cln > botline && wp->w_botline <= wp->w_buffer->b_ml.ml_line_count) { + wp->w_cursor.lnum = botline; + wp->w_valid &= ~(VALID_WROW|VALID_WCOL|VALID_CHEIGHT|VALID_CROW); } } - curwin->w_valid |= VALID_TOPLINE; - curwin->w_viewport_invalid = true; + wp->w_valid |= VALID_TOPLINE; + wp->w_viewport_invalid = true; } -/// Move screen "count" pages up ("dir" is BACKWARD) or down ("dir" is FORWARD) -/// and update the screen. +/// Decide how much overlap to use for page-up or page-down scrolling. +/// This is symmetric, so that doing both keeps the same lines displayed. +/// Three lines are examined: /// -/// @return FAIL for failure, OK otherwise. -int onepage(Direction dir, int count) +/// before CTRL-F after CTRL-F / before CTRL-B +/// etc. l1 +/// l1 last but one line ------------ +/// l2 last text line l2 top text line +/// ------------- l3 second text line +/// l3 etc. +static int get_scroll_overlap(Direction dir) { - int retval = OK; lineoff_T loff; - linenr_T old_topline = curwin->w_topline; - int so = get_scrolloff_value(curwin); + int min_height = curwin->w_height_inner - 2; - if (curbuf->b_ml.ml_line_count == 1) { // nothing to do - beep_flush(); - return FAIL; + validate_botline(curwin); + if ((dir == BACKWARD && curwin->w_topline == 1) + || (dir == FORWARD && curwin->w_botline > curbuf->b_ml.ml_line_count)) { + return min_height + 2; // no overlap, still handle 'smoothscroll' } - for (; count > 0; count--) { - validate_botline(curwin); - // It's an error to move a page up when the first line is already on - // the screen. It's an error to move a page down when the last line - // is on the screen and the topline is 'scrolloff' lines from the - // last line. - if (dir == FORWARD - ? ((curwin->w_topline >= curbuf->b_ml.ml_line_count - so) - && curwin->w_botline > curbuf->b_ml.ml_line_count) - : (curwin->w_topline == 1 - && curwin->w_topfill == win_get_fill(curwin, curwin->w_topline))) { - beep_flush(); - retval = FAIL; - break; - } - - loff.fill = 0; - if (dir == FORWARD) { - if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) { - // Vi compatible scrolling - if (p_window <= 2) { - curwin->w_topline++; - } else { - curwin->w_topline += (linenr_T)p_window - 2; - } - if (curwin->w_topline > curbuf->b_ml.ml_line_count) { - curwin->w_topline = curbuf->b_ml.ml_line_count; - } - curwin->w_cursor.lnum = curwin->w_topline; - } else if (curwin->w_botline > curbuf->b_ml.ml_line_count) { - // at end of file - curwin->w_topline = curbuf->b_ml.ml_line_count; - curwin->w_topfill = 0; - curwin->w_valid &= ~(VALID_WROW|VALID_CROW); - } else { - // For the overlap, start with the line just below the window - // and go upwards. - loff.lnum = curwin->w_botline; - loff.fill = win_get_fill(curwin, loff.lnum) - - curwin->w_filler_rows; - get_scroll_overlap(&loff, -1); - curwin->w_topline = loff.lnum; - curwin->w_topfill = loff.fill; - check_topfill(curwin, false); - curwin->w_cursor.lnum = curwin->w_topline; - curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW| - VALID_CROW|VALID_BOTLINE|VALID_BOTLINE_AP); - } - } else { // dir == BACKWARDS - if (curwin->w_topline == 1) { - // Include max number of filler lines - max_topfill(); - continue; - } - if (ONE_WINDOW && p_window > 0 && p_window < Rows - 1) { - // Vi compatible scrolling (sort of) - if (p_window <= 2) { - curwin->w_topline--; - } else { - curwin->w_topline -= (linenr_T)p_window - 2; - } - if (curwin->w_topline < 1) { - curwin->w_topline = 1; - } - curwin->w_cursor.lnum = curwin->w_topline + (linenr_T)p_window - 1; - if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - } - continue; - } - - // Find the line at the top of the window that is going to be the - // line at the bottom of the window. Make sure this results in - // the same line as before doing CTRL-F. - loff.lnum = curwin->w_topline - 1; - loff.fill = win_get_fill(curwin, loff.lnum + 1) - curwin->w_topfill; - get_scroll_overlap(&loff, 1); - - if (loff.lnum >= curbuf->b_ml.ml_line_count) { - loff.lnum = curbuf->b_ml.ml_line_count; - loff.fill = 0; - } else { - botline_topline(&loff); - } - curwin->w_cursor.lnum = loff.lnum; - - // Find the line just above the new topline to get the right line - // at the bottom of the window. - int n = 0; - while (n <= curwin->w_height_inner && loff.lnum >= 1) { - topline_back(curwin, &loff); - if (loff.height == MAXCOL) { - n = MAXCOL; - } else { - n += loff.height; - } - } - if (loff.lnum < 1) { // at begin of file - curwin->w_topline = 1; - max_topfill(); - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - } else { - // Go two lines forward again. - topline_botline(&loff); - botline_forw(curwin, &loff); - botline_forw(curwin, &loff); - botline_topline(&loff); - // We're at the wrong end of a fold now. - hasFoldingWin(curwin, loff.lnum, &loff.lnum, NULL, true, NULL); - - // Always scroll at least one line. Avoid getting stuck on - // very long lines. - if (loff.lnum >= curwin->w_topline - && (loff.lnum > curwin->w_topline - || loff.fill >= curwin->w_topfill)) { - // First try using the maximum number of filler lines. If - // that's not enough, backup one line. - loff.fill = curwin->w_topfill; - if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) { - max_topfill(); - } - if (curwin->w_topfill == loff.fill) { - curwin->w_topline--; - curwin->w_topfill = 0; - curwin->w_valid &= ~(VALID_WROW|VALID_CROW); - } - comp_botline(curwin); - curwin->w_cursor.lnum = curwin->w_botline - 1; - curwin->w_valid &= ~(VALID_WCOL|VALID_CHEIGHT|VALID_WROW|VALID_CROW); - } else { - curwin->w_topline = loff.lnum; - curwin->w_topfill = loff.fill; - check_topfill(curwin, false); - curwin->w_valid &= ~(VALID_WROW|VALID_CROW|VALID_BOTLINE); - } - } - } - } - foldAdjustCursor(); - cursor_correct(); - check_cursor_col(); - if (retval == OK) { - beginline(BL_SOL | BL_FIX); - } - curwin->w_valid &= ~(VALID_WCOL|VALID_WROW|VALID_VIRTCOL); - - if (retval == OK && dir == FORWARD) { - // Avoid the screen jumping up and down when 'scrolloff' is non-zero. - // But make sure we scroll at least one line (happens with mix of long - // wrapping lines and non-wrapping line). - if (check_top_offset()) { - scroll_cursor_top(1, false); - if (curwin->w_topline <= old_topline - && old_topline < curbuf->b_ml.ml_line_count) { - curwin->w_topline = old_topline + 1; - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); - } - } else if (curwin->w_botline > curbuf->b_ml.ml_line_count) { - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); - } - } + loff.lnum = dir == FORWARD ? curwin->w_botline : curwin->w_topline - 1; + loff.fill = win_get_fill(curwin, loff.lnum + (dir == BACKWARD)) + - (dir == FORWARD ? curwin->w_filler_rows : curwin->w_topfill); + loff.height = loff.fill > 0 ? 1 : plines_win_nofill(curwin, loff.lnum, true); - redraw_later(curwin, UPD_VALID); - return retval; -} - -// Decide how much overlap to use for page-up or page-down scrolling. -// This is symmetric, so that doing both keeps the same lines displayed. -// Three lines are examined: -// -// before CTRL-F after CTRL-F / before CTRL-B -// etc. l1 -// l1 last but one line ------------ -// l2 last text line l2 top text line -// ------------- l3 second text line -// l3 etc. -static void get_scroll_overlap(lineoff_T *lp, int dir) -{ - int min_height = curwin->w_height_inner - 2; - - if (lp->fill > 0) { - lp->height = 1; - } else { - lp->height = plines_win_nofill(curwin, lp->lnum, true); - } - int h1 = lp->height; + int h1 = loff.height; if (h1 > min_height) { - return; // no overlap + return min_height + 2; // no overlap } - lineoff_T loff0 = *lp; - if (dir > 0) { - botline_forw(curwin, lp); + if (dir == FORWARD) { + topline_back(curwin, &loff); } else { - topline_back(curwin, lp); + botline_forw(curwin, &loff); } - int h2 = lp->height; + + int h2 = loff.height; if (h2 == MAXCOL || h2 + h1 > min_height) { - *lp = loff0; // no overlap - return; + return min_height + 2; // no overlap } - - lineoff_T loff1 = *lp; - if (dir > 0) { - botline_forw(curwin, lp); + if (dir == FORWARD) { + topline_back(curwin, &loff); } else { - topline_back(curwin, lp); + botline_forw(curwin, &loff); } - int h3 = lp->height; + + int h3 = loff.height; if (h3 == MAXCOL || h3 + h2 > min_height) { - *lp = loff0; // no overlap - return; + return min_height + 2; // no overlap } - - lineoff_T loff2 = *lp; - if (dir > 0) { - botline_forw(curwin, lp); + if (dir == FORWARD) { + topline_back(curwin, &loff); } else { - topline_back(curwin, lp); + botline_forw(curwin, &loff); } - int h4 = lp->height; + + int h4 = loff.height; if (h4 == MAXCOL || h4 + h3 + h2 > min_height || h3 + h2 + h1 > min_height) { - *lp = loff1; // 1 line overlap + return min_height + 1; // 1 line overlap } else { - *lp = loff2; // 2 lines overlap + return min_height; // 2 lines overlap } } -// Scroll 'scroll' lines up or down. -void halfpage(bool flag, linenr_T Prenum) +/// Scroll "count" lines with 'smoothscroll' in direction "dir". Return true +/// when scrolling happened. Adjust "curscount" for scrolling different amount +/// of lines when 'smoothscroll' is disabled. +static bool scroll_with_sms(Direction dir, int count, int *curscount) { - int scrolled = 0; - int i; - - if (Prenum) { - curwin->w_p_scr = (Prenum > curwin->w_height_inner) ? curwin->w_height_inner - : Prenum; - } - assert(curwin->w_p_scr <= INT_MAX); - int n = curwin->w_p_scr <= curwin->w_height_inner ? (int)curwin->w_p_scr - : curwin->w_height_inner; + int prev_sms = curwin->w_p_sms; + colnr_T prev_skipcol = curwin->w_skipcol; + linenr_T prev_topline = curwin->w_topline; + int prev_topfill = curwin->w_topfill; + + curwin->w_p_sms = true; + scroll_redraw(dir == FORWARD, count); + + // Not actually smoothscrolling but ended up with partially visible line. + // Continue scrolling until skipcol is zero. + if (!prev_sms && curwin->w_skipcol > 0) { + int fixdir = dir; + // Reverse the scroll direction when topline already changed. One line + // extra for scrolling backward so that consuming skipcol is symmetric. + if (labs(curwin->w_topline - prev_topline) > (dir == BACKWARD)) { + fixdir = dir * -1; + } + while (curwin->w_skipcol > 0 + && curwin->w_topline < curbuf->b_ml.ml_line_count) { + scroll_redraw(fixdir == FORWARD, 1); + *curscount += (fixdir == dir ? 1 : -1); + } + } + curwin->w_p_sms = prev_sms; + + return curwin->w_topline == prev_topline + && curwin->w_topfill == prev_topfill + && curwin->w_skipcol == prev_skipcol; +} - update_topline(curwin); - validate_botline(curwin); - int room = curwin->w_empty_rows + curwin->w_filler_rows; - if (flag) { - // scroll the text up - while (n > 0 && curwin->w_botline <= curbuf->b_ml.ml_line_count) { - if (curwin->w_topfill > 0) { - i = 1; - n--; - curwin->w_topfill--; - } else { - i = plines_win_nofill(curwin, curwin->w_topline, true); - n -= i; - if (n < 0 && scrolled > 0) { - break; - } - hasFolding(curwin->w_topline, NULL, &curwin->w_topline); - curwin->w_topline++; - curwin->w_topfill = win_get_fill(curwin, curwin->w_topline); - - if (curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - curwin->w_cursor.lnum++; - curwin->w_valid &= - ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); - } +/// Move screen "count" (half) pages up ("dir" is BACKWARD) or down ("dir" is +/// FORWARD) and update the screen. Handle moving the cursor and not scrolling +/// to reveal end of buffer lines for half-page scrolling with CTRL-D and CTRL-U. +/// +/// @return FAIL for failure, OK otherwise. +int pagescroll(Direction dir, int count, bool half) +{ + int nochange = true; + int buflen = curbuf->b_ml.ml_line_count; + colnr_T prev_col = curwin->w_cursor.col; + colnr_T prev_curswant = curwin->w_curswant; + linenr_T prev_lnum = curwin->w_cursor.lnum; + oparg_T oa = { 0 }; + cmdarg_T ca = { 0 }; + ca.oap = &oa; + + if (half) { + // Scroll [count], 'scroll' or current window height lines. + if (count) { + curwin->w_p_scr = MIN(curwin->w_height_inner, count); + } + count = MIN(curwin->w_height_inner, (int)curwin->w_p_scr); + + int curscount = count; + // Adjust count so as to not reveal end of buffer lines. + if (dir == FORWARD + && (curwin->w_topline + curwin->w_height_inner + count > buflen || hasAnyFolding(curwin))) { + int n = plines_correct_topline(curwin, curwin->w_topline, NULL, false, NULL); + if (n - count < curwin->w_height_inner && curwin->w_topline < buflen) { + n += plines_m_win(curwin, curwin->w_topline + 1, buflen, curwin->w_height_inner + count); } - curwin->w_valid &= ~(VALID_CROW|VALID_WROW); - scrolled += i; - - // Correct w_botline for changed w_topline. - // Won't work when there are filler lines. - if (win_may_fill(curwin)) { - curwin->w_valid &= ~(VALID_BOTLINE|VALID_BOTLINE_AP); - } else { - room += i; - do { - i = plines_win(curwin, curwin->w_botline, true); - if (i > room) { - break; - } - hasFolding(curwin->w_botline, NULL, &curwin->w_botline); - curwin->w_botline++; - room -= i; - } while (curwin->w_botline <= curbuf->b_ml.ml_line_count); + if (n < curwin->w_height_inner + count) { + count = n - curwin->w_height_inner; } } - // When hit bottom of the file: move cursor down. - if (n > 0) { - if (hasAnyFolding(curwin)) { - while (--n >= 0 - && curwin->w_cursor.lnum < curbuf->b_ml.ml_line_count) { - hasFolding(curwin->w_cursor.lnum, NULL, - &curwin->w_cursor.lnum); - curwin->w_cursor.lnum++; - } - } else { - curwin->w_cursor.lnum += n; - } - check_cursor_lnum(curwin); - } - } else { - // scroll the text down - while (n > 0 && curwin->w_topline > 1) { - if (curwin->w_topfill < win_get_fill(curwin, curwin->w_topline)) { - i = 1; - n--; - curwin->w_topfill++; - } else { - i = plines_win_nofill(curwin, curwin->w_topline - 1, true); - n -= i; - if (n < 0 && scrolled > 0) { - break; - } - curwin->w_topline--; - hasFolding(curwin->w_topline, &curwin->w_topline, NULL); - curwin->w_topfill = 0; - } - curwin->w_valid &= ~(VALID_CROW|VALID_WROW| - VALID_BOTLINE|VALID_BOTLINE_AP); - scrolled += i; - if (curwin->w_cursor.lnum > 1) { - curwin->w_cursor.lnum--; - curwin->w_valid &= ~(VALID_VIRTCOL|VALID_CHEIGHT|VALID_WCOL); - } + // (Try to) scroll the window unless already at the end of the buffer. + if (count > 0) { + nochange = scroll_with_sms(dir, count, &curscount); + curwin->w_cursor.lnum = prev_lnum; + curwin->w_cursor.col = prev_col; + curwin->w_curswant = prev_curswant; } - // When hit top of the file: move cursor up. - if (n > 0) { - if (curwin->w_cursor.lnum <= (linenr_T)n) { - curwin->w_cursor.lnum = 1; - } else if (hasAnyFolding(curwin)) { - while (--n >= 0 && curwin->w_cursor.lnum > 1) { - curwin->w_cursor.lnum--; - hasFolding(curwin->w_cursor.lnum, - &curwin->w_cursor.lnum, NULL); - } - } else { - curwin->w_cursor.lnum -= n; - } + // Move the cursor the same amount of screen lines. + if (curwin->w_p_wrap) { + nv_screengo(&oa, dir, curscount); + } else if (dir == FORWARD) { + cursor_down_inner(curwin, curscount); + } else { + cursor_up_inner(curwin, curscount); } + } else { + // Scroll [count] times 'window' or current window height lines. + count *= ((ONE_WINDOW && p_window > 0 && p_window < Rows - 1) + ? MAX(1, (int)p_window - 2) : get_scroll_overlap(dir)); + nochange = scroll_with_sms(dir, count, &count); + + // Place cursor at top or bottom of window. + validate_botline(curwin); + curwin->w_cursor.lnum = (dir == FORWARD ? curwin->w_topline : curwin->w_botline - 1); + } + + if (get_scrolloff_value(curwin) > 0) { + cursor_correct(curwin); } // Move cursor to first line of closed fold. - foldAdjustCursor(); - check_topfill(curwin, !flag); - cursor_correct(); - beginline(BL_SOL | BL_FIX); - redraw_later(curwin, UPD_VALID); + foldAdjustCursor(curwin); + + nochange = nochange + && prev_col == curwin->w_cursor.col + && prev_lnum == curwin->w_cursor.lnum; + + // Error if both the viewport and cursor did not change. + if (nochange) { + beep_flush(); + } else if (!curwin->w_p_sms) { + beginline(BL_SOL | BL_FIX); + } else if (p_sol) { + nv_g_home_m_cmd(&ca); + } + + return nochange; } void do_check_cursorbind(void) @@ -2748,12 +2591,12 @@ void do_check_cursorbind(void) { int restart_edit_save = restart_edit; restart_edit = true; - check_cursor(); + check_cursor(curwin); // Avoid a scroll here for the cursor position, 'scrollbind' is // more important. if (!curwin->w_p_scb) { - validate_cursor(); + validate_cursor(curwin); } restart_edit = restart_edit_save; diff --git a/src/nvim/msgpack_rpc/channel.c b/src/nvim/msgpack_rpc/channel.c index a8fde5a652..5737a0440f 100644 --- a/src/nvim/msgpack_rpc/channel.c +++ b/src/nvim/msgpack_rpc/channel.c @@ -67,8 +67,6 @@ static void log_notify(char *dir, uint64_t channel_id, const char *name) # define log_notify(...) #endif -static Set(cstr_t) event_strings = SET_INIT; - #ifdef INCLUDE_GENERATED_DECLARATIONS # include "msgpack_rpc/channel.c.generated.h" #endif @@ -111,9 +109,9 @@ static Channel *find_rpc_channel(uint64_t id) return chan; } -/// Publishes an event to a channel. +/// Publishes an event to a channel (emits a notification to method `name`). /// -/// @param id Channel id. 0 means "broadcast to all subscribed channels" +/// @param id Channel id, or 0 to broadcast to all RPC channels. /// @param name Event name (application-defined) /// @param args Array of event arguments /// @return True if the event was sent successfully, false otherwise. @@ -204,41 +202,6 @@ Object rpc_send_call(uint64_t id, const char *method_name, Array args, ArenaMem return frame.errored ? NIL : frame.result; } -/// Subscribes to event broadcasts -/// -/// @param id The channel id -/// @param event The event type string -void rpc_subscribe(uint64_t id, char *event) -{ - Channel *channel; - - if (!(channel = find_rpc_channel(id))) { - abort(); - } - - const char **key_alloc = NULL; - if (set_put_ref(cstr_t, &event_strings, event, &key_alloc)) { - *key_alloc = xstrdup(event); - } - - set_put(cstr_t, channel->rpc.subscribed_events, *key_alloc); -} - -/// Unsubscribes to event broadcasts -/// -/// @param id The channel id -/// @param event The event type string -void rpc_unsubscribe(uint64_t id, char *event) -{ - Channel *channel; - - if (!(channel = find_rpc_channel(id))) { - abort(); - } - - unsubscribe(channel, event); -} - static void receive_msgpack(Stream *stream, RBuffer *rbuf, size_t c, void *data, bool eof) { Channel *channel = data; @@ -289,8 +252,9 @@ static void parse_msgpack(Channel *channel) if (p->type == kMessageTypeRedrawEvent) { // When exiting, ui_client_stop() has already been called, so don't handle UI events. if (ui_client_channel_id && !exiting) { - if (p->grid_line_event) { - ui_client_event_raw_line(p->grid_line_event); + if (p->has_grid_line_event) { + ui_client_event_raw_line(&p->grid_line_event); + p->has_grid_line_event = false; } else if (p->ui_handler.fn != NULL && p->result.type == kObjectTypeArray) { p->ui_handler.fn(p->result.data.array); } @@ -339,7 +303,7 @@ static void parse_msgpack(Channel *channel) } if (unpacker_closed(p)) { - chan_close_with_error(channel, p->unpack_error.msg, LOGLVL_ERR); + chan_close_with_error(channel, p->unpack_error.msg, LOGLVL_INF); api_clear_error(&p->unpack_error); } } @@ -493,34 +457,24 @@ static void send_error(Channel *chan, MsgpackRpcRequestHandler handler, MessageT api_clear_error(&e); } +/// Broadcasts a notification to all RPC channels. static void broadcast_event(const char *name, Array args) { - kvec_withinit_t(Channel *, 4) subscribed = KV_INITIAL_VALUE; - kvi_init(subscribed); + kvec_withinit_t(Channel *, 4) chans = KV_INITIAL_VALUE; + kvi_init(chans); Channel *channel; map_foreach_value(&channels, channel, { - if (channel->is_rpc - && set_has(cstr_t, channel->rpc.subscribed_events, name)) { - kv_push(subscribed, channel); + if (channel->is_rpc) { + kv_push(chans, channel); } }); - if (kv_size(subscribed)) { - serialize_request(subscribed.items, kv_size(subscribed), 0, name, args); + if (kv_size(chans)) { + serialize_request(chans.items, kv_size(chans), 0, name, args); } - kvi_destroy(subscribed); -} - -static void unsubscribe(Channel *channel, char *event) -{ - if (!set_has(cstr_t, &event_strings, event)) { - WLOG("RPC: ch %" PRIu64 ": tried to unsubscribe unknown event '%s'", - channel->id, event); - return; - } - set_del(cstr_t, channel->rpc.subscribed_events, event); + kvi_destroy(chans); } /// Mark rpc state as closed, and release its reference to the channel. @@ -550,7 +504,6 @@ void rpc_free(Channel *channel) unpacker_teardown(channel->rpc.unpacker); xfree(channel->rpc.unpacker); - set_destroy(cstr_t, channel->rpc.subscribed_events); kv_destroy(channel->rpc.call_stack); api_free_dictionary(channel->rpc.info); } @@ -718,12 +671,6 @@ const char *get_client_info(Channel *chan, const char *key) #ifdef EXITFREE void rpc_free_all_mem(void) { - cstr_t key; - set_foreach(&event_strings, key, { - xfree((void *)key); - }); - set_destroy(cstr_t, &event_strings); - multiqueue_free(ch_before_blocking_events); } #endif diff --git a/src/nvim/msgpack_rpc/channel_defs.h b/src/nvim/msgpack_rpc/channel_defs.h index 56dbb332e0..7dc1374964 100644 --- a/src/nvim/msgpack_rpc/channel_defs.h +++ b/src/nvim/msgpack_rpc/channel_defs.h @@ -37,7 +37,6 @@ typedef struct { } RequestEvent; typedef struct { - Set(cstr_t) subscribed_events[1]; bool closed; Unpacker *unpacker; uint32_t next_request_id; diff --git a/src/nvim/msgpack_rpc/unpacker.c b/src/nvim/msgpack_rpc/unpacker.c index dbb30b0c9a..28d27e8268 100644 --- a/src/nvim/msgpack_rpc/unpacker.c +++ b/src/nvim/msgpack_rpc/unpacker.c @@ -187,6 +187,8 @@ void unpacker_init(Unpacker *p) p->unpack_error = ERROR_INIT; p->arena = (Arena)ARENA_EMPTY; + + p->has_grid_line_event = false; } void unpacker_teardown(Unpacker *p) @@ -303,6 +305,7 @@ error: bool unpacker_advance(Unpacker *p) { assert(p->state >= 0); + p->has_grid_line_event = false; if (p->state == 0) { if (!unpacker_parse_header(p)) { return false; @@ -323,6 +326,7 @@ bool unpacker_advance(Unpacker *p) if (p->state == 16) { // grid_line event already unpacked + p->has_grid_line_event = true; goto done; } else { assert(p->state == 12); @@ -378,7 +382,7 @@ bool unpacker_parse_redraw(Unpacker *p) const char *data = p->read_ptr; size_t size = p->read_size; - GridLineEvent *g = p->grid_line_event; + GridLineEvent *g = &p->grid_line_event; #define NEXT_TYPE(tok, typ) \ result = mpack_rtoken(&data, &size, &tok); \ @@ -420,16 +424,10 @@ bool unpacker_parse_redraw(Unpacker *p) p->read_size = size; if (p->ui_handler.fn != ui_client_event_grid_line) { p->state = 12; - if (p->grid_line_event) { - arena_mem_free(arena_finish(&p->arena)); - p->grid_line_event = NULL; - } return true; } else { p->state = 14; p->arena = (Arena)ARENA_EMPTY; - p->grid_line_event = arena_alloc(&p->arena, sizeof *p->grid_line_event, true); - g = p->grid_line_event; } FALLTHROUGH; diff --git a/src/nvim/msgpack_rpc/unpacker.h b/src/nvim/msgpack_rpc/unpacker.h index 022d778013..ed55fdd4af 100644 --- a/src/nvim/msgpack_rpc/unpacker.h +++ b/src/nvim/msgpack_rpc/unpacker.h @@ -37,7 +37,8 @@ struct Unpacker { int nevents; int ncalls; UIClientHandler ui_handler; - GridLineEvent *grid_line_event; + GridLineEvent grid_line_event; + bool has_grid_line_event; }; // unrecovareble error. unpack_error should be set! diff --git a/src/nvim/normal.c b/src/nvim/normal.c index 8ff47097fa..8ba375f29d 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -32,6 +32,7 @@ #include "nvim/ex_cmds.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_docmd.h" +#include "nvim/ex_eval.h" #include "nvim/ex_getln.h" #include "nvim/fileio.h" #include "nvim/fold.h" @@ -47,6 +48,7 @@ #include "nvim/mapping.h" #include "nvim/mark.h" #include "nvim/mark_defs.h" +#include "nvim/math.h" #include "nvim/mbyte.h" #include "nvim/memline.h" #include "nvim/memline_defs.h" @@ -748,7 +750,7 @@ static void normal_get_additional_char(NormalState *s) bool langmap_active = false; // using :lmap mappings if (repl) { State = MODE_REPLACE; // pretend Replace mode - ui_cursor_shape(); // show different cursor shape + ui_cursor_shape_no_check_conceal(); // show different cursor shape } if (lang && curbuf->b_p_iminsert == B_IMODE_LMAP) { // Allow mappings defined with ":lmap". @@ -891,8 +893,8 @@ static bool normal_get_command_count(NormalState *s) // Handle a count before a command and compute ca.count0. // Note that '0' is a command and not the start of a count, but it's // part of a count after other digits. - while ((s->c >= '1' && s->c <= '9') || (s->ca.count0 != 0 - && (s->c == K_DEL || s->c == K_KDEL || s->c == '0'))) { + while ((s->c >= '1' && s->c <= '9') + || (s->ca.count0 != 0 && (s->c == K_DEL || s->c == K_KDEL || s->c == '0'))) { if (s->c == K_DEL || s->c == K_KDEL) { s->ca.count0 /= 10; del_from_showcmd(4); // delete the digit and ~@% @@ -1009,12 +1011,12 @@ normal_end: mb_check_adjust_col(curwin); // #6203 if (curwin->w_p_scb && s->toplevel) { - validate_cursor(); // may need to update w_leftcol + validate_cursor(curwin); // may need to update w_leftcol do_check_scrollbind(true); } if (curwin->w_p_crb && s->toplevel) { - validate_cursor(); // may need to update w_leftcol + validate_cursor(curwin); // may need to update w_leftcol do_check_cursorbind(); } @@ -1078,7 +1080,7 @@ static int normal_execute(VimState *state, int key) // When "restart_edit" is set fake a "d"elete command, Insert mode will restart automatically. // Insert the typed character in the typeahead buffer, so that it can // be mapped in Insert mode. Required for ":lmap" to work. - int len = ins_char_typebuf(vgetc_char, vgetc_mod_mask); + int len = ins_char_typebuf(vgetc_char, vgetc_mod_mask, true); // When recording and gotchars() was called the character will be // recorded again, remove the previous recording. @@ -1343,7 +1345,7 @@ static void normal_redraw(NormalState *s) // Before redrawing, make sure w_topline is correct, and w_leftcol // if lines don't wrap, and w_skipcol if lines wrap. update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); show_cursor_info_later(false); @@ -1403,6 +1405,12 @@ static int normal_check(VimState *state) normal_check_stuff_buffer(s); normal_check_interrupt(s); + // At the toplevel there is no exception handling. Discard any that + // may be hanging around (e.g. from "interrupt" at the debug prompt). + if (did_throw && !ex_normal_busy) { + discard_current_exception(); + } + if (!exmode_active) { msg_scroll = false; } @@ -1420,7 +1428,7 @@ static int normal_check(VimState *state) // Ensure curwin->w_topline and curwin->w_leftcol are up to date // before triggering a WinScrolled autocommand. update_topline(curwin); - validate_cursor(); + validate_cursor(curwin); normal_check_cursor_moved(s); normal_check_text_changed(s); @@ -1515,7 +1523,7 @@ void end_visual_mode(void) curbuf->b_visual.vi_end = curwin->w_cursor; curbuf->b_visual.vi_curswant = curwin->w_curswant; curbuf->b_visual_mode_eval = VIsual_mode; - if (!virtual_active()) { + if (!virtual_active(curwin)) { curwin->w_cursor.coladd = 0; } @@ -1863,8 +1871,8 @@ void clear_showcmd(void) bot = VIsual.lnum; } // Include closed folds as a whole. - hasFolding(top, &top, NULL); - hasFolding(bot, NULL, &bot); + hasFolding(curwin, top, &top, NULL); + hasFolding(curwin, bot, NULL, &bot); lines = bot - top + 1; if (VIsual_mode == Ctrl_V) { @@ -1960,9 +1968,16 @@ bool add_to_showcmd(int c) } } - char *p = transchar(c); - if (*p == ' ') { - STRCPY(p, "<20>"); + char *p; + char mbyte_buf[MB_MAXCHAR + 1]; + if (c <= 0x7f || !vim_isprintc(c)) { + p = transchar(c); + if (*p == ' ') { + STRCPY(p, "<20>"); + } + } else { + mbyte_buf[utf_char2bytes(c, mbyte_buf)] = NUL; + p = mbyte_buf; } size_t old_len = strlen(showcmd_buf); size_t extra_len = strlen(p); @@ -2028,8 +2043,7 @@ void pop_showcmd(void) static void display_showcmd(void) { - int len = (int)strlen(showcmd_buf); - showcmd_is_clear = (len == 0); + showcmd_is_clear = (showcmd_buf[0] == NUL); if (*p_sloc == 's') { if (showcmd_is_clear) { @@ -2050,14 +2064,11 @@ static void display_showcmd(void) return; } // 'showcmdloc' is "last" or empty - if (p_ch == 0 && !ui_has(kUIMessages)) { - return; - } if (ui_has(kUIMessages)) { MAXSIZE_TEMP_ARRAY(content, 1); MAXSIZE_TEMP_ARRAY(chunk, 2); - if (len > 0) { + if (!showcmd_is_clear) { // placeholder for future highlight support ADD_C(chunk, INTEGER_OBJ(0)); ADD_C(chunk, CSTR_AS_OBJ(showcmd_buf)); @@ -2066,13 +2077,17 @@ static void display_showcmd(void) ui_call_msg_showcmd(content); return; } + if (p_ch == 0) { + return; + } msg_grid_validate(); int showcmd_row = Rows - 1; grid_line_start(&msg_grid_adj, showcmd_row); + int len = 0; if (!showcmd_is_clear) { - grid_line_puts(sc_col, showcmd_buf, -1, HL_ATTR(HLF_MSG)); + len = grid_line_puts(sc_col, showcmd_buf, -1, HL_ATTR(HLF_MSG)); } // clear the rest of an old message by outputting up to SHOWCMD_COLS spaces @@ -2174,14 +2189,14 @@ void check_scrollbind(linenr_T topline_diff, int leftcol_diff) y = topline - curwin->w_topline; if (y > 0) { - scrollup(y, false); + scrollup(curwin, y, false); } else { - scrolldown(-y, false); + scrolldown(curwin, -y, false); } } redraw_later(curwin, UPD_VALID); - cursor_correct(); + cursor_correct(curwin); curwin->w_redr_status = true; } @@ -2258,7 +2273,7 @@ static void nv_page(cmdarg_T *cap) goto_tabpage(cap->count0); } } else { - onepage(cap->arg, cap->count1); + pagescroll(cap->arg, cap->count1, false); } } @@ -2334,13 +2349,15 @@ bool find_decl(char *ptr, size_t len, bool locally, bool thisblock, int flags_ar bool incll; int searchflags = flags_arg; - size_t patlen = len + 7; - char *pat = xmalloc(patlen); + size_t patsize = len + 7; + char *pat = xmalloc(patsize); // Put "\V" before the pattern to avoid that the special meaning of "." // and "~" causes trouble. - assert(patlen <= INT_MAX); - snprintf(pat, patlen, vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", (int)len, ptr); + assert(patsize <= INT_MAX); + size_t patlen = (size_t)snprintf(pat, patsize, + vim_iswordp(ptr) ? "\\V\\<%.*s\\>" : "\\V%.*s", + (int)len, ptr); pos_T old_pos = curwin->w_cursor; bool save_p_ws = p_ws; bool save_p_scs = p_scs; @@ -2367,7 +2384,7 @@ bool find_decl(char *ptr, size_t len, bool locally, bool thisblock, int flags_ar clearpos(&found_pos); while (true) { t = searchit(curwin, curbuf, &curwin->w_cursor, NULL, FORWARD, - pat, 1, searchflags, RE_LAST, NULL); + pat, patlen, 1, searchflags, RE_LAST, NULL); if (curwin->w_cursor.lnum >= old_pos.lnum) { t = false; // match after start is failure too } @@ -2453,7 +2470,7 @@ bool find_decl(char *ptr, size_t len, bool locally, bool thisblock, int flags_ar /// 'dist' must be positive. /// /// @return true if able to move cursor, false otherwise. -static bool nv_screengo(oparg_T *oap, int dir, int dist) +bool nv_screengo(oparg_T *oap, int dir, int dist) { int linelen = linetabsize(curwin, curwin->w_cursor.lnum); bool retval = true; @@ -2466,8 +2483,8 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) oap->motion_type = kMTCharWise; oap->inclusive = (curwin->w_curswant == MAXCOL); - col_off1 = curwin_col_off(); - col_off2 = col_off1 - curwin_col_off2(); + col_off1 = win_col_off(curwin); + col_off2 = col_off1 - win_col_off2(curwin); width1 = curwin->w_width_inner - col_off1; width2 = curwin->w_width_inner - col_off2; @@ -2481,7 +2498,7 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) // try to stick in the last column of the screen. if (curwin->w_curswant == MAXCOL) { atend = true; - validate_virtcol(); + validate_virtcol(curwin); if (width1 <= 0) { curwin->w_curswant = 0; } else { @@ -2506,7 +2523,7 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) while (dist--) { if (dir == BACKWARD) { if (curwin->w_curswant >= width1 - && !hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + && !hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { // Move back within the line. This can give a negative value // for w_curswant if width1 < width2 (with cpoptions+=n), // which will get clipped to column 0. @@ -2533,7 +2550,7 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) n = width1; } if (curwin->w_curswant + width2 < (colnr_T)n - && !hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + && !hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { // move forward within line curwin->w_curswant += width2; } else { @@ -2558,17 +2575,17 @@ static bool nv_screengo(oparg_T *oap, int dir, int dist) } } - if (virtual_active() && atend) { - coladvance(MAXCOL); + if (virtual_active(curwin) && atend) { + coladvance(curwin, MAXCOL); } else { - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } if (curwin->w_cursor.col > 0 && curwin->w_p_wrap) { // Check for landing on a character that got split at the end of the // last line. We want to advance a screenline, not end up in the same // screenline or move two screenlines. - validate_virtcol(); + validate_virtcol(curwin); colnr_T virtcol = curwin->w_virtcol; if (virtcol > (colnr_T)width1 && *get_showbreak_value(curwin) != NUL) { virtcol -= vim_strsize(get_showbreak_value(curwin)); @@ -2607,58 +2624,6 @@ void nv_scroll_line(cmdarg_T *cap) } } -/// Scroll "count" lines up or down, and redraw. -void scroll_redraw(bool up, linenr_T count) -{ - linenr_T prev_topline = curwin->w_topline; - int prev_skipcol = curwin->w_skipcol; - int prev_topfill = curwin->w_topfill; - linenr_T prev_lnum = curwin->w_cursor.lnum; - - bool moved = up - ? scrollup(count, true) - : scrolldown(count, true); - - if (get_scrolloff_value(curwin) > 0) { - // Adjust the cursor position for 'scrolloff'. Mark w_topline as - // valid, otherwise the screen jumps back at the end of the file. - cursor_correct(); - check_cursor_moved(curwin); - curwin->w_valid |= VALID_TOPLINE; - - // If moved back to where we were, at least move the cursor, otherwise - // we get stuck at one position. Don't move the cursor up if the - // first line of the buffer is already on the screen - while (curwin->w_topline == prev_topline - && curwin->w_skipcol == prev_skipcol - && curwin->w_topfill == prev_topfill) { - if (up) { - if (curwin->w_cursor.lnum > prev_lnum - || cursor_down(1, false) == false) { - break; - } - } else { - if (curwin->w_cursor.lnum < prev_lnum - || prev_topline == 1 - || cursor_up(1, false) == false) { - break; - } - } - // Mark w_topline as valid, otherwise the screen jumps back at the - // end of the file. - check_cursor_moved(curwin); - curwin->w_valid |= VALID_TOPLINE; - } - } - if (curwin->w_cursor.lnum != prev_lnum) { - coladvance(curwin->w_curswant); - } - if (moved) { - curwin->w_viewport_invalid = true; - } - redraw_later(curwin, UPD_VALID); -} - /// Get the count specified after a 'z' command. Only the 'z<CR>', 'zl', 'zh', /// 'z<Left>', and 'z<Right>' commands accept a count after 'z'. /// @return true to process the 'z' command and false to skip it. @@ -2684,11 +2649,10 @@ static bool nv_z_get_count(cmdarg_T *cap, int *nchar_arg) if (nchar == K_DEL || nchar == K_KDEL) { n /= 10; } else if (ascii_isdigit(nchar)) { - if (n > INT_MAX / 10) { + if (vim_append_digit_int(&n, nchar - '0') == FAIL) { clearopbeep(cap->oap); break; } - n = n * 10 + (nchar - '0'); } else if (nchar == CAR) { win_setheight(n); break; @@ -2748,7 +2712,7 @@ static int nv_zg_zw(cmdarg_T *cap, int nchar) // off this fails and find_ident_under_cursor() is // used below. emsg_off++; - len = spell_move_to(curwin, FORWARD, true, true, NULL); + len = spell_move_to(curwin, FORWARD, SMT_ALL, true, NULL); emsg_off--; if (len != 0 && curwin->w_cursor.col <= pos.col) { ptr = ml_get_pos(&curwin->w_cursor); @@ -2803,7 +2767,7 @@ static void nv_zet(cmdarg_T *cap) } else { curwin->w_cursor.lnum = cap->count0; } - check_cursor_col(); + check_cursor_col(curwin); } switch (nchar) { @@ -2826,7 +2790,7 @@ static void nv_zet(cmdarg_T *cap) FALLTHROUGH; case 't': - scroll_cursor_top(0, true); + scroll_cursor_top(curwin, 0, true); redraw_later(curwin, UPD_VALID); set_fraction(curwin); break; @@ -2837,7 +2801,7 @@ static void nv_zet(cmdarg_T *cap) FALLTHROUGH; case 'z': - scroll_cursor_halfway(true, false); + scroll_cursor_halfway(curwin, true, false); redraw_later(curwin, UPD_VALID); set_fraction(curwin); break; @@ -2847,7 +2811,7 @@ static void nv_zet(cmdarg_T *cap) // when <count> is at bottom of window, and puts that one at // bottom of window. if (cap->count0 != 0) { - scroll_cursor_bot(0, true); + scroll_cursor_bot(curwin, 0, true); curwin->w_cursor.lnum = curwin->w_topline; } else if (curwin->w_topline == 1) { curwin->w_cursor.lnum = 1; @@ -2860,7 +2824,7 @@ static void nv_zet(cmdarg_T *cap) FALLTHROUGH; case 'b': - scroll_cursor_bot(0, true); + scroll_cursor_bot(curwin, 0, true); redraw_later(curwin, UPD_VALID); set_fraction(curwin); break; @@ -2895,7 +2859,7 @@ static void nv_zet(cmdarg_T *cap) // "zs" - scroll screen, cursor at the start case 's': if (!curwin->w_p_wrap) { - if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { col = 0; // like the cursor is in col 0 } else { getvcol(curwin, &curwin->w_cursor, &col, NULL, NULL); @@ -2915,12 +2879,12 @@ static void nv_zet(cmdarg_T *cap) // "ze" - scroll screen, cursor at the end case 'e': if (!curwin->w_p_wrap) { - if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { col = 0; // like the cursor is in col 0 } else { getvcol(curwin, &curwin->w_cursor, NULL, NULL, &col); } - int n = curwin->w_width_inner - curwin_col_off(); + int n = curwin->w_width_inner - win_col_off(curwin); if (col + siso < n) { col = 0; } else { @@ -2980,7 +2944,7 @@ static void nv_zet(cmdarg_T *cap) case 'E': if (foldmethodIsManual(curwin)) { clearFolding(curwin); - changed_window_setting(); + changed_window_setting(curwin); } else if (foldmethodIsMarker(curwin)) { deleteFold(curwin, 1, curbuf->b_ml.ml_line_count, true, false); } else { @@ -3005,7 +2969,7 @@ static void nv_zet(cmdarg_T *cap) // "za": open closed fold or close open fold at cursor case 'a': - if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { openFold(curwin->w_cursor, cap->count1); } else { closeFold(curwin->w_cursor, cap->count1); @@ -3015,7 +2979,7 @@ static void nv_zet(cmdarg_T *cap) // "zA": open fold at cursor recursively case 'A': - if (hasFolding(curwin->w_cursor.lnum, NULL, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL)) { openFoldRecurse(curwin->w_cursor); } else { closeFoldRecurse(curwin->w_cursor); @@ -3151,11 +3115,11 @@ static void nv_zet(cmdarg_T *cap) FOR_ALL_WINDOWS_IN_TAB(wp, curtab) { if (wp != curwin && foldmethodIsDiff(wp) && wp->w_p_scb) { wp->w_p_fen = curwin->w_p_fen; - changed_window_setting_win(wp); + changed_window_setting(wp); } } } - changed_window_setting(); + changed_window_setting(curwin); } // Redraw when 'foldlevel' changed. @@ -3223,8 +3187,7 @@ static void nv_colon(cmdarg_T *cap) 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)) + || cap->oap->start.col > ml_get_len(cap->oap->start.lnum) || did_emsg)) { // The start of the operator has become invalid by the Ex command. clearopbeep(cap->oap); @@ -3335,21 +3298,22 @@ void do_nv_ident(int c1, int c2) /// 'K' normal-mode command. Get the command to lookup the keyword under the /// cursor. static size_t nv_K_getcmd(cmdarg_T *cap, char *kp, bool kp_help, bool kp_ex, char **ptr_arg, - size_t n, char *buf, size_t buf_size) + size_t n, char *buf, size_t bufsize, size_t *buflen) { if (kp_help) { // in the help buffer STRCPY(buf, "he! "); + *buflen = STRLEN_LITERAL("he! "); return n; } if (kp_ex) { + *buflen = 0; // 'keywordprg' is an ex command if (cap->count0 != 0) { // Send the count to the ex command. - snprintf(buf, buf_size, "%" PRId64, (int64_t)(cap->count0)); + *buflen = (size_t)snprintf(buf, bufsize, "%" PRId64, (int64_t)(cap->count0)); } - STRCAT(buf, kp); - STRCAT(buf, " "); + *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen, "%s ", kp); return n; } @@ -3374,21 +3338,19 @@ static size_t nv_K_getcmd(cmdarg_T *cap, char *kp, bool kp_help, bool kp_ex, cha bool isman = (strcmp(kp, "man") == 0); bool isman_s = (strcmp(kp, "man -s") == 0); if (cap->count0 != 0 && !(isman || isman_s)) { - snprintf(buf, buf_size, ".,.+%" PRId64, (int64_t)(cap->count0 - 1)); + *buflen = (size_t)snprintf(buf, bufsize, ".,.+%" PRId64, (int64_t)(cap->count0 - 1)); } do_cmdline_cmd("tabnew"); - STRCAT(buf, "terminal "); + *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen, "terminal "); if (cap->count0 == 0 && isman_s) { - STRCAT(buf, "man"); + *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen, "man "); } else { - STRCAT(buf, kp); + *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen, "%s ", kp); } - STRCAT(buf, " "); if (cap->count0 != 0 && (isman || isman_s)) { - snprintf(buf + strlen(buf), buf_size - strlen(buf), "%" PRId64, - (int64_t)cap->count0); - STRCAT(buf, " "); + *buflen += (size_t)snprintf(buf + *buflen, bufsize - *buflen, + "%" PRId64 " ", (int64_t)cap->count0); } *ptr_arg = ptr; @@ -3451,9 +3413,10 @@ static void nv_ident(cmdarg_T *cap) return; } bool kp_ex = (*kp == ':'); // 'keywordprg' is an ex command - size_t buf_size = n * 2 + 30 + strlen(kp); - char *buf = xmalloc(buf_size); + size_t bufsize = n * 2 + 30 + strlen(kp); + char *buf = xmalloc(bufsize); buf[0] = NUL; + size_t buflen = 0; switch (cmdchar) { case '*': @@ -3467,12 +3430,13 @@ static void nv_ident(cmdarg_T *cap) if (!g_cmd && vim_iswordp(ptr)) { STRCPY(buf, "\\<"); + buflen = STRLEN_LITERAL("\\<"); } no_smartcase = true; // don't use 'smartcase' now break; case 'K': - n = nv_K_getcmd(cap, kp, kp_help, kp_ex, &ptr, n, buf, buf_size); + n = nv_K_getcmd(cap, kp, kp_help, kp_ex, &ptr, n, buf, bufsize, &buflen); if (n == 0) { return; } @@ -3481,17 +3445,23 @@ static void nv_ident(cmdarg_T *cap) case ']': tag_cmd = true; STRCPY(buf, "ts "); + buflen = STRLEN_LITERAL("ts "); break; default: tag_cmd = true; if (curbuf->b_help) { STRCPY(buf, "he! "); + buflen = STRLEN_LITERAL("he! "); } else { if (g_cmd) { STRCPY(buf, "tj "); + buflen = STRLEN_LITERAL("tj "); + } else if (cap->count0 == 0) { + STRCPY(buf, "ta "); + buflen = STRLEN_LITERAL("ta "); } else { - snprintf(buf, buf_size, "%" PRId64 "ta ", (int64_t)cap->count0); + buflen = (size_t)snprintf(buf, bufsize, ":%" PRId64 "ta ", (int64_t)cap->count0); } } } @@ -3507,9 +3477,11 @@ static void nv_ident(cmdarg_T *cap) p = vim_strsave_shellescape(ptr, true, true); } xfree(ptr); - char *newbuf = xrealloc(buf, strlen(buf) + strlen(p) + 1); + size_t plen = strlen(p); + char *newbuf = xrealloc(buf, buflen + plen + 1); buf = newbuf; - STRCAT(buf, p); + STRCPY(buf + buflen, p); + buflen += plen; xfree(p); } else { char *aux_ptr; @@ -3528,12 +3500,13 @@ static void nv_ident(cmdarg_T *cap) aux_ptr = "\\|\"\n*?["; } - p = buf + strlen(buf); + p = buf + buflen; while (n-- > 0) { // put a backslash before \ and some others if (vim_strchr(aux_ptr, (uint8_t)(*ptr)) != NULL) { *p++ = '\\'; } + // When current byte is a part of multibyte character, copy all // bytes of that character. const size_t len = (size_t)(utfc_ptr2len(ptr) - 1); @@ -3543,20 +3516,21 @@ static void nv_ident(cmdarg_T *cap) *p++ = *ptr++; } *p = NUL; + buflen = (size_t)(p - buf); } // Execute the command. if (cmdchar == '*' || cmdchar == '#') { - if (!g_cmd - && vim_iswordp(mb_prevptr(get_cursor_line_ptr(), ptr))) { - STRCAT(buf, "\\>"); + if (!g_cmd && vim_iswordp(mb_prevptr(get_cursor_line_ptr(), ptr))) { + STRCPY(buf + buflen, "\\>"); + buflen += STRLEN_LITERAL("\\>"); } // put pattern in search history init_history(); - add_to_history(HIST_SEARCH, buf, true, NUL); + add_to_history(HIST_SEARCH, buf, buflen, true, NUL); - normal_search(cap, cmdchar == '*' ? '/' : '?', buf, 0, NULL); + normal_search(cap, cmdchar == '*' ? '/' : '?', buf, buflen, 0, NULL); } else { g_tag_at_cursor = true; do_cmdline_cmd(buf); @@ -3592,7 +3566,7 @@ bool get_visual_text(cmdarg_T *cap, char **pp, size_t *lenp) } if (VIsual_mode == 'V') { *pp = get_cursor_line_ptr(); - *lenp = strlen(*pp); + *lenp = (size_t)get_cursor_line_len(); } else { if (lt(curwin->w_cursor, VIsual)) { *pp = ml_get_pos(&curwin->w_cursor); @@ -3640,7 +3614,7 @@ static void nv_scroll(cmdarg_T *cap) // Count a fold for one screen line. for (n = cap->count1 - 1; n > 0 && curwin->w_cursor.lnum > curwin->w_topline; n--) { - hasFolding(curwin->w_cursor.lnum, + hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); if (curwin->w_cursor.lnum > curwin->w_topline) { curwin->w_cursor.lnum--; @@ -3669,7 +3643,7 @@ static void nv_scroll(cmdarg_T *cap) if (used >= half) { break; } - if (hasFolding(curwin->w_topline + n, NULL, &lnum)) { + if (hasFolding(curwin, curwin->w_topline + n, NULL, &lnum)) { n = lnum - curwin->w_topline; } } @@ -3682,7 +3656,7 @@ static void nv_scroll(cmdarg_T *cap) // Count a fold for one screen line. lnum = curwin->w_topline; while (n-- > 0 && lnum < curwin->w_botline - 1) { - hasFolding(lnum, NULL, &lnum); + hasFolding(curwin, lnum, NULL, &lnum); lnum++; } n = lnum - curwin->w_topline; @@ -3696,7 +3670,7 @@ static void nv_scroll(cmdarg_T *cap) // Correct for 'so', except when an operator is pending. if (cap->oap->op_type == OP_NOP) { - cursor_correct(); + cursor_correct(curwin); } beginline(BL_SOL | BL_FIX); } @@ -3721,7 +3695,7 @@ static void nv_right(cmdarg_T *cap) // In virtual edit mode, there's no such thing as "past_line", as lines // are (theoretically) infinitely long. - if (virtual_active()) { + if (virtual_active(curwin)) { past_line = false; } @@ -3764,7 +3738,7 @@ static void nv_right(cmdarg_T *cap) break; } else if (past_line) { curwin->w_set_curswant = true; - if (virtual_active()) { + if (virtual_active(curwin)) { oneright(); } else { curwin->w_cursor.col += utfc_ptr2len(get_cursor_pos_ptr()); @@ -3806,7 +3780,7 @@ static void nv_left(cmdarg_T *cap) || (cap->cmdchar == K_LEFT && vim_strchr(p_ww, '<') != NULL)) && curwin->w_cursor.lnum > 1) { curwin->w_cursor.lnum--; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); curwin->w_set_curswant = true; // When the NL before the first char has to be deleted we @@ -3897,6 +3871,10 @@ static void nv_gotofile(cmdarg_T *cap) return; } + if (!check_can_set_curbuf_disabled()) { + return; + } + char *ptr = grab_file_name(cap->count1, &lnum); if (ptr != NULL) { @@ -3937,7 +3915,7 @@ static void nv_dollar(cmdarg_T *cap) // In virtual mode when off the edge of a line and an operator // is pending (whew!) keep the cursor where it is. // Otherwise, send it to the end of the line. - if (!virtual_active() || gchar_cursor() != NUL + if (!virtual_active(curwin) || gchar_cursor() != NUL || cap->oap->op_type == OP_NOP) { curwin->w_curswant = MAXCOL; // so we stay at the end } @@ -3973,7 +3951,7 @@ static void nv_search(cmdarg_T *cap) return; } - normal_search(cap, cap->cmdchar, cap->searchbuf, + normal_search(cap, cap->cmdchar, cap->searchbuf, strlen(cap->searchbuf), (cap->arg || !equalpos(save_cursor, curwin->w_cursor)) ? 0 : SEARCH_MARK, NULL); } @@ -3984,14 +3962,14 @@ static void nv_next(cmdarg_T *cap) { pos_T old = curwin->w_cursor; int wrapped = false; - int i = normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg, &wrapped); + int i = normal_search(cap, 0, NULL, 0, SEARCH_MARK | cap->arg, &wrapped); if (i == 1 && !wrapped && equalpos(old, curwin->w_cursor)) { // Avoid getting stuck on the current cursor position, which can happen when // an offset is given and the cursor is on the last char in the buffer: // Repeat with count + 1. cap->count1 += 1; - normal_search(cap, 0, NULL, SEARCH_MARK | cap->arg, NULL); + normal_search(cap, 0, NULL, 0, SEARCH_MARK | cap->arg, NULL); cap->count1 -= 1; } } @@ -4002,7 +3980,7 @@ static void nv_next(cmdarg_T *cap) /// @param opt extra flags for do_search() /// /// @return 0 for failure, 1 for found, 2 for found and line offset added. -static int normal_search(cmdarg_T *cap, int dir, char *pat, int opt, int *wrapped) +static int normal_search(cmdarg_T *cap, int dir, char *pat, size_t patlen, int opt, int *wrapped) { searchit_arg_T sia; @@ -4012,7 +3990,7 @@ static int normal_search(cmdarg_T *cap, int dir, char *pat, int opt, int *wrappe curwin->w_set_curswant = true; CLEAR_FIELD(sia); - int i = do_search(cap->oap, dir, dir, pat, cap->count1, + int i = do_search(cap->oap, dir, dir, pat, patlen, cap->count1, opt | SEARCH_OPT | SEARCH_ECHO | SEARCH_MSG, &sia); if (wrapped != NULL) { *wrapped = sia.sa_wrapped; @@ -4031,7 +4009,8 @@ static int normal_search(cmdarg_T *cap, int dir, char *pat, int opt, int *wrappe // "/$" will put the cursor after the end of the line, may need to // correct that here - check_cursor(); + check_cursor(curwin); + return i; } @@ -4057,7 +4036,7 @@ static void nv_csearch(cmdarg_T *cap) curwin->w_set_curswant = true; // Include a Tab for "tx" and for "dfx". - if (gchar_cursor() == TAB && virtual_active() && cap->arg == FORWARD + if (gchar_cursor() == TAB && virtual_active(curwin) && cap->arg == FORWARD && (t_cmd || cap->oap->op_type != OP_NOP)) { colnr_T scol, ecol; @@ -4233,7 +4212,8 @@ static void nv_brackets(cmdarg_T *cap) (cap->cmdchar == ']' ? curwin->w_cursor.lnum + 1 : 1), - MAXLNUM); + MAXLNUM, + false); xfree(ptr); curwin->w_set_curswant = true; } @@ -4306,12 +4286,15 @@ static void nv_brackets(cmdarg_T *cap) cap->count1) == false) { clearopbeep(cap->oap); } - } else if (cap->nchar == 's' || cap->nchar == 'S') { - // "[s", "[S", "]s" and "]S": move to next spell error. + } else if (cap->nchar == 'r' || cap->nchar == 's' || cap->nchar == 'S') { + // "[r", "[s", "[S", "]r", "]s" and "]S": move to next spell error. setpcmark(); for (n = 0; n < cap->count1; n++) { if (spell_move_to(curwin, cap->cmdchar == ']' ? FORWARD : BACKWARD, - cap->nchar == 's', false, NULL) == 0) { + cap->nchar == 's' + ? SMT_ALL + : cap->nchar == 'r' ? SMT_RARE : SMT_BAD, + false, NULL) == 0) { clearopbeep(cap->oap); break; } @@ -4512,7 +4495,7 @@ static void nv_replace(cmdarg_T *cap) } // Break tabs, etc. - if (virtual_active()) { + if (virtual_active(curwin)) { if (u_save_cursor() == false) { return; } @@ -4527,9 +4510,8 @@ static void nv_replace(cmdarg_T *cap) } // Abort if not enough characters to replace. - char *ptr = get_cursor_pos_ptr(); - if (strlen(ptr) < (unsigned)cap->count1 - || (mb_charlen(ptr) < cap->count1)) { + if ((size_t)get_cursor_pos_len() < (unsigned)cap->count1 + || (mb_charlen(get_cursor_pos_ptr()) < cap->count1)) { clearopbeep(cap->oap); return; } @@ -4625,7 +4607,7 @@ static void v_swap_corners(int cmdchar) pos_T old_cursor = curwin->w_cursor; getvcols(curwin, &old_cursor, &VIsual, &left, &right); curwin->w_cursor.lnum = VIsual.lnum; - coladvance(left); + coladvance(curwin, left); VIsual = curwin->w_cursor; curwin->w_cursor.lnum = old_cursor.lnum; @@ -4635,20 +4617,20 @@ static void v_swap_corners(int cmdchar) if (old_cursor.lnum >= VIsual.lnum && *p_sel == 'e') { curwin->w_curswant++; } - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); if (curwin->w_cursor.col == old_cursor.col - && (!virtual_active() + && (!virtual_active(curwin) || curwin->w_cursor.coladd == old_cursor.coladd)) { curwin->w_cursor.lnum = VIsual.lnum; if (old_cursor.lnum <= VIsual.lnum && *p_sel == 'e') { right++; } - coladvance(right); + coladvance(curwin, right); VIsual = curwin->w_cursor; curwin->w_cursor.lnum = old_cursor.lnum; - coladvance(left); + coladvance(curwin, left); curwin->w_curswant = left; } } else { @@ -4678,8 +4660,8 @@ static void nv_Replace(cmdarg_T *cap) if (!MODIFIABLE(curbuf)) { emsg(_(e_modifiable)); } else { - if (virtual_active()) { - coladvance(getviscol()); + if (virtual_active(curwin)) { + coladvance(curwin, getviscol()); } invoke_edit(cap, false, cap->arg ? 'V' : 'R', false); } @@ -4713,8 +4695,8 @@ static void nv_vreplace(cmdarg_T *cap) } stuffcharReadbuff(cap->extra_char); stuffcharReadbuff(ESC); - if (virtual_active()) { - coladvance(getviscol()); + if (virtual_active(curwin)) { + coladvance(curwin, getviscol()); } invoke_edit(cap, true, 'v', false); } @@ -4761,7 +4743,7 @@ static void n_swapchar(cmdarg_T *cap) } } - check_cursor(); + check_cursor(curwin); curwin->w_set_curswant = true; if (did_change) { changed_lines(curbuf, startpos.lnum, startpos.col, curwin->w_cursor.lnum + 1, @@ -4893,7 +4875,7 @@ static void nv_gomark(cmdarg_T *cap) move_res = nv_mark_move_to(cap, flags, fm); // May need to clear the coladd that a mark includes. - if (!virtual_active()) { + if (!virtual_active(curwin)) { curwin->w_cursor.coladd = 0; } @@ -5022,7 +5004,7 @@ static void nv_visual(cmdarg_T *cap) // was only one -- webb if (resel_VIsual_mode != 'v' || resel_VIsual_line_count > 1) { curwin->w_cursor.lnum += resel_VIsual_line_count * cap->count0 - 1; - check_cursor(); + check_cursor(curwin); } VIsual_mode = resel_VIsual_mode; if (VIsual_mode == 'v') { @@ -5036,11 +5018,11 @@ static void nv_visual(cmdarg_T *cap) } else { curwin->w_curswant = resel_VIsual_vcol; } - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } if (resel_VIsual_vcol == MAXCOL) { curwin->w_curswant = MAXCOL; - coladvance(MAXCOL); + coladvance(curwin, 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; @@ -5049,7 +5031,7 @@ static void nv_visual(cmdarg_T *cap) assert(cap->count0 >= INT_MIN && cap->count0 <= INT_MAX); curwin->w_curswant += resel_VIsual_vcol * cap->count0 - 1; curwin->w_cursor.lnum = lnum; - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } else { curwin->w_set_curswant = true; } @@ -5101,9 +5083,9 @@ static void n_start_visual_mode(int c) // Corner case: the 0 position in a tab may change when going into // virtualedit. Recalculate curwin->w_cursor to avoid bad highlighting. // - if (c == Ctrl_V && (get_ve_flags() & VE_BLOCK) && gchar_cursor() == TAB) { - validate_virtcol(); - coladvance(curwin->w_virtcol); + if (c == Ctrl_V && (get_ve_flags(curwin) & VE_BLOCK) && gchar_cursor() == TAB) { + validate_virtcol(curwin); + coladvance(curwin, curwin->w_virtcol); } VIsual = curwin->w_cursor; @@ -5191,10 +5173,10 @@ static void nv_gv_cmd(cmdarg_T *cap) // Set Visual to the start and w_cursor to the end of the Visual // area. Make sure they are on an existing character. - check_cursor(); + check_cursor(curwin); VIsual = curwin->w_cursor; curwin->w_cursor = tpos; - check_cursor(); + check_cursor(curwin); update_topline(curwin); // When called from normal "g" command: start Select mode when @@ -5213,7 +5195,7 @@ static void nv_gv_cmd(cmdarg_T *cap) /// "g0", "g^" : Like "0" and "^" but for screen lines. /// "gm": middle of "g0" and "g$". -static void nv_g_home_m_cmd(cmdarg_T *cap) +void nv_g_home_m_cmd(cmdarg_T *cap) { int i; const bool flag = cap->nchar == '^'; @@ -5221,14 +5203,23 @@ static void nv_g_home_m_cmd(cmdarg_T *cap) cap->oap->motion_type = kMTCharWise; cap->oap->inclusive = false; if (curwin->w_p_wrap && curwin->w_width_inner != 0) { - int width1 = curwin->w_width_inner - curwin_col_off(); - int width2 = width1 + curwin_col_off2(); + int width1 = curwin->w_width_inner - win_col_off(curwin); + int width2 = width1 + win_col_off2(curwin); - validate_virtcol(); + validate_virtcol(curwin); i = 0; if (curwin->w_virtcol >= (colnr_T)width1 && width2 > 0) { i = (curwin->w_virtcol - width1) / width2 * width2 + width1; } + + // When ending up below 'smoothscroll' marker, move just beyond it so + // that skipcol is not adjusted later. + if (curwin->w_skipcol > 0 && curwin->w_cursor.lnum == curwin->w_topline) { + int overlap = sms_marker_overlap(curwin, -1); + if (overlap > 0 && i == curwin->w_skipcol) { + i += overlap; + } + } } else { i = curwin->w_leftcol; } @@ -5236,10 +5227,10 @@ static void nv_g_home_m_cmd(cmdarg_T *cap) // 'relativenumber' is on and lines are wrapping the middle can be more // to the left. if (cap->nchar == 'm') { - i += (curwin->w_width_inner - curwin_col_off() - + ((curwin->w_p_wrap && i > 0) ? curwin_col_off2() : 0)) / 2; + i += (curwin->w_width_inner - win_col_off(curwin) + + ((curwin->w_p_wrap && i > 0) ? win_col_off2(curwin) : 0)) / 2; } - coladvance((colnr_T)i); + coladvance(curwin, (colnr_T)i); if (flag) { do { i = gchar_cursor(); @@ -5281,7 +5272,7 @@ static void nv_g_dollar_cmd(cmdarg_T *cap) { oparg_T *oap = cap->oap; int i; - int col_off = curwin_col_off(); + int col_off = win_col_off(curwin); const bool flag = cap->nchar == K_END || cap->nchar == K_KEND; oap->motion_type = kMTCharWise; @@ -5290,14 +5281,14 @@ static void nv_g_dollar_cmd(cmdarg_T *cap) curwin->w_curswant = MAXCOL; // so we stay at the end if (cap->count1 == 1) { int width1 = curwin->w_width_inner - col_off; - int width2 = width1 + curwin_col_off2(); + int width2 = width1 + win_col_off2(curwin); - validate_virtcol(); + validate_virtcol(curwin); i = width1 - 1; if (curwin->w_virtcol >= (colnr_T)width1) { i += ((curwin->w_virtcol - width1) / width2 + 1) * width2; } - coladvance((colnr_T)i); + coladvance(curwin, (colnr_T)i); // Make sure we stick in this column. update_curswant_force(); @@ -5318,7 +5309,7 @@ static void nv_g_dollar_cmd(cmdarg_T *cap) cursor_down(cap->count1 - 1, false); } i = curwin->w_leftcol + curwin->w_width_inner - col_off - 1; - coladvance((colnr_T)i); + coladvance(curwin, (colnr_T)i); // if the character doesn't fit move one back if (curwin->w_cursor.col > 0 && utf_ptr2cells(get_cursor_pos_ptr()) > 1) { @@ -5347,9 +5338,9 @@ static void nv_gi_cmd(cmdarg_T *cap) if (curbuf->b_last_insert.mark.lnum != 0) { curwin->w_cursor = curbuf->b_last_insert.mark; check_cursor_lnum(curwin); - int i = (int)strlen(get_cursor_line_ptr()); + int i = (int)get_cursor_line_len(); if (curwin->w_cursor.col > (colnr_T)i) { - if (virtual_active()) { + if (virtual_active(curwin)) { curwin->w_cursor.coladd += curwin->w_cursor.col - i; } curwin->w_cursor.col = i; @@ -5477,9 +5468,9 @@ static void nv_g_cmd(cmdarg_T *cap) oap->inclusive = false; i = linetabsize(curwin, curwin->w_cursor.lnum); if (cap->count0 > 0 && cap->count0 <= 100) { - coladvance((colnr_T)(i * cap->count0 / 100)); + coladvance(curwin, (colnr_T)(i * cap->count0 / 100)); } else { - coladvance((colnr_T)(i / 2)); + coladvance(curwin, (colnr_T)(i / 2)); } curwin->w_set_curswant = true; break; @@ -5702,11 +5693,11 @@ static void n_opencmd(cmdarg_T *cap) if (cap->cmdchar == 'O') { // Open above the first line of a folded sequence of lines - hasFolding(curwin->w_cursor.lnum, + hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL); } else { // Open below the last line of a folded sequence of lines - hasFolding(curwin->w_cursor.lnum, + hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum); } // trigger TextChangedI for the 'o/O' command @@ -5887,7 +5878,7 @@ static void nv_pipe(cmdarg_T *cap) cap->oap->inclusive = false; beginline(0); if (cap->count0 > 0) { - coladvance((colnr_T)(cap->count0 - 1)); + coladvance(curwin, (colnr_T)(cap->count0 - 1)); curwin->w_curswant = (colnr_T)(cap->count0 - 1); } else { curwin->w_curswant = 0; @@ -5983,8 +5974,8 @@ static void adjust_cursor(oparg_T *oap) // - 'virtualedit' is not "all" and not "onemore". if (curwin->w_cursor.col > 0 && gchar_cursor() == NUL && (!VIsual_active || *p_sel == 'o') - && !virtual_active() - && (get_ve_flags() & VE_ONEMORE) == 0) { + && !virtual_active(curwin) + && (get_ve_flags(curwin) & VE_ONEMORE) == 0) { curwin->w_cursor.col--; // prevent cursor from moving on the trail byte mb_adjust_cursor(); @@ -6023,26 +6014,37 @@ static void adjust_for_sel(cmdarg_T *cap) bool unadjust_for_sel(void) { if (*p_sel == 'e' && !equalpos(VIsual, curwin->w_cursor)) { - pos_T *pp; - if (lt(VIsual, curwin->w_cursor)) { - pp = &curwin->w_cursor; - } else { - pp = &VIsual; - } - if (pp->coladd > 0) { - pp->coladd--; - } else if (pp->col > 0) { - pp->col--; - mark_mb_adjustpos(curbuf, pp); - } else if (pp->lnum > 1) { - pp->lnum--; - pp->col = (colnr_T)strlen(ml_get(pp->lnum)); - return true; - } + return unadjust_for_sel_inner(lt(VIsual, curwin->w_cursor) + ? &curwin->w_cursor : &VIsual); } return false; } +/// Move position "*pp" back one character for 'selection' == "exclusive". +/// +/// @return true when backed up to the previous line. +bool unadjust_for_sel_inner(pos_T *pp) +{ + colnr_T cs, ce; + + if (pp->coladd > 0) { + pp->coladd--; + } else if (pp->col > 0) { + pp->col--; + mark_mb_adjustpos(curbuf, pp); + if (virtual_active(curwin)) { + getvcol(curwin, pp, &cs, NULL, &ce); + pp->coladd = ce - cs; + } + } else if (pp->lnum > 1) { + pp->lnum--; + pp->col = ml_get_len(pp->lnum); + return true; + } + + return false; +} + /// SELECT key in Normal or Visual mode: end of Select mode mapping. static void nv_select(cmdarg_T *cap) { @@ -6147,7 +6149,7 @@ static void nv_esc(cmdarg_T *cap) if (VIsual_active) { end_visual_mode(); // stop Visual - check_cursor_col(); // make sure cursor is not beyond EOL + check_cursor_col(curwin); // make sure cursor is not beyond EOL curwin->w_set_curswant = true; redraw_curbuf_later(UPD_INVERTED); } else if (no_reason) { @@ -6160,12 +6162,12 @@ static void nv_esc(cmdarg_T *cap) void set_cursor_for_append_to_line(void) { curwin->w_set_curswant = true; - if (get_ve_flags() == VE_ALL) { + if (get_ve_flags(curwin) == VE_ALL) { const int save_State = State; // Pretend Insert mode here to allow the cursor on the // character past the end of the line State = MODE_INSERT; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); State = save_State; } else { curwin->w_cursor.col += (colnr_T)strlen(get_cursor_pos_ptr()); @@ -6203,7 +6205,7 @@ static void nv_edit(cmdarg_T *cap) case 'a': // "a"ppend is like "i"nsert on the next character. // increment coladd when in virtual space, increment the // column otherwise, also to append after an unprintable char - if (virtual_active() + if (virtual_active(curwin) && (curwin->w_cursor.coladd > 0 || *get_cursor_pos_ptr() == NUL || *get_cursor_pos_ptr() == TAB)) { @@ -6220,7 +6222,7 @@ static void nv_edit(cmdarg_T *cap) // Pretend Insert mode here to allow the cursor on the // character past the end of the line State = MODE_INSERT; - coladvance(getviscol()); + coladvance(curwin, getviscol()); State = save_State; } @@ -6391,12 +6393,8 @@ static void nv_at(cmdarg_T *cap) /// Handle the CTRL-U and CTRL-D commands. static void nv_halfpage(cmdarg_T *cap) { - if ((cap->cmdchar == Ctrl_U && curwin->w_cursor.lnum == 1) - || (cap->cmdchar == Ctrl_D - && curwin->w_cursor.lnum == curbuf->b_ml.ml_line_count)) { - clearopbeep(cap->oap); - } else if (!checkclearop(cap->oap)) { - halfpage(cap->cmdchar == Ctrl_D, cap->count0); + if (!checkclearop(cap->oap)) { + pagescroll(cap->cmdchar == Ctrl_D ? FORWARD : BACKWARD, cap->count0, true); } } @@ -6575,7 +6573,7 @@ static void nv_put_opt(cmdarg_T *cap, bool fix_indent) // line. if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } } auto_format(false, true); diff --git a/src/nvim/ops.c b/src/nvim/ops.c index 9b969a2337..6233e446e0 100644 --- a/src/nvim/ops.c +++ b/src/nvim/ops.c @@ -283,7 +283,7 @@ void op_shift(oparg_T *oap, bool curs_top, int amount) // Set "'[" and "']" marks. curbuf->b_op_start = oap->start; curbuf->b_op_end.lnum = oap->end.lnum; - curbuf->b_op_end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); + curbuf->b_op_end.col = ml_get_len(oap->end.lnum); if (curbuf->b_op_end.col > 0) { curbuf->b_op_end.col--; } @@ -365,6 +365,7 @@ static void shift_block(oparg_T *oap, int amount) } char *const oldp = get_cursor_line_ptr(); + const int old_line_len = get_cursor_line_len(); int startcol, oldlen, newlen; @@ -414,17 +415,17 @@ static void shift_block(oparg_T *oap, int amount) const int col_pre = bd.pre_whitesp_c - (bd.startspaces != 0); bd.textcol -= col_pre; - const size_t new_line_len // the length of the line after the block shift - = (size_t)bd.textcol + (size_t)tabs + (size_t)spaces + strlen(bd.textstart); - newp = xmalloc(new_line_len + 1); + const int new_line_len // the length of the line after the block shift + = bd.textcol + tabs + spaces + (old_line_len - (int)(bd.textstart - oldp)); + newp = xmalloc((size_t)new_line_len + 1); memmove(newp, oldp, (size_t)bd.textcol); startcol = bd.textcol; oldlen = (int)(bd.textstart - old_textstart) + col_pre; newlen = tabs + spaces; memset(newp + bd.textcol, TAB, (size_t)tabs); memset(newp + bd.textcol + tabs, ' ', (size_t)spaces); - // Note that STRMOVE() copies the trailing NUL. - STRMOVE(newp + bd.textcol + tabs + spaces, bd.textstart); + STRCPY(newp + bd.textcol + tabs + spaces, bd.textstart); + assert(newlen - oldlen == new_line_len - old_line_len); } else { // left char *verbatim_copy_end; // end of the part of the line which is // copied verbatim @@ -491,26 +492,27 @@ static void shift_block(oparg_T *oap, int amount) // part of the line that will be copied, it means we encountered a tab // character, which we will have to partly replace with spaces. assert(destination_col - verbatim_copy_width >= 0); - const size_t fill // nr of spaces that replace a TAB - = (size_t)(destination_col - verbatim_copy_width); + const int fill // nr of spaces that replace a TAB + = destination_col - verbatim_copy_width; assert(verbatim_copy_end - oldp >= 0); - const size_t verbatim_diff = (size_t)(verbatim_copy_end - oldp); + // length of string left of the shift position (ie the string not being shifted) + const int fixedlen = (int)(verbatim_copy_end - oldp); // The replacement line will consist of: // - the beginning of the original line up to "verbatim_copy_end", // - "fill" number of spaces, // - the rest of the line, pointed to by non_white. - const size_t new_line_len // the length of the line after the block shift - = verbatim_diff + fill + strlen(non_white); - - newp = xmalloc(new_line_len + 1); - startcol = (int)verbatim_diff; - oldlen = bd.textcol + (int)(non_white - bd.textstart) - (int)verbatim_diff; - newlen = (int)fill; - memmove(newp, oldp, verbatim_diff); - memset(newp + verbatim_diff, ' ', fill); - // Note that STRMOVE() copies the trailing NUL. - STRMOVE(newp + verbatim_diff + fill, non_white); + const int new_line_len // the length of the line after the block shift + = fixedlen + fill + (old_line_len - (int)(non_white - oldp)); + + newp = xmalloc((size_t)new_line_len + 1); + startcol = fixedlen; + oldlen = bd.textcol + (int)(non_white - bd.textstart) - fixedlen; + newlen = fill; + memmove(newp, oldp, (size_t)fixedlen); + memset(newp + fixedlen, ' ', (size_t)fill); + STRCPY(newp + fixedlen + fill, non_white); + assert(newlen - oldlen == new_line_len - old_line_len); } // replace the line ml_replace(curwin->w_cursor.lnum, newp, false); @@ -525,13 +527,13 @@ static void shift_block(oparg_T *oap, int amount) /// Insert string "s" (b_insert ? before : after) block :AKelly /// Caller must prepare for undo. -static void block_insert(oparg_T *oap, char *s, bool b_insert, struct block_def *bdp) +static void block_insert(oparg_T *oap, const char *s, size_t slen, bool b_insert, + struct block_def *bdp) { int ts_val; int count = 0; // extra spaces to replace a cut TAB int spaces = 0; // non-zero if cutting a TAB colnr_T offset; // pointer along new line - size_t s_len = strlen(s); char *newp, *oldp; // new, old lines int oldstate = State; State = MODE_INSERT; // don't want MODE_REPLACE for State @@ -579,8 +581,8 @@ static void block_insert(oparg_T *oap, char *s, bool b_insert, struct block_def assert(count >= 0); // Make sure the allocated size matches what is actually copied below. - newp = xmalloc(strlen(oldp) + (size_t)spaces + s_len - + (spaces > 0 && !bdp->is_short ? (size_t)ts_val - (size_t)spaces : 0) + newp = xmalloc((size_t)ml_get_len(lnum) + (size_t)spaces + slen + + (spaces > 0 && !bdp->is_short ? (size_t)(ts_val - spaces) : 0) + (size_t)count + 1); // copy up to shifted part @@ -592,8 +594,8 @@ static void block_insert(oparg_T *oap, char *s, bool b_insert, struct block_def memset(newp + offset, ' ', (size_t)spaces); // copy the new text - memmove(newp + offset + spaces, s, s_len); - offset += (int)s_len; + memmove(newp + offset + spaces, s, slen); + offset += (int)slen; int skipped = 0; if (spaces > 0 && !bdp->is_short) { @@ -614,7 +616,7 @@ static void block_insert(oparg_T *oap, char *s, bool b_insert, struct block_def if (spaces > 0) { offset += count; } - STRMOVE(newp + offset, oldp); + STRCPY(newp + offset, oldp); ml_replace(lnum, newp, false); extmark_splice_cols(curbuf, (int)lnum - 1, startcol, @@ -1843,15 +1845,15 @@ int op_delete(oparg_T *oap) // Thus the number of characters may increase! int n = bd.textlen - bd.startspaces - bd.endspaces; char *oldp = ml_get(lnum); - char *newp = xmalloc(strlen(oldp) - (size_t)n + 1); + char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)n + 1); // copy up to deleted part memmove(newp, oldp, (size_t)bd.textcol); // insert spaces memset(newp + bd.textcol, ' ', (size_t)bd.startspaces + (size_t)bd.endspaces); // copy the part after the deleted part - oldp += bd.textcol + bd.textlen; - STRMOVE(newp + bd.textcol + bd.startspaces + bd.endspaces, oldp); + STRCPY(newp + bd.textcol + bd.startspaces + bd.endspaces, + oldp + bd.textcol + bd.textlen); // replace the line ml_replace(lnum, newp, false); @@ -1860,7 +1862,7 @@ int op_delete(oparg_T *oap) kExtmarkUndo); } - check_cursor_col(); + check_cursor_col(curwin); changed_lines(curbuf, curwin->w_cursor.lnum, curwin->w_cursor.col, oap->end.lnum + 1, 0, true); oap->line_count = 0; // no lines deleted @@ -1886,15 +1888,8 @@ int op_delete(oparg_T *oap) } else { beginline(0); // cursor in column 0 } - - int old_len = (int)strlen(ml_get(curwin->w_cursor.lnum)); - truncate_line(false); // delete the rest of the line - - extmark_splice_cols(curbuf, - (int)curwin->w_cursor.lnum - 1, curwin->w_cursor.col, - old_len - curwin->w_cursor.col, 0, kExtmarkUndo); - - // leave cursor past last char in line + truncate_line(false); // delete the rest of the line, + // leaving cursor past last char in line if (oap->line_count > 1) { u_clearline(curbuf); // "U" command not possible after "2cc" } @@ -1917,7 +1912,7 @@ int op_delete(oparg_T *oap) coladvance_force(getviscol2(oap->start.col, oap->start.coladd)); oap->start = curwin->w_cursor; if (oap->line_count == 1) { - coladvance(endcol); + coladvance(curwin, endcol); oap->end.col = curwin->w_cursor.col; oap->end.coladd = curwin->w_cursor.coladd; curwin->w_cursor = oap->start; @@ -1959,8 +1954,7 @@ int op_delete(oparg_T *oap) if (virtual_op) { // fix up things for virtualedit-delete: // break the tabs which are going to get in our way - char *curline = get_cursor_line_ptr(); - int len = (int)strlen(curline); + int len = get_cursor_line_len(); if (oap->end.coladd != 0 && (int)oap->end.col >= len - 1 @@ -2120,7 +2114,7 @@ static int op_replace(oparg_T *oap, int c) pos_T vpos; vpos.lnum = curwin->w_cursor.lnum; - getvpos(&vpos, oap->start_vcol); + getvpos(curwin, &vpos, oap->start_vcol); bd.startspaces += vpos.coladd; n = bd.startspaces; } else { @@ -2153,7 +2147,7 @@ static int op_replace(oparg_T *oap, int c) numc *= utf_char2len(c); char *oldp = get_cursor_line_ptr(); - colnr_T oldlen = (int)strlen(oldp); + colnr_T oldlen = get_cursor_line_len(); size_t newp_size = (size_t)bd.textcol + (size_t)bd.startspaces; if (had_ctrl_v_cr || (c != '\r' && c != '\n')) { @@ -2217,7 +2211,7 @@ static int op_replace(oparg_T *oap, int c) if (oap->motion_type == kMTLineWise) { oap->start.col = 0; curwin->w_cursor.col = 0; - oap->end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); + oap->end.col = ml_get_len(oap->end.lnum); if (oap->end.col) { oap->end.col--; } @@ -2255,7 +2249,7 @@ static int op_replace(oparg_T *oap, int c) } coladvance_force(getviscol()); if (curwin->w_cursor.lnum == oap->end.lnum) { - getvpos(&oap->end, end_vcol); + getvpos(curwin, &oap->end, end_vcol); } } // with "coladd" set may move to just after a TAB @@ -2298,7 +2292,7 @@ static int op_replace(oparg_T *oap, int c) } curwin->w_cursor = oap->start; - check_cursor(); + check_cursor(curwin); changed_lines(curbuf, oap->start.lnum, oap->start.col, oap->end.lnum + 1, 0, true); if ((cmdmod.cmod_flags & CMOD_LOCKMARKS) == 0) { @@ -2336,7 +2330,7 @@ void op_tilde(oparg_T *oap) if (oap->motion_type == kMTLineWise) { oap->start.col = 0; pos.col = 0; - oap->end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); + oap->end.col = ml_get_len(oap->end.lnum); if (oap->end.col) { oap->end.col--; } @@ -2351,7 +2345,7 @@ void op_tilde(oparg_T *oap) while (true) { did_change |= swapchars(oap->op_type, &pos, pos.lnum == oap->end.lnum ? oap->end.col + 1 - : (int)strlen(ml_get_pos(&pos))); + : ml_get_pos_len(&pos)); if (ltoreq(oap->end, pos) || inc(&pos) == -1) { break; } @@ -2510,12 +2504,10 @@ void op_insert(oparg_T *oap, int count1) // Get indent information ind_pre_col = (colnr_T)getwhitecols_curline(); ind_pre_vcol = get_indent(); - char *firstline = ml_get(oap->start.lnum) + bd.textcol; - + pre_textlen = ml_get_len(oap->start.lnum) - bd.textcol; if (oap->op_type == OP_APPEND) { - firstline += bd.textlen; + pre_textlen -= bd.textlen; } - pre_textlen = (int)strlen(firstline); } if (oap->op_type == OP_APPEND) { @@ -2540,7 +2532,7 @@ void op_insert(oparg_T *oap, int count1) } } else { curwin->w_cursor = oap->end; - check_cursor_col(); + check_cursor_col(curwin); // Works just like an 'i'nsert on the next character. if (!LINEEMPTY(curwin->w_cursor.lnum) @@ -2642,7 +2634,7 @@ void op_insert(oparg_T *oap, int count1) // Subsequent calls to ml_get() flush the firstline data - take a // copy of the required string. char *firstline = ml_get(oap->start.lnum); - const size_t len = strlen(firstline); + colnr_T len = ml_get_len(oap->start.lnum); colnr_T add = bd.textcol; colnr_T offset = 0; // offset when cursor was moved in insert mode if (oap->op_type == OP_APPEND) { @@ -2659,21 +2651,21 @@ void op_insert(oparg_T *oap, int count1) } } } - if ((size_t)add > len) { - firstline += len; // short line, point to the NUL - } else { - firstline += add; + if (add > len) { + add = len; // short line, point to the NUL } - int ins_len = (int)strlen(firstline) - pre_textlen - offset; + firstline += add; + len -= add; + int ins_len = len - pre_textlen - offset; if (pre_textlen >= 0 && ins_len > 0) { char *ins_text = xmemdupz(firstline, (size_t)ins_len); // block handled here if (u_save(oap->start.lnum, (linenr_T)(oap->end.lnum + 1)) == OK) { - block_insert(oap, ins_text, (oap->op_type == OP_INSERT), &bd); + block_insert(oap, ins_text, (size_t)ins_len, (oap->op_type == OP_INSERT), &bd); } curwin->w_cursor.col = oap->start.col; - check_cursor(); + check_cursor(curwin); xfree(ins_text); } } @@ -2719,7 +2711,7 @@ int op_change(oparg_T *oap) coladvance_force(getviscol()); } firstline = ml_get(oap->start.lnum); - pre_textlen = (int)strlen(firstline); + pre_textlen = ml_get_len(oap->start.lnum); pre_indent = (int)getwhitecols(firstline); bd.textcol = curwin->w_cursor.col; } @@ -2741,7 +2733,6 @@ int op_change(oparg_T *oap) // Don't repeat the insert when Insert mode ended with CTRL-C. if (oap->motion_type == kMTBlockWise && oap->start.lnum != oap->end.lnum && !got_int) { - int ins_len; // Auto-indenting may have changed the indent. If the cursor was past // the indent, exclude that indent change from the inserted text. firstline = ml_get(oap->start.lnum); @@ -2752,12 +2743,12 @@ int op_change(oparg_T *oap) bd.textcol += (colnr_T)(new_indent - pre_indent); } - ins_len = (int)strlen(firstline) - pre_textlen; + int ins_len = ml_get_len(oap->start.lnum) - pre_textlen; if (ins_len > 0) { // Subsequent calls to ml_get() flush the firstline data - take a // copy of the inserted text. char *ins_text = xmalloc((size_t)ins_len + 1); - xstrlcpy(ins_text, firstline + bd.textcol, (size_t)ins_len + 1); + xmemcpyz(ins_text, firstline + bd.textcol, (size_t)ins_len); for (linenr_T linenr = oap->start.lnum + 1; linenr <= oap->end.lnum; linenr++) { block_prep(oap, &bd, linenr, true); @@ -2768,28 +2759,27 @@ int op_change(oparg_T *oap) // initial coladd offset as part of "startspaces" if (bd.is_short) { vpos.lnum = linenr; - getvpos(&vpos, oap->start_vcol); + getvpos(curwin, &vpos, oap->start_vcol); } else { vpos.coladd = 0; } char *oldp = ml_get(linenr); - char *newp = xmalloc(strlen(oldp) + (size_t)vpos.coladd - + (size_t)ins_len + 1); + char *newp = xmalloc((size_t)ml_get_len(linenr) + + (size_t)vpos.coladd + (size_t)ins_len + 1); // copy up to block start memmove(newp, oldp, (size_t)bd.textcol); - int offset = bd.textcol; - memset(newp + offset, ' ', (size_t)vpos.coladd); - offset += vpos.coladd; - memmove(newp + offset, ins_text, (size_t)ins_len); - offset += ins_len; - oldp += bd.textcol; - STRMOVE(newp + offset, oldp); + int newlen = bd.textcol; + memset(newp + newlen, ' ', (size_t)vpos.coladd); + newlen += vpos.coladd; + memmove(newp + newlen, ins_text, (size_t)ins_len); + newlen += ins_len; + STRCPY(newp + newlen, oldp + bd.textcol); ml_replace(linenr, newp, false); extmark_splice_cols(curbuf, (int)linenr - 1, bd.textcol, 0, vpos.coladd + ins_len, kExtmarkUndo); } } - check_cursor(); + check_cursor(curwin); changed_lines(curbuf, oap->start.lnum + 1, 0, oap->end.lnum + 1, 0, true); xfree(ins_text); } @@ -3196,7 +3186,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) bool allocated = false; const pos_T orig_start = curbuf->b_op_start; const pos_T orig_end = curbuf->b_op_end; - unsigned cur_ve_flags = get_ve_flags(); + unsigned cur_ve_flags = get_ve_flags(curwin); if (flags & PUT_FIXINDENT) { orig_indent = get_indent(); @@ -3421,9 +3411,9 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) // Correct line number for closed fold. Don't move the cursor yet, // u_save() uses it. if (dir == BACKWARD) { - hasFolding(lnum, &lnum, NULL); + hasFolding(curwin, lnum, &lnum, NULL); } else { - hasFolding(lnum, NULL, &lnum); + hasFolding(curwin, lnum, NULL, &lnum); } if (dir == FORWARD) { lnum++; @@ -3528,6 +3518,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) } // get the old line and advance to the position to insert at char *oldp = get_cursor_line_ptr(); + colnr_T oldlen = get_cursor_line_len(); CharsizeArg csarg; CSType cstype = init_charsize_arg(&csarg, curwin, curwin->w_cursor.lnum, oldp); @@ -3538,7 +3529,6 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) vcol += incr; ci = utfc_next(ci); } - size_t oldlen = (size_t)(ci.ptr - oldp) + strlen(ci.ptr); char *ptr = ci.ptr; bd.textcol = (colnr_T)(ptr - oldp); @@ -3588,7 +3578,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) totlen = (size_t)count * (size_t)(yanklen + spaces) + (size_t)bd.startspaces + (size_t)bd.endspaces; - char *newp = xmalloc(totlen + oldlen + 1); + char *newp = xmalloc(totlen + (size_t)oldlen + 1); // copy part up to cursor to new line ptr = newp; @@ -3618,7 +3608,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) ptr += bd.endspaces; // move the text after the cursor to the end of the line. - int columns = (int)oldlen - bd.textcol - delcount + 1; + int columns = oldlen - bd.textcol - delcount + 1; assert(columns >= 0); memmove(ptr, oldp + bd.textcol + delcount, (size_t)columns); ml_replace(curwin->w_cursor.lnum, newp, false); @@ -3650,7 +3640,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) curwin->w_cursor.col++; // in Insert mode we might be after the NUL, correct for that - colnr_T len = (colnr_T)strlen(get_cursor_line_ptr()); + colnr_T len = get_cursor_line_len(); if (curwin->w_cursor.col > len) { curwin->w_cursor.col = len; } @@ -3714,22 +3704,22 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) totlen = (size_t)count * (size_t)yanklen; do { char *oldp = ml_get(lnum); - size_t oldlen = strlen(oldp); + colnr_T oldlen = ml_get_len(lnum); if (lnum > start_lnum) { pos_T pos = { .lnum = lnum, }; - if (getvpos(&pos, vcol) == OK) { + if (getvpos(curwin, &pos, vcol) == OK) { col = pos.col; } else { col = MAXCOL; } } - if (VIsual_active && col > (colnr_T)oldlen) { + if (VIsual_active && col > oldlen) { lnum++; continue; } - char *newp = xmalloc(totlen + oldlen + 1); + char *newp = xmalloc(totlen + (size_t)oldlen + 1); memmove(newp, oldp, (size_t)col); char *ptr = newp + col; for (size_t i = 0; i < (size_t)count; i++) { @@ -3786,7 +3776,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) lnum = new_cursor.lnum; char *ptr = ml_get(lnum) + col; totlen = strlen(y_array[y_size - 1]); - char *newp = xmalloc((size_t)(strlen(ptr) + totlen + 1)); + char *newp = xmalloc((size_t)ml_get_len(lnum) - (size_t)col + totlen + 1); STRCPY(newp, y_array[y_size - 1]); STRCAT(newp, ptr); // insert second line @@ -3820,7 +3810,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) curwin->w_cursor.lnum = lnum; char *ptr = ml_get(lnum); if (cnt == count && i == y_size - 1) { - lendiff = (int)strlen(ptr); + lendiff = ml_get_len(lnum); } if (*ptr == '#' && preprocs_left()) { indent = 0; // Leave # lines at start @@ -3837,7 +3827,7 @@ void do_put(int regname, yankreg_T *reg, int dir, int count, int flags) curwin->w_cursor = old_pos; // remember how many chars were removed if (cnt == count && i == y_size - 1) { - lendiff -= (int)strlen(ml_get(lnum)); + lendiff -= ml_get_len(lnum); } } } @@ -3943,7 +3933,7 @@ error: curwin->w_set_curswant = true; // Make sure the cursor is not after the NUL. - int len = (int)strlen(get_cursor_line_ptr()); + int len = get_cursor_line_len(); if (curwin->w_cursor.col > len) { if (cur_ve_flags == VE_ALL) { curwin->w_cursor.coladd = curwin->w_cursor.col - len; @@ -3977,7 +3967,7 @@ end: /// there move it left. void adjust_cursor_eol(void) { - unsigned cur_ve_flags = get_ve_flags(); + unsigned cur_ve_flags = get_ve_flags(curwin); const bool adj_cursor = (curwin->w_cursor.col > 0 && gchar_cursor() == NUL @@ -4439,7 +4429,7 @@ int do_join(size_t count, bool insert_space, bool save_undo, bool use_formatopti // vim: use the column of the last join curwin->w_cursor.col = (vim_strchr(p_cpo, CPO_JOINCOL) != NULL ? currsize : col); - check_cursor_col(); + check_cursor_col(curwin); curwin->w_cursor.coladd = 0; curwin->w_set_curswant = true; @@ -4617,11 +4607,13 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T { colnr_T startcol = 0; colnr_T endcol = MAXCOL; - bool is_oneChar = false; colnr_T cs, ce; char *p = ml_get(lnum); + bdp->startspaces = 0; bdp->endspaces = 0; + bdp->is_oneChar = false; + bdp->start_char_vcols = 0; if (lnum == start.lnum) { startcol = start.col; @@ -4629,7 +4621,8 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T getvcol(curwin, &start, &cs, NULL, &ce); if (ce != cs && start.coladd > 0) { // Part of a tab selected -- but don't double-count it. - bdp->startspaces = (ce - cs + 1) - start.coladd; + bdp->start_char_vcols = ce - cs + 1; + bdp->startspaces = bdp->start_char_vcols - start.coladd; if (bdp->startspaces < 0) { bdp->startspaces = 0; } @@ -4649,7 +4642,7 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T && utf_head_off(p, p + endcol) == 0)) { if (start.lnum == end.lnum && start.col == end.col) { // Special case: inside a single char - is_oneChar = true; + bdp->is_oneChar = true; bdp->startspaces = end.coladd - start.coladd + inclusive; endcol = startcol; } else { @@ -4660,13 +4653,14 @@ void charwise_block_prep(pos_T start, pos_T end, struct block_def *bdp, linenr_T } } if (endcol == MAXCOL) { - endcol = (colnr_T)strlen(p); + endcol = ml_get_len(lnum); } - if (startcol > endcol || is_oneChar) { + if (startcol > endcol || bdp->is_oneChar) { bdp->textlen = 0; } else { bdp->textlen = endcol - startcol + inclusive; } + bdp->textcol = startcol; bdp->textstart = p + startcol; } @@ -4717,20 +4711,20 @@ void op_addsub(oparg_T *oap, linenr_T Prenum1, bool g_cmd) } else if (oap->motion_type == kMTLineWise) { curwin->w_cursor.col = 0; pos.col = 0; - length = (colnr_T)strlen(ml_get(pos.lnum)); + length = ml_get_len(pos.lnum); } else { // oap->motion_type == kMTCharWise if (pos.lnum == oap->start.lnum && !oap->inclusive) { dec(&(oap->end)); } - length = (colnr_T)strlen(ml_get(pos.lnum)); + length = ml_get_len(pos.lnum); pos.col = 0; if (pos.lnum == oap->start.lnum) { pos.col += oap->start.col; length -= oap->start.col; } if (pos.lnum == oap->end.lnum) { - length = (int)strlen(ml_get(oap->end.lnum)); + length = ml_get_len(oap->end.lnum); if (oap->end.col >= length) { oap->end.col = length - 1; } @@ -4806,16 +4800,17 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // "Unsigned" const bool do_unsigned = vim_strchr(curbuf->b_p_nf, 'u') != NULL; - if (virtual_active()) { + if (virtual_active(curwin)) { save_coladd = pos->coladd; pos->coladd = 0; } curwin->w_cursor = *pos; char *ptr = ml_get(pos->lnum); + int linelen = ml_get_len(pos->lnum); int col = pos->col; - if (*ptr == NUL || col + !!save_coladd >= (int)strlen(ptr)) { + if (col + !!save_coladd >= linelen) { goto theend; } @@ -4954,9 +4949,7 @@ bool do_addsub(int op_type, pos_T *pos, int length, linenr_T Prenum1) // get the number value (unsigned) if (visual && VIsual_mode != 'V') { - maxlen = (curbuf->b_visual.vi_curswant == MAXCOL - ? (int)strlen(ptr) - col - : length); + maxlen = curbuf->b_visual.vi_curswant == MAXCOL ? linelen - col : length; } bool overflow = false; @@ -5128,7 +5121,7 @@ theend: curwin->w_cursor = save_cursor; } else if (did_change) { curwin->w_set_curswant = true; - } else if (virtual_active()) { + } else if (virtual_active(curwin)) { curwin->w_cursor.coladd = save_coladd; } @@ -5714,7 +5707,7 @@ void cursor_pos_info(dict_T *dict) switch (l_VIsual_mode) { case Ctrl_V: - virtual_op = virtual_active(); + virtual_op = virtual_active(curwin); block_prep(&oparg, &bd, lnum, false); virtual_op = kNone; s = bd.textstart; @@ -5803,10 +5796,10 @@ void cursor_pos_info(dict_T *dict) } } else { char *p = get_cursor_line_ptr(); - validate_virtcol(); + validate_virtcol(curwin); col_print(buf1, sizeof(buf1), (int)curwin->w_cursor.col + 1, (int)curwin->w_virtcol + 1); - col_print(buf2, sizeof(buf2), (int)strlen(p), linetabsize_str(p)); + col_print(buf2, sizeof(buf2), get_cursor_line_len(), linetabsize_str(p)); if (char_count_cursor == byte_count_cursor && char_count == byte_count) { @@ -5888,7 +5881,7 @@ static void op_colon(oparg_T *oap) // When using !! on a closed fold the range ".!" works best to operate // on, it will be made the whole closed fold later. linenr_T endOfStartFold = oap->start.lnum; - hasFolding(oap->start.lnum, NULL, &endOfStartFold); + hasFolding(curwin, oap->start.lnum, NULL, &endOfStartFold); if (oap->end.lnum != oap->start.lnum && oap->end.lnum != endOfStartFold) { // Make it a range with the end line. stuffcharReadbuff(','); @@ -5899,7 +5892,7 @@ static void op_colon(oparg_T *oap) } else if (oap->start.lnum == curwin->w_cursor.lnum // do not use ".+number" for a closed fold, it would count // folded lines twice - && !hasFolding(oap->end.lnum, NULL, NULL)) { + && !hasFolding(curwin, oap->end.lnum, NULL, NULL)) { stuffReadbuff(".+"); stuffnumReadbuff(oap->line_count - 1); } else { @@ -6061,11 +6054,11 @@ static void get_op_vcol(oparg_T *oap, colnr_T redo_VIsual_vcol, bool initial) // (Actually, this does convert column positions into character // positions) curwin->w_cursor.lnum = oap->end.lnum; - coladvance(oap->end_vcol); + coladvance(curwin, oap->end_vcol); oap->end = curwin->w_cursor; curwin->w_cursor = oap->start; - coladvance(oap->start_vcol); + coladvance(curwin, oap->start_vcol); oap->start = curwin->w_cursor; } @@ -6190,7 +6183,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (redo_VIsual.rv_vcol == MAXCOL || VIsual_mode == 'v') { if (VIsual_mode == 'v') { if (redo_VIsual.rv_line_count <= 1) { - validate_virtcol(); + validate_virtcol(curwin); curwin->w_curswant = curwin->w_virtcol + redo_VIsual.rv_vcol - 1; } else { curwin->w_curswant = redo_VIsual.rv_vcol; @@ -6198,7 +6191,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else { curwin->w_curswant = MAXCOL; } - coladvance(curwin->w_curswant); + coladvance(curwin, curwin->w_curswant); } cap->count0 = redo_VIsual.rv_count; cap->count1 = (cap->count0 == 0 ? 1 : cap->count0); @@ -6220,11 +6213,10 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) && cap->oap->op_type != OP_DELETE) { if (lt(VIsual, curwin->w_cursor)) { VIsual.col = 0; - curwin->w_cursor.col = - (colnr_T)strlen(ml_get(curwin->w_cursor.lnum)); + curwin->w_cursor.col = ml_get_len(curwin->w_cursor.lnum); } else { curwin->w_cursor.col = 0; - VIsual.col = (colnr_T)strlen(ml_get(VIsual.lnum)); + VIsual.col = ml_get_len(VIsual.lnum); } VIsual_mode = 'v'; } else if (VIsual_mode == 'v') { @@ -6245,15 +6237,15 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (lt(oap->start, curwin->w_cursor)) { // Include folded lines completely. if (!VIsual_active) { - if (hasFolding(oap->start.lnum, &oap->start.lnum, NULL)) { + if (hasFolding(curwin, oap->start.lnum, &oap->start.lnum, NULL)) { oap->start.col = 0; } if ((curwin->w_cursor.col > 0 || oap->inclusive || oap->motion_type == kMTLineWise) - && hasFolding(curwin->w_cursor.lnum, NULL, + && hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { - curwin->w_cursor.col = (colnr_T)strlen(get_cursor_line_ptr()); + curwin->w_cursor.col = get_cursor_line_len(); } } oap->end = curwin->w_cursor; @@ -6266,12 +6258,12 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else { // Include folded lines completely. if (!VIsual_active && oap->motion_type == kMTLineWise) { - if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, + if (hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) { curwin->w_cursor.col = 0; } - if (hasFolding(oap->start.lnum, NULL, &oap->start.lnum)) { - oap->start.col = (colnr_T)strlen(ml_get(oap->start.lnum)); + if (hasFolding(curwin, oap->start.lnum, NULL, &oap->start.lnum)) { + oap->start.col = ml_get_len(oap->start.lnum); } } oap->end = oap->start; @@ -6283,7 +6275,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) oap->line_count = oap->end.lnum - oap->start.lnum + 1; // Set "virtual_op" before resetting VIsual_active. - virtual_op = virtual_active(); + virtual_op = virtual_active(curwin); if (VIsual_active || redo_VIsual_busy) { get_op_vcol(oap, redo_VIsual.rv_vcol, true); @@ -6455,7 +6447,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) if (inindent(0)) { oap->motion_type = kMTLineWise; } else { - oap->end.col = (colnr_T)strlen(ml_get(oap->end.lnum)); + oap->end.col = ml_get_len(oap->end.lnum); if (oap->end.col) { oap->end.col--; oap->inclusive = true; @@ -6514,7 +6506,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) oap->excl_tr_ws = cap->cmdchar == 'z'; op_yank(oap, !gui_yank); } - check_cursor_col(); + check_cursor_col(curwin); break; case OP_CHANGE: @@ -6588,7 +6580,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) } else { op_tilde(oap); } - check_cursor_col(); + check_cursor_col(curwin); break; case OP_FORMAT: @@ -6706,7 +6698,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) op_addsub(oap, (linenr_T)cap->count1, redo_VIsual.rv_arg); VIsual_active = false; } - check_cursor_col(); + check_cursor_col(curwin); break; default: clearopbeep(oap); @@ -6718,7 +6710,7 @@ void do_pending_operator(cmdarg_T *cap, int old_col, bool gui_yank) && (oap->op_type == OP_LSHIFT || oap->op_type == OP_RSHIFT || oap->op_type == OP_DELETE)) { reset_lbr(); - coladvance(curwin->w_curswant = old_col); + coladvance(curwin, curwin->w_curswant = old_col); } } else { curwin->w_cursor = old_cursor; @@ -6763,7 +6755,7 @@ static yankreg_T *adjust_clipboard_name(int *name, bool quiet, bool writing) goto end; } - if (!eval_has_provider("clipboard")) { + if (!eval_has_provider("clipboard", false)) { if (batch_change_count <= 1 && !quiet && (!clipboard_didwarn || (explicit_cb_reg && !redirecting()))) { clipboard_didwarn = true; @@ -7232,14 +7224,13 @@ bcount_t get_region_bytecount(buf_T *buf, linenr_T start_lnum, linenr_T end_lnum if (start_lnum == end_lnum) { return end_col - start_col; } - const char *first = ml_get_buf(buf, start_lnum); - bcount_t deleted_bytes = (bcount_t)strlen(first) - start_col + 1; + bcount_t deleted_bytes = ml_get_buf_len(buf, start_lnum) - start_col + 1; for (linenr_T i = 1; i <= end_lnum - start_lnum - 1; i++) { if (start_lnum + i > max_lnum) { return deleted_bytes; } - deleted_bytes += (bcount_t)strlen(ml_get_buf(buf, start_lnum + i)) + 1; + deleted_bytes += ml_get_buf_len(buf, start_lnum + i) + 1; } if (end_lnum > max_lnum) { return deleted_bytes; diff --git a/src/nvim/option.c b/src/nvim/option.c index d5df8385f8..22897d4f7e 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -430,10 +430,9 @@ static void set_option_default(const OptIndex opt_idx, int opt_flags) uint32_t flags = opt->flags; if (varp != NULL) { // skip hidden option, nothing to do for it if (option_has_type(opt_idx, kOptValTypeString)) { - // Use set_string_option_direct() for local options to handle freeing and allocating the - // value. + // Use set_option_direct() for local options to handle freeing and allocating the value. if (opt->indir != PV_NONE) { - set_string_option_direct(opt_idx, opt->def_val.string, opt_flags, 0); + set_option_direct(opt_idx, CSTR_AS_OPTVAL(opt->def_val.string), opt_flags, 0); } else { if (flags & P_ALLOCED) { free_string_option(*(char **)(varp)); @@ -765,7 +764,7 @@ static char *stropt_get_default_val(OptIndex opt_idx, uint64_t flags) } /// Copy the new string value into allocated memory for the option. -/// Can't use set_string_option_direct(), because we need to remove the backslashes. +/// Can't use set_option_direct(), because we need to remove the backslashes. static char *stropt_copy_value(char *origval, char **argp, set_op_T op, uint32_t flags FUNC_ATTR_UNUSED) { @@ -1398,7 +1397,8 @@ static void do_one_set_option(int opt_flags, char **argp, bool *did_show, char * return; } - *errmsg = set_option(opt_idx, varp, newval, opt_flags, op == OP_NONE, errbuf, errbuflen); + *errmsg = set_option(opt_idx, varp, newval, opt_flags, 0, false, op == OP_NONE, errbuf, + errbuflen); } /// Parse 'arg' for option settings. @@ -1937,7 +1937,7 @@ static const char *did_set_arabic(optset_T *args) // set rightleft mode if (!win->w_p_rl) { win->w_p_rl = true; - changed_window_setting(); + changed_window_setting(curwin); } // Enable Arabic shaping (major part of what Arabic requires) @@ -1968,7 +1968,7 @@ static const char *did_set_arabic(optset_T *args) // reset rightleft mode if (win->w_p_rl) { win->w_p_rl = false; - changed_window_setting(); + changed_window_setting(curwin); } // 'arabicshape' isn't reset, it is a global option and @@ -2024,9 +2024,6 @@ static const char *did_set_cmdheight(optset_T *args) { OptInt old_value = args->os_oldval.number; - if (ui_has(kUIMessages)) { - p_ch = 0; - } if (p_ch > Rows - min_rows() + 1) { p_ch = Rows - min_rows() + 1; } @@ -2247,7 +2244,7 @@ static const char *did_set_modified(optset_T *args) save_file_ff(buf); // Buffer is unchanged } redraw_titles(); - modified_was_set = (int)args->os_newval.boolean; + buf->b_modified_was_set = (int)args->os_newval.boolean; return NULL; } @@ -2901,8 +2898,6 @@ static const char *validate_num_option(OptIndex opt_idx, void *varp, OptInt *new } else if (value > p_wiw) { return e_winwidth; } - } else if (varp == &p_mco) { - *newval = MAX_MCO; } else if (varp == &p_titlelen) { if (value < 0) { return e_positive; @@ -3032,7 +3027,7 @@ void check_redraw_for(buf_T *buf, win_T *win, uint32_t flags) if (flags & P_HLONLY) { redraw_later(win, UPD_NOT_VALID); } else { - changed_window_setting_win(win); + changed_window_setting(win); } } if (flags & P_RBUF) { @@ -3314,38 +3309,6 @@ OptVal object_as_optval(Object o, bool *error) UNREACHABLE; } -/// Unset the local value of an option. The exact semantics of this depend on the option. -/// TODO(famiu): Remove this once we have a dedicated OptVal type for unset local options. -/// -/// @param opt_idx Option index in options[] table. -/// @param[in] varp Pointer to option variable. -/// -/// @return [allocated] Option value equal to the unset value for the option. -static OptVal optval_unset_local(OptIndex opt_idx, void *varp) -{ - vimoption_T *opt = &options[opt_idx]; - // For global-local options, use the unset value of the local value. - if (opt->indir & PV_BOTH) { - // String global-local options always use an empty string for the unset value. - if (option_has_type(opt_idx, kOptValTypeString)) { - return STATIC_CSTR_TO_OPTVAL(""); - } - - if ((int *)varp == &curbuf->b_p_ar) { - return BOOLEAN_OPTVAL(kNone); - } else if ((OptInt *)varp == &curwin->w_p_so || (OptInt *)varp == &curwin->w_p_siso) { - return NUMBER_OPTVAL(-1); - } else if ((OptInt *)varp == &curbuf->b_p_ul) { - return NUMBER_OPTVAL(NO_LOCAL_UNDOLEVEL); - } else { - // This should never happen. - abort(); - } - } - // For options that aren't global-local, just set the local value to the global value. - return get_option_value(opt_idx, OPT_GLOBAL); -} - /// Get an allocated string containing a list of valid types for an option. /// For options with a singular type, it returns the name of the type. For options with multiple /// possible types, it returns a slash separated list of types. For example, if an option can be a @@ -3420,24 +3383,60 @@ vimoption_T *get_option(OptIndex opt_idx) return &options[opt_idx]; } +/// Get option value that represents an unset local value for an option. +/// TODO(famiu): Remove this once we have a dedicated OptVal type for unset local options. +/// +/// @param opt_idx Option index in options[] table. +/// @param[in] varp Pointer to option variable. +/// +/// @return Option value equal to the unset value for the option. +static OptVal get_option_unset_value(OptIndex opt_idx) +{ + assert(opt_idx != kOptInvalid); + vimoption_T *opt = &options[opt_idx]; + + // For global-local options, use the unset value of the local value. + if (opt->indir & PV_BOTH) { + // String global-local options always use an empty string for the unset value. + if (option_has_type(opt_idx, kOptValTypeString)) { + return STATIC_CSTR_AS_OPTVAL(""); + } + + switch (opt_idx) { + case kOptAutoread: + return BOOLEAN_OPTVAL(kNone); + case kOptScrolloff: + case kOptSidescrolloff: + return NUMBER_OPTVAL(-1); + case kOptUndolevels: + return NUMBER_OPTVAL(NO_LOCAL_UNDOLEVEL); + default: + abort(); + } + } + + // For options that aren't global-local, use the global value to represent an unset local value. + return optval_from_varp(opt_idx, get_varp_scope(opt, OPT_GLOBAL)); +} + /// Check if local value of global-local option is unset for current buffer / window. /// Always returns false for options that aren't global-local. /// /// TODO(famiu): Remove this once we have an OptVal type to indicate an unset local value. -static bool is_option_local_value_unset(vimoption_T *opt, buf_T *buf, win_T *win) +static bool is_option_local_value_unset(OptIndex opt_idx) { + vimoption_T *opt = get_option(opt_idx); + // Local value of option that isn't global-local is always considered set. if (!((int)opt->indir & PV_BOTH)) { return false; } - // Get pointer to local value in varp_local, and a pointer to the currently used value in varp. - // If the local value is the one currently being used, that indicates that it's set. - // Otherwise it indicates the local value is unset. - void *varp = get_varp_from(opt, buf, win); - void *varp_local = get_varp_scope_from(opt, OPT_LOCAL, buf, win); + void *varp_local = get_varp_scope(opt, OPT_LOCAL); + OptVal local_value = optval_from_varp(opt_idx, varp_local); + OptVal unset_local_value = get_option_unset_value(opt_idx); - return varp != varp_local; + return optval_equal(local_value, unset_local_value); } /// Handle side-effects of setting an option. @@ -3445,17 +3444,19 @@ static bool is_option_local_value_unset(vimoption_T *opt, buf_T *buf, win_T *win /// @param opt_idx Index in options[] table. Must not be kOptInvalid. /// @param[in] varp Option variable pointer, cannot be NULL. /// @param old_value Old option value. -/// @param new_value New option value. /// @param opt_flags Option flags. -/// @param[out] value_checked Value was checked to be safe, no need to set P_INSECURE. +/// @param set_sid Script ID. Special values: +/// 0: Use current script ID. +/// SID_NONE: Don't set script ID. +/// @param direct Don't process side-effects. /// @param value_replaced Value was replaced completely. /// @param[out] errbuf Buffer for error message. /// @param errbuflen Length of error buffer. /// /// @return NULL on success, an untranslated error message on error. static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value, OptVal new_value, - int opt_flags, bool *value_checked, bool value_replaced, - char *errbuf, // NOLINT(readability-non-const-parameter) + int opt_flags, scid_T set_sid, const bool direct, + const bool value_replaced, char *errbuf, // NOLINT(readability-non-const-parameter) size_t errbuflen) { vimoption_T *opt = &options[opt_idx]; @@ -3463,6 +3464,7 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value bool restore_chartab = false; bool free_oldval = (opt->flags & P_ALLOCED); bool value_changed = false; + bool value_checked = false; optset_T did_set_cb_args = { .os_varp = varp, @@ -3479,8 +3481,11 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value .os_win = curwin }; + if (direct || opt->hidden) { + // Don't do any extra processing if setting directly or if option is hidden. + } // Disallow changing immutable options. - if (opt->immutable && !optval_equal(old_value, new_value)) { + else if (opt->immutable && !optval_equal(old_value, new_value)) { errmsg = e_unsupportedoption; } // Disallow changing some options from secure mode. @@ -3498,30 +3503,41 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value value_changed = did_set_cb_args.os_value_changed; // The 'keymap', 'filetype' and 'syntax' option callback functions may change the // os_value_checked field. - *value_checked = did_set_cb_args.os_value_checked; + value_checked = did_set_cb_args.os_value_checked; // The 'isident', 'iskeyword', 'isprint' and 'isfname' options may change the character table. // On failure, this needs to be restored. restore_chartab = did_set_cb_args.os_restore_chartab; } - // If an error is detected, restore the previous value and don't do any further processing. - if (errmsg != NULL) { + // If option is hidden or if an error is detected, restore the previous value and don't do any + // further processing. + if (opt->hidden || errmsg != NULL) { set_option_varp(opt_idx, varp, old_value, true); // When resetting some values, need to act on it. if (restore_chartab) { buf_init_chartab(curbuf, true); } - // Unset new_value as it is no longer valid. - new_value = NIL_OPTVAL; // NOLINT(clang-analyzer-deadcode.DeadStores) return errmsg; } // Re-assign the new value as its value may get freed or modified by the option callback. new_value = optval_from_varp(opt_idx, varp); - // Remember where the option was set. - set_option_sctx(opt_idx, opt_flags, current_sctx); + if (set_sid != SID_NONE) { + sctx_T script_ctx; + + if (set_sid == 0) { + script_ctx = current_sctx; + } else { + script_ctx.sc_sid = set_sid; + script_ctx.sc_seq = 0; + script_ctx.sc_lnum = 0; + } + // Remember where the option was set. + set_option_sctx(opt_idx, opt_flags, script_ctx); + } + // Free options that are in allocated memory. // Use "free_oldval", because recursiveness may change the flags (esp. init_highlight()). if (free_oldval) { @@ -3529,16 +3545,26 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value } opt->flags |= P_ALLOCED; - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 && (opt->indir & PV_BOTH)) { - // Global option with local value set to use global value. - // Free the local value and clear it. - void *varp_local = get_varp_scope(opt, OPT_LOCAL); - OptVal local_unset_value = optval_unset_local(opt_idx, varp_local); - set_option_varp(opt_idx, varp_local, local_unset_value, true); - } else if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - // May set global value for local option. - void *varp_global = get_varp_scope(opt, OPT_GLOBAL); - set_option_varp(opt_idx, varp_global, optval_copy(new_value), true); + const bool scope_both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; + const bool opt_is_global_local = opt->indir & PV_BOTH; + + if (scope_both) { + if (opt_is_global_local) { + // Global option with local value set to use global value. + // Free the local value and clear it. + void *varp_local = get_varp_scope(opt, OPT_LOCAL); + OptVal local_unset_value = get_option_unset_value(opt_idx); + set_option_varp(opt_idx, varp_local, optval_copy(local_unset_value), true); + } else { + // May set global value for local option. + void *varp_global = get_varp_scope(opt, OPT_GLOBAL); + set_option_varp(opt_idx, varp_global, optval_copy(new_value), true); + } + } + + // Don't do anything else if setting the option directly. + if (direct) { + return errmsg; } // Trigger the autocommand only after setting the flags. @@ -3592,91 +3618,105 @@ static const char *did_set_option(OptIndex opt_idx, void *varp, OptVal old_value return errmsg; } -/// Set the value of an option using an OptVal. +/// Validate the new value for an option. /// -/// @param opt_idx Index in options[] table. Must not be kOptInvalid. -/// @param[in] varp Option variable pointer, cannot be NULL. -/// @param value New option value. Might get freed. -/// @param opt_flags Option flags. -/// @param value_replaced Value was replaced completely. -/// @param[out] errbuf Buffer for error message. -/// @param errbuflen Length of error buffer. -/// -/// @return NULL on success, an untranslated error message on error. -static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, int opt_flags, - const bool value_replaced, char *errbuf, size_t errbuflen) +/// @param opt_idx Index in options[] table. Must not be kOptInvalid. +/// @param varp Pointer to option variable. +/// @param newval[in,out] New option value. Might be modified. +static const char *validate_option_value(const OptIndex opt_idx, void *varp, OptVal *newval, + int opt_flags, char *errbuf, size_t errbuflen) { - assert(opt_idx != kOptInvalid && varp != NULL); - const char *errmsg = NULL; - bool value_checked = false; - vimoption_T *opt = &options[opt_idx]; - if (value.type == kOptValTypeNil) { + if (newval->type == kOptValTypeNil) { // Don't try to unset local value if scope is global. // TODO(famiu): Change this to forbid changing all non-local scopes when the API scope bug is // fixed. if (opt_flags == OPT_GLOBAL) { errmsg = _("Cannot unset global option value"); } else { - optval_free(value); - value = optval_unset_local(opt_idx, varp); + optval_free(*newval); + *newval = optval_copy(get_option_unset_value(opt_idx)); } - } else if (!option_has_type(opt_idx, value.type)) { - char *rep = optval_to_cstr(value); + } else if (!option_has_type(opt_idx, newval->type)) { + char *rep = optval_to_cstr(*newval); char *valid_types = option_get_valid_types(opt_idx); snprintf(errbuf, IOSIZE, _("Invalid value for option '%s': expected %s, got %s %s"), - opt->fullname, valid_types, optval_type_get_name(value.type), rep); + opt->fullname, valid_types, optval_type_get_name(newval->type), rep); xfree(rep); xfree(valid_types); errmsg = errbuf; + } else if (newval->type == kOptValTypeNumber) { + // Validate and bound check num option values. + errmsg = validate_num_option(opt_idx, varp, &newval->data.number, errbuf, errbuflen); } + return errmsg; +} + +/// Set the value of an option using an OptVal. +/// +/// @param opt_idx Index in options[] table. Must not be kOptInvalid. +/// @param[in] varp Option variable pointer, cannot be NULL. +/// @param value New option value. Might get freed. +/// @param opt_flags Option flags. +/// @param set_sid Script ID. Special values: +/// 0: Use current script ID. +/// SID_NONE: Don't set script ID. +/// @param direct Don't process side-effects. +/// @param value_replaced Value was replaced completely. +/// @param[out] errbuf Buffer for error message. +/// @param errbuflen Length of error buffer. +/// +/// @return NULL on success, an untranslated error message on error. +static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, int opt_flags, + scid_T set_sid, const bool direct, const bool value_replaced, + char *errbuf, size_t errbuflen) + FUNC_ATTR_NONNULL_ARG(2) +{ + assert(opt_idx != kOptInvalid); + + const char *errmsg = validate_option_value(opt_idx, varp, &value, opt_flags, errbuf, errbuflen); + if (errmsg != NULL) { - goto err; + optval_free(value); + return errmsg; } + vimoption_T *opt = &options[opt_idx]; + const bool scope_local = opt_flags & OPT_LOCAL; + const bool scope_global = opt_flags & OPT_GLOBAL; + const bool scope_both = !scope_local && !scope_global; + const bool opt_is_global_local = opt->indir & PV_BOTH; + // Whether local value of global-local option is unset. + // NOTE: When this is true, it also implies that opt_is_global_local is true. + const bool is_opt_local_unset = is_option_local_value_unset(opt_idx); + // When using ":set opt=val" for a global option with a local value the local value will be reset, // use the global value here. - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0 && ((int)opt->indir & PV_BOTH)) { + if (scope_both && opt_is_global_local) { varp = opt->var; } - OptVal old_value = optval_from_varp(opt_idx, varp); - OptVal old_global_value = NIL_OPTVAL; - OptVal old_local_value = NIL_OPTVAL; - - // Save the local and global values before changing anything. This is needed as for a global-only - // option setting the "local value" in fact sets the global value (since there is only one value). - // - // TODO(famiu): This needs to be changed to use the current type of the old value instead of - // value.type, when multi-type options are added. - if ((opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0) { - old_global_value = optval_from_varp(opt_idx, get_varp_scope(opt, OPT_GLOBAL)); - old_local_value = optval_from_varp(opt_idx, get_varp_scope(opt, OPT_LOCAL)); - - // If local value of global-local option is unset, use global value as local value. - if (is_option_local_value_unset(opt, curbuf, curwin)) { - old_local_value = old_global_value; - } - } + void *varp_local = get_varp_scope(opt, OPT_LOCAL); + void *varp_global = get_varp_scope(opt, OPT_GLOBAL); + OptVal old_value = optval_from_varp(opt_idx, varp); + OptVal old_global_value = optval_from_varp(opt_idx, varp_global); + // If local value of global-local option is unset, use global value as local value. + OptVal old_local_value = is_opt_local_unset + ? old_global_value + : optval_from_varp(opt_idx, varp_local); // Value that's actually being used. - // For local scope of a global-local option, it is equal to the global value. - // In every other case, it is the same as old_value. - const bool oldval_is_global = ((int)opt->indir & PV_BOTH) && (opt_flags & OPT_LOCAL); - OptVal used_old_value = oldval_is_global ? optval_from_varp(opt_idx, get_varp(opt)) : old_value; - - if (value.type == kOptValTypeNumber) { - errmsg = validate_num_option(opt_idx, varp, &value.data.number, errbuf, errbuflen); - if (errmsg != NULL) { - goto err; - } - } - - set_option_varp(opt_idx, varp, value, false); - + // For local scope of a global-local option, it's equal to the global value if the local value is + // unset. In every other case, it is the same as old_value. + // This value is used instead of old_value when triggering the OptionSet autocommand. + OptVal used_old_value = (scope_local && is_opt_local_unset) + ? optval_from_varp(opt_idx, get_varp(opt)) + : old_value; + + // Save the old values and the new value in case they get changed. OptVal saved_used_value = optval_copy(used_old_value); OptVal saved_old_global_value = optval_copy(old_global_value); OptVal saved_old_local_value = optval_copy(old_local_value); @@ -3693,23 +3733,20 @@ static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, secure = 1; } - errmsg = did_set_option(opt_idx, varp, old_value, value, opt_flags, &value_checked, + // Set option through its variable pointer. + set_option_varp(opt_idx, varp, value, false); + // Process any side effects. + errmsg = did_set_option(opt_idx, varp, old_value, value, opt_flags, set_sid, direct, value_replaced, errbuf, errbuflen); secure = secure_saved; - if (errmsg == NULL) { + if (errmsg == NULL && !direct) { if (!starting) { apply_optionset_autocmd(opt_idx, opt_flags, saved_used_value, saved_old_global_value, saved_old_local_value, saved_new_value, errmsg); } if (opt->flags & P_UI_OPTION) { - // Calculate saved_new_value again as its value might be changed by bound checks. - // NOTE: Currently there are no buffer/window local UI options, but if there ever are buffer - // or window local UI options added in the future, varp might become invalid if the buffer or - // window is closed during an autocommand, and a check would have to be added for it. - optval_free(saved_new_value); - saved_new_value = optval_copy(optval_from_varp(opt_idx, varp)); ui_call_option_set(cstr_as_string(opt->fullname), optval_as_object(saved_new_value)); } } @@ -3719,10 +3756,70 @@ static const char *set_option(const OptIndex opt_idx, void *varp, OptVal value, optval_free(saved_old_local_value); optval_free(saved_old_global_value); optval_free(saved_new_value); + return errmsg; -err: - optval_free(value); - return errmsg; +} + +/// Set option value directly, without processing any side effects. +/// +/// @param opt_idx Option index in options[] table. +/// @param value Option value. +/// @param opt_flags Option flags. +/// @param set_sid Script ID. Special values: +/// 0: Use current script ID. +/// SID_NONE: Don't set script ID. +void set_option_direct(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid) +{ + static char errbuf[IOSIZE]; + + vimoption_T *opt = get_option(opt_idx); + + if (opt->var == NULL) { + return; + } + + const bool scope_both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; + void *varp = get_varp_scope(opt, scope_both ? OPT_LOCAL : opt_flags); + + set_option(opt_idx, varp, optval_copy(value), opt_flags, set_sid, true, true, errbuf, + sizeof(errbuf)); +} + +/// Set option value directly for buffer / window, without processing any side effects. +/// +/// @param opt_idx Option index in options[] table. +/// @param value Option value. +/// @param opt_flags Option flags. +/// @param set_sid Script ID. Special values: +/// 0: Use current script ID. +/// SID_NONE: Don't set script ID. +/// @param req_scope Requested option scope. See OptReqScope in option.h. +/// @param[in] from Target buffer/window. +void set_option_direct_for(OptIndex opt_idx, OptVal value, int opt_flags, scid_T set_sid, + OptReqScope req_scope, void *const from) +{ + buf_T *save_curbuf = curbuf; + win_T *save_curwin = curwin; + + // Don't use switch_option_context(), as that calls aucmd_prepbuf(), which may have unintended + // side-effects when setting an option directly. Just change the values of curbuf and curwin if + // needed, no need to properly switch the window / buffer. + switch (req_scope) { + case kOptReqGlobal: + break; + case kOptReqBuf: + curbuf = (buf_T *)from; + break; + case kOptReqWin: + curwin = (win_T *)from; + curbuf = curwin->w_buffer; + break; + } + + set_option_direct(opt_idx, value, opt_flags, set_sid); + + curwin = save_curwin; + curbuf = save_curbuf; } /// Set the value of an option. @@ -3750,7 +3847,8 @@ const char *set_option_value(const OptIndex opt_idx, const OptVal value, int opt return NULL; } - return set_option(opt_idx, varp, optval_copy(value), opt_flags, true, errbuf, sizeof(errbuf)); + return set_option(opt_idx, varp, optval_copy(value), opt_flags, 0, false, true, errbuf, + sizeof(errbuf)); } /// Set the value of an option. Supports TTY options, unlike set_option_value(). @@ -4128,7 +4226,7 @@ static int optval_default(OptIndex opt_idx, void *varp) vimoption_T *opt = &options[opt_idx]; // Hidden or immutable options always use their default value. - if (varp == NULL || opt->immutable) { + if (varp == NULL || opt->hidden || opt->immutable) { return true; } @@ -4629,6 +4727,8 @@ void *get_varp_from(vimoption_T *p, buf_T *buf, win_T *win) return &(win->w_p_rnu); case PV_NUW: return &(win->w_p_nuw); + case PV_WFB: + return &(win->w_p_wfb); case PV_WFH: return &(win->w_p_wfh); case PV_WFW: @@ -6109,9 +6209,9 @@ char *get_flp_value(buf_T *buf) } /// Get the local or global value of the 'virtualedit' flags. -unsigned get_ve_flags(void) +unsigned get_ve_flags(win_T *wp) { - return (curwin->w_ve_flags ? curwin->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU); + return (wp->w_ve_flags ? wp->w_ve_flags : ve_flags) & ~(VE_NONE | VE_NONEU); } /// Get the local or global value of 'showbreak'. @@ -6208,7 +6308,7 @@ void set_fileformat(int eol_style, int opt_flags) // p is NULL if "eol_style" is EOL_UNKNOWN. if (p != NULL) { - set_string_option_direct(kOptFileformat, p, opt_flags, 0); + set_option_direct(kOptFileformat, CSTR_AS_OPTVAL(p), opt_flags, 0); } // This may cause the buffer to become (un)modified. diff --git a/src/nvim/option.h b/src/nvim/option.h index 7cf880b19b..19764c0121 100644 --- a/src/nvim/option.h +++ b/src/nvim/option.h @@ -49,7 +49,8 @@ typedef struct { ///< buffer-local option: global value idopt_T indir; ///< global option: PV_NONE; ///< local option: indirect option index - bool immutable; ///< option value cannot be changed from the default value. + bool hidden; ///< option is hidden, any attempt to set its value will be ignored. + bool immutable; ///< option is immutable, trying to set its value will give an error. /// callback function to invoke after an option is modified to validate and /// apply the new value. diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index 69d8f0833d..be78a708ad 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -61,7 +61,7 @@ "-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel," \ "[:PmenuKind,]:PmenuKindSel,{:PmenuExtra,}:PmenuExtraSel,x:PmenuSbar,X:PmenuThumb," \ "*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn," \ - "q:QuickFixLine,0:Whitespace,I:NormalNC" + "q:QuickFixLine,g:MsgArea,0:Whitespace,I:NormalNC" // Default values for 'errorformat'. // The "%f|%l| %m" one is used for when the contents of the quickfix window is @@ -129,6 +129,8 @@ #define DFLT_FO_VIM "tcqj" #define FO_ALL "tcro/q2vlb1mMBn,aw]jp" // for do_set() +#define MAX_MCO 6 // fixed value for 'maxcombine' + // characters for the p_cpo option: #define CPO_ALTREAD 'a' // ":read" sets alternate file name #define CPO_ALTWRITE 'A' // ":write" sets alternate file name @@ -549,8 +551,6 @@ EXTERN char *p_mef; ///< 'makeef' EXTERN char *p_mp; ///< 'makeprg' EXTERN char *p_mps; ///< 'matchpairs' EXTERN OptInt p_mat; ///< 'matchtime' -EXTERN OptInt p_mco; ///< 'maxcombine' -#define MAX_MCO 6 // fixed value for 'maxcombine' EXTERN OptInt p_mfd; ///< 'maxfuncdepth' EXTERN OptInt p_mmd; ///< 'maxmapdepth' EXTERN OptInt p_mmp; ///< 'maxmempattern' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 632732d7b7..5173240384 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -7,6 +7,7 @@ --- @field varname? string --- @field pv_name? string --- @field type 'boolean'|'number'|'string' +--- @field hidden? boolean --- @field immutable? boolean --- @field list? 'comma'|'onecomma'|'commacolon'|'onecommacolon'|'flags'|'flagscomma' --- @field scope vim.option_scope[] @@ -90,6 +91,7 @@ return { { abbreviation = 'al', defaults = { if_true = 224 }, + enable_if = false, full_name = 'aleph', scope = { 'global' }, short_desc = N_('ASCII code of the letter Aleph (Hebrew)'), @@ -99,14 +101,13 @@ return { abbreviation = 'ari', defaults = { if_true = false }, desc = [=[ - Allow CTRL-_ in Insert and Command-line mode. This is default off, to - avoid that users that accidentally type CTRL-_ instead of SHIFT-_ get - into reverse Insert mode, and don't know how to get out. See - 'revins'. + Allow CTRL-_ in Insert mode. This is default off, to avoid that users + that accidentally type CTRL-_ instead of SHIFT-_ get into reverse + Insert mode, and don't know how to get out. See 'revins'. ]=], full_name = 'allowrevins', scope = { 'global' }, - short_desc = N_('allow CTRL-_ in Insert and Command-line mode'), + short_desc = N_('allow CTRL-_ in Insert mode'), type = 'boolean', varname = 'p_ari', }, @@ -1323,7 +1324,7 @@ return { defaults = { if_true = '' }, desc = [=[ A template for a comment. The "%s" in the value is replaced with the - comment text. For example, C uses "/*%s*/". Currently only used to + comment text. For example, C uses "/*%s*/". Used for |commenting| and to add markers for folding, see |fold-marker|. ]=], full_name = 'commentstring', @@ -3367,6 +3368,8 @@ return { Format to recognize for the ":grep" command output. This is a scanf-like string that uses the same format as the 'errorformat' option: see |errorformat|. + + If ripgrep ('grepprg') is available, this option defaults to `%f:%l:%c:%m`. ]=], full_name = 'grepformat', list = 'onecomma', @@ -3379,10 +3382,9 @@ return { abbreviation = 'gp', defaults = { condition = 'MSWIN', - if_false = 'grep -n $* /dev/null', + if_false = 'grep -HIn $* /dev/null', if_true = 'findstr /n $* nul', - doc = [["grep -n ", - Unix: "grep -n $* /dev/null"]], + doc = [[see below]], }, desc = [=[ Program to use for the |:grep| command. This option may contain '%' @@ -3390,16 +3392,23 @@ return { line. The placeholder "$*" is allowed to specify where the arguments will be included. Environment variables are expanded |:set_env|. See |option-backslash| about including spaces and backslashes. - When your "grep" accepts the "-H" argument, use this to make ":grep" - also work well with a single file: >vim - set grepprg=grep\ -nH - < Special value: When 'grepprg' is set to "internal" the |:grep| command + Special value: When 'grepprg' is set to "internal" the |:grep| command works like |:vimgrep|, |:lgrep| like |:lvimgrep|, |:grepadd| like |:vimgrepadd| and |:lgrepadd| like |:lvimgrepadd|. See also the section |:make_makeprg|, since most of the comments there apply equally to 'grepprg'. This option cannot be set from a |modeline| or in the |sandbox|, for security reasons. + This option defaults to: + - `rg --vimgrep -uu ` if ripgrep is available (|:checkhealth|), + - `grep -HIn $* /dev/null` on Unix, + - `findstr /n $* nul` on Windows. + Ripgrep can perform additional filtering such as using .gitignore rules + and skipping hidden files. This is disabled by default (see the -u option) + to more closely match the behaviour of standard grep. + You can make ripgrep match Vim's case handling using the + -i/--ignore-case and -S/--smart-case options. + An |OptionSet| autocmd can be used to set it up to match automatically. ]=], expand = true, full_name = 'grepprg', @@ -5142,12 +5151,12 @@ return { }, { abbreviation = 'mco', - defaults = { if_true = 6 }, + defaults = { if_true = imacros('MAX_MCO') }, full_name = 'maxcombine', scope = { 'global' }, short_desc = N_('maximum nr of combining characters displayed'), type = 'number', - varname = 'p_mco', + hidden = true, }, { abbreviation = 'mfd', @@ -5459,7 +5468,6 @@ return { When on, the mouse pointer is hidden when characters are typed. The mouse pointer is restored when the mouse is moved. ]=], - enable_if = false, full_name = 'mousehide', redraw = { 'ui_option' }, scope = { 'global' }, @@ -5875,6 +5883,7 @@ return { { abbreviation = 'pt', defaults = { if_true = '' }, + enable_if = false, full_name = 'pastetoggle', scope = { 'global' }, short_desc = N_('No description'), @@ -6573,9 +6582,6 @@ return { top are deleted if new lines exceed this limit. Minimum is 1, maximum is 100000. Only in |terminal| buffers. - - Note: Lines that are not visible and kept in scrollback are not - reflown when the terminal buffer is resized horizontally. ]=], full_name = 'scrollback', redraw = { 'current_buffer' }, @@ -7665,8 +7671,7 @@ return { highlighted with |hl-NonText|. You may also want to add "lastline" to the 'display' option to show as much of the last line as possible. - NOTE: only partly implemented, currently works with CTRL-E, CTRL-Y - and scrolling with the mouse. + NOTE: partly implemented, doesn't work yet for |gj| and |gk|. ]=], full_name = 'smoothscroll', pv_name = 'p_sms', @@ -8406,6 +8411,8 @@ return { "split" when both are present. uselast If included, jump to the previously used window when jumping to errors with |quickfix| commands. + If a window has 'winfixbuf' enabled, 'switchbuf' is currently not + applied to the split window. ]=], expand_cb = 'expand_set_switchbuf', full_name = 'switchbuf', @@ -8530,7 +8537,7 @@ return { appear wrong in many places. The value must be more than 0 and less than 10000. - There are four main ways to use tabs in Vim: + There are five main ways to use tabs in Vim: 1. Always keep 'tabstop' at 8, set 'softtabstop' and 'shiftwidth' to 4 (or 3 or whatever you prefer) and use 'noexpandtab'. Then Vim will use a mix of tabs and spaces, but typing <Tab> and <BS> will @@ -8768,6 +8775,7 @@ return { { abbreviation = 'tenc', defaults = { if_true = '' }, + enable_if = false, full_name = 'termencoding', scope = { 'global' }, short_desc = N_('Terminal encoding'), @@ -9360,6 +9368,7 @@ return { Level Messages ~ ---------------------------------------------------------------------- + 1 Enables Lua tracing (see above). Does not produce messages. 2 When a file is ":source"'ed, or |shada| file is read or written. 3 UI info, terminal capabilities. 4 Shell commands. @@ -9863,8 +9872,8 @@ return { will scroll 'window' minus two lines, with a minimum of one. When 'window' is equal to 'lines' minus one CTRL-F and CTRL-B scroll in a much smarter way, taking care of wrapping lines. - When resizing the Vim window, the value is smaller than 1 or more than - or equal to 'lines' it will be set to 'lines' minus 1. + When resizing the Vim window, and the value is smaller than 1 or more + than or equal to 'lines' it will be set to 'lines' minus 1. Note: Do not confuse this with the height of the Vim window, use 'lines' for that. ]=], @@ -9875,6 +9884,23 @@ return { varname = 'p_window', }, { + abbreviation = 'wfb', + defaults = { if_true = false }, + desc = [=[ + If enabled, the window and the buffer it is displaying are paired. + For example, attempting to change the buffer with |:edit| will fail. + Other commands which change a window's buffer such as |:cnext| will + also skip any window with 'winfixbuf' enabled. However if an Ex + command has a "!" modifier, it can force switching buffers. + ]=], + full_name = 'winfixbuf', + pv_name = 'p_wfb', + redraw = { 'current_window' }, + scope = { 'window' }, + short_desc = N_('pin a window to a specific buffer'), + type = 'boolean', + }, + { abbreviation = 'wfh', defaults = { if_true = false }, desc = [=[ diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 4be08b28f5..29433ddbb5 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -266,113 +266,6 @@ void check_string_option(char **pp) } } -/// Set global value for string option when it's a local option. -/// -/// @param opt option -/// @param varp pointer to option variable -static void set_string_option_global(vimoption_T *opt, char **varp) -{ - char **p; - - // the global value is always allocated - if (opt->var == VAR_WIN) { - p = (char **)GLOBAL_WO(varp); - } else { - p = (char **)opt->var; - } - if (opt->indir != PV_NONE && p != varp) { - char *s = xstrdup(*varp); - free_string_option(*p); - *p = s; - } -} - -/// Set a string option to a new value (without checking the effect). -/// The string is copied into allocated memory. -/// if ("opt_idx" == kOptInvalid) "name" is used, otherwise "opt_idx" is used. -/// When "set_sid" is zero set the scriptID to current_sctx.sc_sid. When -/// "set_sid" is SID_NONE don't set the scriptID. Otherwise set the scriptID to -/// "set_sid". -/// -/// @param opt_flags Option flags. -/// -/// TODO(famiu): Remove this and its win/buf variants. -void set_string_option_direct(OptIndex opt_idx, const char *val, int opt_flags, scid_T set_sid) -{ - vimoption_T *opt = get_option(opt_idx); - - if (opt->var == NULL) { // can't set hidden option - return; - } - - assert(opt->var != &p_shada); - - bool both = (opt_flags & (OPT_LOCAL | OPT_GLOBAL)) == 0; - char *s = xstrdup(val); - char **varp = (char **)get_varp_scope(opt, both ? OPT_LOCAL : opt_flags); - - if (opt->flags & P_ALLOCED) { - free_string_option(*varp); - } - *varp = s; - - // For buffer/window local option may also set the global value. - if (both) { - set_string_option_global(opt, varp); - } - - opt->flags |= P_ALLOCED; - - // When setting both values of a global option with a local value, - // make the local value empty, so that the global value is used. - if ((opt->indir & PV_BOTH) && both) { - free_string_option(*varp); - *varp = empty_string_option; - } - if (set_sid != SID_NONE) { - sctx_T script_ctx; - - if (set_sid == 0) { - script_ctx = current_sctx; - } else { - script_ctx.sc_sid = set_sid; - script_ctx.sc_seq = 0; - script_ctx.sc_lnum = 0; - } - set_option_sctx(opt_idx, opt_flags, script_ctx); - } -} - -/// Like set_string_option_direct(), but for a window-local option in "wp". -/// Blocks autocommands to avoid the old curwin becoming invalid. -void set_string_option_direct_in_win(win_T *wp, OptIndex opt_idx, const char *val, int opt_flags, - int set_sid) -{ - win_T *save_curwin = curwin; - - block_autocmds(); - curwin = wp; - curbuf = curwin->w_buffer; - set_string_option_direct(opt_idx, val, opt_flags, set_sid); - curwin = save_curwin; - curbuf = curwin->w_buffer; - unblock_autocmds(); -} - -/// Like set_string_option_direct(), but for a buffer-local option in "buf". -/// Blocks autocommands to avoid the old curwin becoming invalid. -void set_string_option_direct_in_buf(buf_T *buf, OptIndex opt_idx, const char *val, int opt_flags, - int set_sid) -{ - buf_T *save_curbuf = curbuf; - - block_autocmds(); - curbuf = buf; - set_string_option_direct(opt_idx, val, opt_flags, set_sid); - curbuf = save_curbuf; - unblock_autocmds(); -} - /// Return true if "val" is a valid 'filetype' name. /// Also used for 'syntax' and 'keymap'. static bool valid_filetype(const char *val) @@ -2479,9 +2372,8 @@ const char *did_set_virtualedit(optset_T *args) } else if (strcmp(ve, args->os_oldval.string.data) != 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); + validate_virtcol(win); + coladvance(win, win->w_virtcol); } } return NULL; diff --git a/src/nvim/os/env.c b/src/nvim/os/env.c index 5b1cb01976..5a79004c41 100644 --- a/src/nvim/os/env.c +++ b/src/nvim/os/env.c @@ -49,6 +49,7 @@ #endif #ifdef INCLUDE_GENERATED_DECLARATIONS +# include "auto/pathdef.h" # include "os/env.c.generated.h" #endif @@ -473,17 +474,9 @@ void init_homedir(void) var = os_homedir(); } - if (var != NULL) { - // Change to the directory and get the actual path. This resolves - // links. Don't do it when we can't return. - if (os_dirname(os_buf, MAXPATHL) == OK && os_chdir(os_buf) == 0) { - if (!os_chdir(var) && os_dirname(IObuff, IOSIZE) == OK) { - var = IObuff; - } - if (os_chdir(os_buf) != 0) { - emsg(_(e_prev_dir)); - } - } + // Get the actual path. This resolves links. + if (var != NULL && os_realpath(var, IObuff, IOSIZE) != NULL) { + var = IObuff; } // Fall back to current working directory if home is not found @@ -586,9 +579,6 @@ void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool es bool copy_char; bool mustfree; // var was allocated, need to free it later bool at_start = true; // at start of a name -#if defined(BACKSLASH_IN_FILENAME) - char *const save_dst = dst; -#endif int prefix_len = (prefix == NULL) ? 0 : (int)strlen(prefix); @@ -729,7 +719,7 @@ void expand_env_esc(char *restrict srcp, char *restrict dst, int dstlen, bool es // with it, skip a character if (after_pathsep(dst, dst + c) #if defined(BACKSLASH_IN_FILENAME) - && (dst == save_dst || dst[-1] != ':') + && dst[c - 1] != ':' #endif && vim_ispathsep(*tail)) { tail++; @@ -1198,7 +1188,7 @@ bool os_setenv_append_path(const char *fname) const char *tail = path_tail_with_sep((char *)fname); size_t dirlen = (size_t)(tail - fname); assert(tail >= fname && dirlen + 1 < sizeof(os_buf)); - xstrlcpy(os_buf, fname, dirlen + 1); + xmemcpyz(os_buf, fname, dirlen); const char *path = os_getenv("PATH"); const size_t pathlen = path ? strlen(path) : 0; const size_t newlen = pathlen + dirlen + 2; diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index ade745df2c..19bdf30311 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -374,8 +374,8 @@ static bool is_executable_in_path(const char *name, char **abspath) char *e = xstrchrnul(p, ENV_SEPCHAR); // Combine the $PATH segment with `name`. - xstrlcpy(buf, p, (size_t)(e - p) + 1); - append_path(buf, name, buf_len); + xmemcpyz(buf, p, (size_t)(e - p)); + (void)append_path(buf, name, buf_len); #ifdef MSWIN if (is_executable_ext(buf, abspath)) { @@ -789,7 +789,7 @@ void os_copy_xattr(const char *from_file, const char *to_file) // get the length of the extended attributes ssize_t size = listxattr((char *)from_file, NULL, 0); // not supported or no attributes to copy - if (errno == ENOTSUP || size <= 0) { + if (size <= 0) { return; } char *xattr_buf = xmalloc((size_t)size); @@ -1320,22 +1320,22 @@ bool os_fileid_equal_fileinfo(const FileID *file_id, const FileInfo *file_info) /// Return the canonicalized absolute pathname. /// /// @param[in] name Filename to be canonicalized. -/// @param[out] buf Buffer to store the canonicalized values. A minimum length -// of MAXPATHL+1 is required. If it is NULL, memory is -// allocated. In that case, the caller should deallocate this -// buffer. +/// @param[out] buf Buffer to store the canonicalized values. +/// If it is NULL, memory is allocated. In that case, the caller +/// should deallocate this buffer. +/// @param[in] len The length of the buffer. /// /// @return pointer to the buf on success, or NULL. -char *os_realpath(const char *name, char *buf) +char *os_realpath(const char *name, char *buf, size_t len) FUNC_ATTR_NONNULL_ARG(1) { uv_fs_t request; int result = uv_fs_realpath(NULL, &request, name, NULL); if (result == kLibuvSuccess) { if (buf == NULL) { - buf = xmallocz(MAXPATHL); + buf = xmalloc(len); } - xstrlcpy(buf, request.ptr, MAXPATHL + 1); + xstrlcpy(buf, request.ptr, len); } uv_fs_req_cleanup(&request); return result == kLibuvSuccess ? buf : NULL; diff --git a/src/nvim/os/input.c b/src/nvim/os/input.c index fab360c9af..60b5b48745 100644 --- a/src/nvim/os/input.c +++ b/src/nvim/os/input.c @@ -247,6 +247,13 @@ bool os_isatty(int fd) return uv_guess_handle(fd) == UV_TTY; } +void input_enqueue_raw(String keys) +{ + if (keys.size > 0) { + rbuffer_write(input_buffer, keys.data, keys.size); + } +} + size_t input_enqueue(String keys) { const char *ptr = keys.data; @@ -255,9 +262,9 @@ size_t input_enqueue(String keys) while (rbuffer_space(input_buffer) >= 19 && ptr < end) { // A "<x>" form occupies at least 1 characters, and produces up // to 19 characters (1 + 5 * 3 for the char and 3 for a modifier). - // In the case of K_SPECIAL(0x80), 3 bytes are escaped and needed, + // In the case of K_SPECIAL (0x80), 3 bytes are escaped and needed, // but since the keys are UTF-8, so the first byte cannot be - // K_SPECIAL(0x80). + // K_SPECIAL (0x80). uint8_t buf[19] = { 0 }; // Do not simplify the keys here. Simplification will be done later. unsigned new_size @@ -351,8 +358,7 @@ static uint8_t check_multiclick(int code, int grid, int row, int col) return modifiers; } -// Mouse event handling code(Extract row/col if available and detect multiple -// clicks) +/// Mouse event handling code (extract row/col if available and detect multiple clicks) static unsigned handle_mouse_event(const char **ptr, uint8_t *buf, unsigned bufsize) { int mouse_code = 0; diff --git a/src/nvim/os/nvim.manifest b/src/nvim/os/nvim.manifest index 571b7f4580..f6bd20f66b 100644 --- a/src/nvim/os/nvim.manifest +++ b/src/nvim/os/nvim.manifest @@ -18,8 +18,9 @@ </application> </compatibility> <asmv3:application> - <asmv3:windowsSettings xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings"> - <activeCodePage>UTF-8</activeCodePage> + <asmv3:windowsSettings> + <activeCodePage xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">UTF-8</activeCodePage> + <longPathAware xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">true</longPathAware> </asmv3:windowsSettings> </asmv3:application> </assembly> diff --git a/src/nvim/os/shell.c b/src/nvim/os/shell.c index 46ba13c4cd..2a10510b0f 100644 --- a/src/nvim/os/shell.c +++ b/src/nvim/os/shell.c @@ -1117,8 +1117,8 @@ static void out_data_ring(char *output, size_t size) /// Continue to append data to last screen line. /// /// @param output Data to append to screen lines. -/// @param remaining Size of data. -/// @param new_line If true, next data output will be on a new line. +/// @param count Size of data. +/// @param eof If true, there will be no more data output. static void out_data_append_to_screen(char *output, size_t *count, bool eof) FUNC_ATTR_NONNULL_ALL { @@ -1168,8 +1168,7 @@ static void out_data_cb(Stream *stream, RBuffer *buf, size_t count, void *data, rbuffer_consumed(buf, cnt); } - // Move remaining data to start of buffer, so the buffer can never - // wrap around. + // Move remaining data to start of buffer, so the buffer can never wrap around. rbuffer_reset(buf); } diff --git a/src/nvim/os/stdpaths.c b/src/nvim/os/stdpaths.c index ede17bc7c8..e5bdd56fe6 100644 --- a/src/nvim/os/stdpaths.c +++ b/src/nvim/os/stdpaths.c @@ -2,13 +2,16 @@ #include <stdbool.h> #include <string.h> +#include "klib/kvec.h" #include "nvim/ascii_defs.h" #include "nvim/fileio.h" #include "nvim/globals.h" #include "nvim/memory.h" #include "nvim/os/os.h" +#include "nvim/os/os_defs.h" #include "nvim/os/stdpaths_defs.h" #include "nvim/path.h" +#include "nvim/strings.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "os/stdpaths.c.generated.h" @@ -93,6 +96,46 @@ bool appname_is_valid(void) return true; } +/// Remove duplicate directories in the given XDG directory. +/// @param[in] List of directories possibly with duplicates +/// @param[out] List of directories without duplicates +static char *xdg_remove_duplicate(char *ret, const char *sep) +{ + kvec_t(char *) data = KV_INITIAL_VALUE; + char *saveptr; + + char *token = os_strtok(ret, sep, &saveptr); + while (token != NULL) { + // Check if the directory is not already in the list + bool is_duplicate = false; + for (size_t i = 0; i < data.size; i++) { + if (path_fnamecmp(kv_A(data, i), token) == 0) { + is_duplicate = true; + break; + } + } + // If it's not a duplicate, add it to the list + if (!is_duplicate) { + kv_push(data, token); + } + token = os_strtok(NULL, sep, &saveptr); + } + + StringBuilder result = KV_INITIAL_VALUE; + + for (size_t i = 0; i < data.size; i++) { + if (i == 0) { + kv_printf(result, "%s", kv_A(data, i)); + } else { + kv_printf(result, "%s%s", sep, kv_A(data, i)); + } + } + + kv_destroy(data); + xfree(ret); + return result.items; +} + /// Return XDG variable value /// /// @param[in] idx XDG variable to use. @@ -131,6 +174,10 @@ char *stdpaths_get_xdg_var(const XDGVarType idx) ret = xmemdupz(ret, len >= 2 ? len - 1 : 0); // Trim trailing slash. } + if ((idx == kXDGDataDirs || idx == kXDGConfigDirs) && ret != NULL) { + ret = xdg_remove_duplicate(ret, ENV_SEPSTR); + } + return ret; } @@ -151,7 +198,7 @@ char *get_xdg_home(const XDGVarType idx) assert(appname_len < (IOSIZE - sizeof("-data"))); if (dir) { - xstrlcpy(IObuff, appname, appname_len + 1); + xmemcpyz(IObuff, appname, appname_len); #if defined(MSWIN) if (idx == kXDGDataHome || idx == kXDGStateHome) { xstrlcat(IObuff, "-data", IOSIZE); diff --git a/src/nvim/os/users.c b/src/nvim/os/users.c index 8886d6068d..d5a8355470 100644 --- a/src/nvim/os/users.c +++ b/src/nvim/os/users.c @@ -203,7 +203,7 @@ static void init_users(void) os_get_usernames(&ga_users); } -/// Given to ExpandGeneric() to obtain an user names. +/// Given to ExpandGeneric() to obtain user names. char *get_users(expand_T *xp, int idx) { init_users(); diff --git a/src/nvim/path.c b/src/nvim/path.c index 4de18c7530..d782d1a989 100644 --- a/src/nvim/path.c +++ b/src/nvim/path.c @@ -62,8 +62,8 @@ enum { /// @return Enum of type FileComparison. @see FileComparison. FileComparison path_full_compare(char *const s1, char *const s2, const bool checkname, const bool expandenv) + FUNC_ATTR_NONNULL_ALL { - assert(s1 && s2); char exp1[MAXPATHL]; char full1[MAXPATHL]; char full2[MAXPATHL]; @@ -134,9 +134,8 @@ char *path_tail(const char *fname) /// - `fname` if it contains no path separator. /// - Never NULL. char *path_tail_with_sep(char *fname) + FUNC_ATTR_NONNULL_ALL { - assert(fname != NULL); - // Don't remove the '/' from "c:/file". char *past_head = get_past_head(fname); char *tail = path_tail(fname); @@ -181,8 +180,8 @@ const char *invocation_path_tail(const char *invocation, size_t *len) /// @return Pointer to first found path separator + 1. /// An empty string, if `fname` doesn't contain a path separator, const char *path_next_component(const char *fname) + FUNC_ATTR_NONNULL_ALL { - assert(fname != NULL); while (*fname != NUL && !vim_ispathsep(*fname)) { MB_PTR_ADV(fname); } @@ -212,6 +211,7 @@ int path_head_length(void) /// - True if path begins with a path head /// - False otherwise bool is_path_head(const char *path) + FUNC_ATTR_NONNULL_ALL { #ifdef MSWIN return isalpha((uint8_t)path[0]) && path[1] == ':'; @@ -224,6 +224,7 @@ bool is_path_head(const char *path) /// Unix: after "/"; Win: after "c:\" /// If there is no head, path is returned. char *get_past_head(const char *path) + FUNC_ATTR_NONNULL_ALL { const char *retval = path; @@ -281,6 +282,7 @@ bool vim_ispathlistsep(int c) /// Must be 1 or more. /// It's done in-place. void shorten_dir_len(char *str, int trim_len) + FUNC_ATTR_NONNULL_ALL { char *tail = path_tail(str); char *d = str; @@ -317,6 +319,7 @@ void shorten_dir_len(char *str, int trim_len) /// Shorten the path of a file from "~/foo/../.bar/fname" to "~/f/../.b/fname" /// It's done in-place. void shorten_dir(char *str) + FUNC_ATTR_NONNULL_ALL { shorten_dir_len(str, 1); } @@ -325,6 +328,7 @@ void shorten_dir(char *str) /// Also returns true if there is no directory name. /// "fname" must be writable!. bool dir_of_file_exists(char *fname) + FUNC_ATTR_NONNULL_ALL { char *p = path_tail_with_sep(fname); if (p == fname) { @@ -795,6 +799,7 @@ static size_t do_path_expand(garray_T *gap, const char *path, size_t wildoff, in // Moves "*psep" back to the previous path separator in "path". // Returns FAIL is "*psep" ends up at the beginning of "path". static int find_previous_pathsep(char *path, char **psep) + FUNC_ATTR_NONNULL_ALL { // skip the current separator if (*psep > path && vim_ispathsep(**psep)) { @@ -815,6 +820,7 @@ static int find_previous_pathsep(char *path, char **psep) /// Returns true if "maybe_unique" is unique wrt other_paths in "gap". /// "maybe_unique" is the end portion of "((char **)gap->ga_data)[i]". static bool is_unique(char *maybe_unique, garray_T *gap, int i) + FUNC_ATTR_NONNULL_ALL { char **other_paths = gap->ga_data; @@ -844,6 +850,7 @@ static bool is_unique(char *maybe_unique, garray_T *gap, int i) // TODO(vim): handle upward search (;) and path limiter (**N) notations by // expanding each into their equivalent path(s). static void expand_path_option(char *curdir, garray_T *gap) + FUNC_ATTR_NONNULL_ALL { char *path_option = *curbuf->b_p_path == NUL ? p_path : curbuf->b_p_path; char *buf = xmalloc(MAXPATHL); @@ -899,6 +906,7 @@ static void expand_path_option(char *curdir, garray_T *gap) // fname: /foo/bar/baz/quux.txt // returns: ^this static char *get_path_cutoff(char *fname, garray_T *gap) + FUNC_ATTR_NONNULL_ALL { int maxlen = 0; char **path_part = gap->ga_data; @@ -935,6 +943,7 @@ static char *get_path_cutoff(char *fname, garray_T *gap) /// that they are unique with respect to each other while conserving the part /// that matches the pattern. Beware, this is at least O(n^2) wrt "gap->ga_len". static void uniquefy_paths(garray_T *gap, char *pattern) + FUNC_ATTR_NONNULL_ALL { char **fnames = gap->ga_data; bool sort_again = false; @@ -999,7 +1008,7 @@ static void uniquefy_paths(garray_T *gap, char *pattern) memmove(path, path_cutoff, strlen(path_cutoff) + 1); } else { // Here all files can be reached without path, so get shortest - // unique path. We start at the end of the path. */ + // unique path. We start at the end of the path. char *pathsep_p = path + len - 1; while (find_previous_pathsep(path, &pathsep_p)) { if (vim_regexec(®match, pathsep_p + 1, 0) @@ -1115,6 +1124,7 @@ const char *gettail_dir(const char *const fname) /// /// @param flags EW_* flags static int expand_in_path(garray_T *const gap, char *const pattern, const int flags) + FUNC_ATTR_NONNULL_ALL { garray_T path_ga; @@ -1147,6 +1157,7 @@ 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 *p) + FUNC_ATTR_NONNULL_ALL { for (; *p; MB_PTR_ADV(p)) { if (*p == '\\' && p[1] != NUL) { @@ -1163,6 +1174,7 @@ static bool has_env_var(char *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 *p, int flags) + FUNC_ATTR_NONNULL_ALL { for (; *p; MB_PTR_ADV(p)) { // Disallow line break characters. @@ -1356,6 +1368,7 @@ void FreeWild(int count, char **files) /// @return true if we can expand this backtick thing here. static bool vim_backtick(char *p) + FUNC_ATTR_NONNULL_ALL { return *p == '`' && *(p + 1) != NUL && *(p + strlen(p) - 1) == '`'; } @@ -1366,6 +1379,7 @@ static bool vim_backtick(char *p) /// /// @param flags EW_* flags static int expand_backtick(garray_T *gap, char *pat, int flags) + FUNC_ATTR_NONNULL_ALL { char *p; char *buffer; @@ -1419,6 +1433,7 @@ static int expand_backtick(garray_T *gap, char *pat, int flags) /// When 'shellslash' set do it the other way around. /// When the path looks like a URL leave it unmodified. void slash_adjust(char *p) + FUNC_ATTR_NONNULL_ALL { if (path_with_url(p)) { return; @@ -1451,6 +1466,7 @@ void slash_adjust(char *p) /// /// @param f filename void addfile(garray_T *gap, char *f, int flags) + FUNC_ATTR_NONNULL_ALL { bool isdir; FileInfo file_info; @@ -1500,6 +1516,7 @@ void addfile(garray_T *gap, char *f, int flags) // resulting file name is simplified in place and will either be the same // length as that supplied, or shorter. void simplify_filename(char *filename) + FUNC_ATTR_NONNULL_ALL { int components = 0; bool stripping_disabled = false; @@ -1757,6 +1774,7 @@ bool path_has_drive_letter(const char *p) // Also check for ":\\", which MS Internet Explorer accepts, return // URL_BACKSLASH. int path_is_url(const char *p) + FUNC_ATTR_NONNULL_ALL { // In the spec ':' is enough to recognize a scheme // https://url.spec.whatwg.org/#scheme-state @@ -1773,6 +1791,7 @@ int path_is_url(const char *p) /// @param fname is the filename to test /// @return URL_SLASH for "name://", URL_BACKSLASH for "name:\\", zero otherwise. int path_with_url(const char *fname) + FUNC_ATTR_NONNULL_ALL { const char *p; @@ -1802,6 +1821,7 @@ int path_with_url(const char *fname) } bool path_with_extension(const char *path, const char *extension) + FUNC_ATTR_NONNULL_ALL { const char *last_dot = strrchr(path, '.'); if (!last_dot) { @@ -1812,6 +1832,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(const char *name) + FUNC_ATTR_NONNULL_ALL { return path_with_url(name) != 0 || path_is_absolute(name); } @@ -1951,6 +1972,7 @@ void path_fix_case(char *name) /// Takes care of multi-byte characters. /// "b" must point to the start of the file name int after_pathsep(const char *b, const char *p) + FUNC_ATTR_NONNULL_ALL { return p > b && vim_ispathsep(p[-1]) && utf_head_off(b, p - 1) == 0; @@ -2240,6 +2262,7 @@ int expand_wildcards(int num_pat, char **pat, int *num_files, char ***files, int /// @return true if "fname" matches with an entry in 'suffixes'. bool match_suffix(char *fname) + FUNC_ATTR_NONNULL_ALL { #define MAXSUFLEN 30 // maximum length of a file suffix char suf_buf[MAXSUFLEN]; @@ -2272,14 +2295,22 @@ bool match_suffix(char *fname) /// @param directory Directory name, relative to current directory. /// @return `FAIL` for failure, `OK` for success. int path_full_dir_name(char *directory, char *buffer, size_t len) + FUNC_ATTR_NONNULL_ALL { - int SUCCESS = 0; - int retval = OK; - if (strlen(directory) == 0) { return os_dirname(buffer, len); } + if (os_realpath(directory, buffer, len) != NULL) { + return OK; + } + + // Path does not exist (yet). For a full path fail, will use the path as-is. + if (path_is_absolute(directory)) { + return FAIL; + } + // For a relative path use the current directory and append the file name. + char old_dir[MAXPATHL]; // Get current directory name. @@ -2287,38 +2318,17 @@ int path_full_dir_name(char *directory, char *buffer, size_t len) return FAIL; } - // We have to get back to the current dir at the end, check if that works. - if (os_chdir(old_dir) != SUCCESS) { + xstrlcpy(buffer, old_dir, len); + if (append_path(buffer, directory, len) == FAIL) { return FAIL; } - if (os_chdir(directory) != SUCCESS) { - // 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(directory)) { - // Do not return immediately since we may be in the wrong directory. - retval = FAIL; - } else { - xstrlcpy(buffer, old_dir, len); - append_path(buffer, directory, len); - } - } else if (os_dirname(buffer, len) == FAIL) { - // Do not return immediately since we are in the wrong directory. - retval = FAIL; - } - - if (os_chdir(old_dir) != SUCCESS) { - // That shouldn't happen, since we've tested if it works. - retval = FAIL; - emsg(_(e_prev_dir)); - } - - return retval; + return OK; } // Append to_append to path with a slash in between. int append_path(char *path, const char *to_append, size_t max_len) + FUNC_ATTR_NONNULL_ALL { size_t current_length = strlen(path); size_t to_append_length = strlen(to_append); @@ -2358,6 +2368,7 @@ int append_path(char *path, const char *to_append, size_t max_len) /// /// @return FAIL for failure, OK for success. static int path_to_absolute(const char *fname, char *buf, size_t len, int force) + FUNC_ATTR_NONNULL_ALL { const char *p; *buf = NUL; @@ -2395,6 +2406,7 @@ static int path_to_absolute(const char *fname, char *buf, size_t len, int force) /// /// @return `true` if "fname" is absolute. bool path_is_absolute(const char *fname) + FUNC_ATTR_NONNULL_ALL { #ifdef MSWIN if (*fname == NUL) { @@ -2443,7 +2455,7 @@ void path_guess_exepath(const char *argv0, char *buf, size_t bufsize) if (dir_len + 1 > sizeof(NameBuff)) { continue; } - xstrlcpy(NameBuff, dir, dir_len + 1); + xmemcpyz(NameBuff, dir, dir_len); xstrlcat(NameBuff, PATHSEPSTR, sizeof(NameBuff)); xstrlcat(NameBuff, argv0, sizeof(NameBuff)); if (os_can_exe(NameBuff, NULL, false)) { diff --git a/src/nvim/plines.c b/src/nvim/plines.c index eca07f0144..5881d34c48 100644 --- a/src/nvim/plines.c +++ b/src/nvim/plines.c @@ -44,6 +44,8 @@ /// @param col /// /// @return Number of cells. +/// +/// @see charsize_nowrap() int win_chartabsize(win_T *wp, char *p, colnr_T col) { buf_T *buf = wp->w_buffer; @@ -55,7 +57,7 @@ int win_chartabsize(win_T *wp, char *p, colnr_T col) /// Like linetabsize_str(), but "s" starts at virtual column "startvcol". /// -/// @param startcol +/// @param startvcol /// @param s /// /// @return Number of cells the string will take on the screen. @@ -74,7 +76,7 @@ int linetabsize_col(int startvcol, char *s) /// screen, taking into account the size of a tab and inline virtual text. int linetabsize(win_T *wp, linenr_T lnum) { - return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum), (colnr_T)MAXCOL); + return win_linetabsize(wp, lnum, ml_get_buf(wp->w_buffer, lnum), MAXCOL); } static const uint32_t inline_filter[4] = {[kMTMetaInline] = kMTFilterSelect }; @@ -234,7 +236,7 @@ CharSize charsize_regular(CharsizeArg *csarg, char *const cur, colnr_T const vco wcol += col_off_prev; } - if (wcol + size > wp->w_width) { + if (wcol + size > wp->w_width_inner) { // cells taken by 'showbreak'/'breakindent' halfway current char int head_mid = csarg->indent_width; if (head_mid == INT_MIN) { @@ -247,7 +249,7 @@ CharSize charsize_regular(CharsizeArg *csarg, char *const cur, colnr_T const vco } csarg->indent_width = head_mid; } - if (head_mid > 0 && wcol + size > wp->w_width_inner) { + if (head_mid > 0) { // Calculate effective window width. int prev_rem = wp->w_width_inner - wcol; int width = width2 - head_mid; @@ -375,6 +377,20 @@ CharSize charsize_fast(CharsizeArg *csarg, colnr_T const vcol, int32_t const cur return charsize_fast_impl(csarg->win, csarg->use_tabstop, vcol, cur_char); } +/// Get the number of cells taken up on the screen at given virtual column. +/// +/// @see win_chartabsize() +int charsize_nowrap(buf_T *buf, bool use_tabstop, colnr_T vcol, int32_t cur_char) +{ + if (cur_char == TAB && use_tabstop) { + return tabstop_padding(vcol, buf->b_p_ts, buf->b_p_vts_array); + } else if (cur_char < 0) { + return kInvalidByteCells; + } else { + return char2cells(cur_char); + } +} + /// Check that virtual column "vcol" is in the rightmost column of window "wp". /// /// @param wp window @@ -405,48 +421,63 @@ static bool in_win_border(win_T *wp, colnr_T vcol) /// Calculate virtual column until the given "len". /// -/// @param arg Argument to charsize functions. -/// @param vcol Starting virtual column. -/// @param len First byte of the end character, or MAXCOL. +/// @param csarg Argument to charsize functions. +/// @param vcol_arg Starting virtual column. +/// @param len First byte of the end character, or MAXCOL. /// /// @return virtual column before the character at "len", -/// or full size of the line if "len" is MAXCOL. -int linesize_regular(CharsizeArg *const csarg, int vcol, colnr_T const len) +/// or full size of the line if "len" is MAXCOL. +int linesize_regular(CharsizeArg *const csarg, int vcol_arg, colnr_T const len) { char *const line = csarg->line; + int64_t vcol = vcol_arg; StrCharInfo ci = utf_ptr2StrCharInfo(line); while (ci.ptr - line < len && *ci.ptr != NUL) { - vcol += charsize_regular(csarg, ci.ptr, vcol, ci.chr.value).width; + vcol += charsize_regular(csarg, ci.ptr, vcol_arg, ci.chr.value).width; ci = utfc_next(ci); + if (vcol > MAXCOL) { + vcol_arg = MAXCOL; + break; + } else { + vcol_arg = (int)vcol; + } } // Check for inline virtual text after the end of the line. - if (len == MAXCOL && csarg->virt_row >= 0) { - (void)charsize_regular(csarg, ci.ptr, vcol, ci.chr.value); + if (len == MAXCOL && csarg->virt_row >= 0 && *ci.ptr == NUL) { + (void)charsize_regular(csarg, ci.ptr, vcol_arg, ci.chr.value); vcol += csarg->cur_text_width_left + csarg->cur_text_width_right; + vcol_arg = vcol > MAXCOL ? MAXCOL : (int)vcol; } - return vcol; + return vcol_arg; } -/// Like linesize_regular(), but can be used when CStype is kCharsizeFast. +/// Like linesize_regular(), but can be used when CSType is kCharsizeFast. /// /// @see linesize_regular -int linesize_fast(CharsizeArg const *const csarg, int vcol, colnr_T const len) +int linesize_fast(CharsizeArg const *const csarg, int vcol_arg, colnr_T const len) { win_T *const wp = csarg->win; bool const use_tabstop = csarg->use_tabstop; char *const line = csarg->line; + int64_t vcol = vcol_arg; StrCharInfo ci = utf_ptr2StrCharInfo(line); while (ci.ptr - line < len && *ci.ptr != NUL) { - vcol += charsize_fast_impl(wp, use_tabstop, vcol, ci.chr.value).width; + vcol += charsize_fast_impl(wp, use_tabstop, vcol_arg, ci.chr.value).width; ci = utfc_next(ci); + if (vcol > MAXCOL) { + vcol_arg = MAXCOL; + break; + } else { + vcol_arg = (int)vcol; + } } - return vcol; + return vcol_arg; } /// Get how many virtual columns inline virtual text should offset the cursor. @@ -540,7 +571,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en if (ci.chr.value == TAB && (State & MODE_NORMAL) && !wp->w_p_list - && !virtual_active() + && !virtual_active(wp) && !(VIsual_active && ((*p_sel == 'e') || ltoreq(*pos, VIsual)))) { // cursor at end *cursor = vcol + incr - 1; @@ -556,7 +587,7 @@ void getvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *en /// /// @param posp /// -/// @retujrn The virtual cursor column. +/// @return The virtual cursor column. colnr_T getvcol_nolist(pos_T *posp) { int list_save = curwin->w_p_list; @@ -583,7 +614,7 @@ void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *e { colnr_T col; - if (virtual_active()) { + if (virtual_active(wp)) { // For virtual mode, only want one value getvcol(wp, pos, &col, NULL, NULL); @@ -593,7 +624,7 @@ void getvvcol(win_T *wp, pos_T *pos, colnr_T *start, colnr_T *cursor, colnr_T *e // Cannot put the cursor on part of a wide character. char *ptr = ml_get_buf(wp->w_buffer, pos->lnum); - if (pos->col < (colnr_T)strlen(ptr)) { + if (pos->col < ml_get_buf_len(wp->w_buffer, pos->lnum)) { int c = utf_ptr2char(ptr + pos->col); if ((c != TAB) && vim_isprintc(c)) { endadd = (colnr_T)(char2cells(c) - 1); @@ -850,26 +881,29 @@ int plines_win_full(win_T *wp, linenr_T lnum, linenr_T *const nextp, bool *const (lnum == wp->w_topline ? wp->w_topfill : win_get_fill(wp, lnum))); } -/// Get the number of screen lines a range of buffer lines will take in window "wp". -/// This takes care of both folds and topfill. +/// Return number of window lines a physical line range will occupy in window "wp". +/// Takes into account folding, 'wrap', topfill and filler lines beyond the end of the buffer. /// /// XXX: Because of topfill, this only makes sense when first >= wp->w_topline. /// -/// @param first first line number -/// @param last last line number -/// @param limit_winheight when true limit each line to window height +/// @param first first line number +/// @param last last line number +/// @param max number of lines to limit the height to /// /// @see win_text_height -int plines_m_win(win_T *wp, linenr_T first, linenr_T last, bool limit_winheight) +int plines_m_win(win_T *wp, linenr_T first, linenr_T last, int max) { int count = 0; - while (first <= last) { + while (first <= last && count < max) { linenr_T next = first; - count += plines_win_full(wp, first, &next, NULL, false, limit_winheight); + count += plines_win_full(wp, first, &next, NULL, false, false); first = next + 1; } - return count; + if (first == wp->w_buffer->b_ml.ml_line_count + 1) { + count += win_get_fill(wp, first); + } + return MIN(max, count); } /// Get the number of screen lines a range of text will take in window "wp". @@ -902,7 +936,7 @@ int64_t win_text_height(win_T *const wp, const linenr_T start_lnum, const int64_ if (start_vcol >= 0) { linenr_T lnum_next = lnum; - const bool folded = hasFoldingWin(wp, lnum, &lnum, &lnum_next, true, NULL); + const bool folded = hasFolding(wp, lnum, &lnum, &lnum_next); height_cur_nofill = folded ? 1 : plines_win_nofill(wp, lnum, false); height_sum_nofill += height_cur_nofill; const int64_t row_off = (start_vcol < width1 || width2 <= 0) @@ -914,7 +948,7 @@ int64_t win_text_height(win_T *const wp, const linenr_T start_lnum, const int64_ while (lnum <= end_lnum) { linenr_T lnum_next = lnum; - const bool folded = hasFoldingWin(wp, lnum, &lnum, &lnum_next, true, NULL); + const bool folded = hasFolding(wp, lnum, &lnum, &lnum_next); height_sum_fill += win_get_fill(wp, lnum); height_cur_nofill = folded ? 1 : plines_win_nofill(wp, lnum, false); height_sum_nofill += height_cur_nofill; diff --git a/src/nvim/po/ja.po b/src/nvim/po/ja.po index bdf67933f3..315c860307 100644 --- a/src/nvim/po/ja.po +++ b/src/nvim/po/ja.po @@ -1,9 +1,9 @@ -# Japanese translation for Vim +# Japanese translation for Neovim # # Do ":help uganda" in Vim to read copying and usage conditions. # Do ":help credits" in Vim to see a list of people who contributed. # -# Copyright (C) 2001-2018 MURAOKA Taro <koron.kaoriya@gmail.com>, +# Copyright (C) 2001-2023 MURAOKA Taro <koron.kaoriya@gmail.com>, # vim-jp <http://vim-jp.org/> # # THIS FILE IS DISTRIBUTED UNDER THE VIM LICENSE. @@ -12,11 +12,11 @@ # msgid "" msgstr "" -"Project-Id-Version: Vim 8.1\n" +"Project-Id-Version: Neovim 0.10\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2018-07-18 00:43+0900\n" -"PO-Revision-Date: 2017-05-18 00:45+0900\n" -"Last-Translator: MURAOKA Taro <koron.kaoriya@gmail.com>\n" +"POT-Creation-Date: 2024-03-14 19:01+0900\n" +"PO-Revision-Date: 2024-03-14 19:46+0900\n" +"Last-Translator: ite-usagi <https://github.com/ite-usagi>\n" "Language-Team: Japanese <https://github.com/vim-jp/lang-ja>\n" "Language: ja\n" "MIME-Version: 1.0\n" @@ -24,43 +24,1311 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -msgid "E831: bf_key_init() called with empty password" -msgstr "E831: bf_key_init() が空パスワードで呼び出されました" +msgid "(local to window)" +msgstr "(ウィンドウについてローカル)" -msgid "E820: sizeof(uint32_t) != 4" -msgstr "E820: sizeof(uint32_t) != 4" +msgid "(local to buffer)" +msgstr "(バッファについてローカル)" -msgid "E817: Blowfish big/little endian use wrong" -msgstr "E817: Blowfish暗号のビッグ/リトルエンディアンが間違っています" +msgid "(global or local to buffer)" +msgstr "(グローバル/バッファについてローカル)" -msgid "E818: sha256 test failed" -msgstr "E818: sha256のテストに失敗しました" +msgid "" +"\" Each \"set\" line shows the current value of an option (on the left)." +msgstr "\" それぞれの \"set\" 行はオプションの現在の値を(左側に)示しています。" -msgid "E819: Blowfish test failed" -msgstr "E819: Blowfish暗号のテストに失敗しました" +msgid "\" Hit <Enter> on a \"set\" line to execute it." +msgstr "\" \"set\" 行で <Enter> を打つとそれが実行されます。" -msgid "[Location List]" -msgstr "[ロケーションリスト]" +msgid "\" A boolean option will be toggled." +msgstr "\" 切替オプションは切り替えられます。" -msgid "[Quickfix List]" -msgstr "[Quickfixリスト]" +msgid "" +"\" For other options you can edit the value before hitting " +"<Enter>." +msgstr "" +"\" その他のオプションは <Enter> を打つ前に値を編集することができま" +"す。" -msgid "E855: Autocommands caused command to abort" -msgstr "E855: autocommandがコマンドの停止を引き起こしました" +msgid "\" Hit <Enter> on a help line to open a help window on this option." +msgstr "" +"\" ヘルプ行で <Enter> を打つと、このオプションのへルプウィンドウが開きます。" -msgid "E82: Cannot allocate any buffer, exiting..." -msgstr "E82: バッファを1つも作成できないので、終了します..." +msgid "\" Hit <Enter> on an index line to jump there." +msgstr "\" インデックス行で <Enter> を打つと、そこにジャンプします。" -msgid "E83: Cannot allocate buffer, using other one..." -msgstr "E83: バッファを作成できないので、他のを使用します..." +msgid "\" Hit <Space> on a \"set\" line to refresh it." +msgstr "\" \"set\" 行で <Spece> を打つと、最新の値が読込まれます。" + +msgid "important" +msgstr "重要" + +msgid "behave very Vi compatible (not advisable)" +msgstr "Vi との互換性を非常に高くする (望ましくない)" + +msgid "list of flags to specify Vi compatibility" +msgstr "Vi との互換性を指定するフラグのリスト" + +msgid "paste mode, insert typed text literally" +msgstr "paste モード、タイプされたテキストをそのまま挿入する" + +msgid "list of directories used for runtime files and plugins" +msgstr "ランタイムファイルとプラグインに使われるディレクトリのリスト" + +msgid "list of directories used for plugin packages" +msgstr "プラグインパッケージに使われるディレクトリのリスト" + +msgid "name of the main help file" +msgstr "メインのヘルプファイルの名前" + +msgid "moving around, searching and patterns" +msgstr "移動、検索とパターン" + +msgid "list of flags specifying which commands wrap to another line" +msgstr "どのコマンドが行をまたぐかを指定するフラグのリスト" + +msgid "" +"many jump commands move the cursor to the first non-blank\n" +"character of a line" +msgstr "多くのジャンプ命令で、カーソルが行内の最初の非空白文字に移動する" + +msgid "nroff macro names that separate paragraphs" +msgstr "段落を分けるための nroff マクロの名前" + +msgid "nroff macro names that separate sections" +msgstr "章を分けるための nroff マクロの名前" + +msgid "list of directory names used for file searching" +msgstr "ファイルの検索に用いられるディレクトリ名のリスト" + +msgid ":cd without argument goes to the home directory" +msgstr "引数無しの :cd でホームディレクトリに移動する" + +msgid "list of directory names used for :cd" +msgstr ":cd に用いられるディレクトリ名のリスト" + +msgid "change to directory of file in buffer" +msgstr "バッファ内のファイルのディレクトリに変更する" + +msgid "search commands wrap around the end of the buffer" +msgstr "検索コマンドがバッファの末尾/先頭をまたぐ" + +msgid "show match for partly typed search command" +msgstr "部分的に入力された検索コマンドのマッチを表示する" + +msgid "change the way backslashes are used in search patterns" +msgstr "検索パターン内のバックスラッシュの扱いを変更する" + +msgid "select the default regexp engine used" +msgstr "既定で使われる正規表現エンジンを選択する" + +msgid "ignore case when using a search pattern" +msgstr "検索パターンにおいて大文字と小文字を区別しない" + +msgid "override 'ignorecase' when pattern has upper case characters" +msgstr "検索パターンが大文字を含んでいたら 'ignorecase' を上書きする" + +msgid "what method to use for changing case of letters" +msgstr "大文字・小文字を変更する際にどの方法を使うか" + +msgid "maximum amount of memory in Kbyte used for pattern matching" +msgstr "パターンマッチングに使う最大メモリ量 (Kbyte)" + +msgid "pattern for a macro definition line" +msgstr "マクロ定義行のためのパターン" + +msgid "pattern for an include-file line" +msgstr "include 行のためのパターン" + +msgid "expression used to transform an include line to a file name" +msgstr "include 行をファイル名に変換するために使われる式" + +msgid "tags" +msgstr "タグ" + +msgid "use binary searching in tags files" +msgstr "tags ファイル内で二分探索を使う" + +msgid "number of significant characters in a tag name or zero" +msgstr "タグ名で有効になる文字数、あるいはゼロ" + +msgid "list of file names to search for tags" +msgstr "tags を検索するファイル名のリスト" + +msgid "" +"how to handle case when searching in tags files:\n" +"\"followic\" to follow 'ignorecase', \"ignore\" or \"match\"" +msgstr "" +"タグファイル内を検索するときに大文字小文字をどう扱うか:\n" +"'ignorecase' に従うなら \"followic\"、あるいは \"ignore\" か \"match\"" + +msgid "file names in a tags file are relative to the tags file" +msgstr "tags ファイル内のファイル名は tags ファイルからの相対パス" + +msgid "a :tag command will use the tagstack" +msgstr ":tag コマンドはタグスタックを使う" + +msgid "when completing tags in Insert mode show more info" +msgstr "挿入モードでタグを補完するときにより多くの情報を表示する" + +msgid "a function to be used to perform tag searches" +msgstr "タグの検索を実行する際に使われる関数" + +msgid "displaying text" +msgstr "テキストの表示" + +msgid "number of lines to scroll for CTRL-U and CTRL-D" +msgstr "CTRL-U と CTRL-D でスクロールする行数" + +msgid "scroll by screen line" +msgstr "スクリーン行でスクロールする" + +msgid "number of screen lines to show around the cursor" +msgstr "カーソルの上下に表示されるスクリーン行数" + +msgid "long lines wrap" +msgstr "長い行を折り返して表示する" + +msgid "wrap long lines at a character in 'breakat'" +msgstr "'breakat' の文字で長い行を折り返す" + +msgid "preserve indentation in wrapped text" +msgstr "折り返されたテキストでインデントを保持する" + +msgid "adjust breakindent behaviour" +msgstr "breakindent の挙動を調整する" + +msgid "which characters might cause a line break" +msgstr "どの文字のところで行が折り返されるか" + +msgid "string to put before wrapped screen lines" +msgstr "折り返されたスクリーン行の前に表示される文字列" + +msgid "minimal number of columns to scroll horizontally" +msgstr "水平スクロールの最小桁数" + +msgid "minimal number of columns to keep left and right of the cursor" +msgstr "カーソルの左右に表示する最小桁数" + +msgid "" +"include \"lastline\" to show the last line even if it doesn't fit\n" +"include \"uhex\" to show unprintable characters as a hex number" +msgstr "" +"最後の行が収まらない場合でも表示するには \"lastline\" を含めること\n" +"表示できない文字を 16 進数で表示するには \"uhex\" を含めること" + +msgid "characters to use for the status line, folds and filler lines" +msgstr "ステータス行、折畳み、フィラー行に使われる文字" + +msgid "number of lines used for the command-line" +msgstr "コマンドラインに使われる行数" + +msgid "width of the display" +msgstr "画面の幅" + +msgid "number of lines in the display" +msgstr "画面の行数" + +msgid "number of lines to scroll for CTRL-F and CTRL-B" +msgstr "CTRL-F と CTRL-B でスクロールする行数" + +msgid "don't redraw while executing macros" +msgstr "マクロを実行中に再描画しない" + +msgid "timeout for 'hlsearch' and :match highlighting in msec" +msgstr "'hlsearch' と :match のハイライト処理のタイムアウト (ミリ秒)" + +msgid "" +"delay in msec for each char written to the display\n" +"(for debugging)" +msgstr "" +"それぞれの文字が画面に描かれるまでの遅延時間 (ミリ秒)\n" +"(デバッグ用)" + +msgid "show <Tab> as ^I and end-of-line as $" +msgstr "<Tab> を ^I として表示し、改行を $ として表示する" + +msgid "list of strings used for list mode" +msgstr "リストモードで使われる文字列のリスト" + +msgid "show the line number for each line" +msgstr "それぞれの行に行番号を表示する" + +msgid "show the relative line number for each line" +msgstr "それぞれの行に相対行番号を表示する" + +msgid "number of columns to use for the line number" +msgstr "行番号に使われる桁数" + +msgid "controls whether concealable text is hidden" +msgstr "conceal 可能なテキストを隠すかどうかを制御する" + +msgid "modes in which text in the cursor line can be concealed" +msgstr "カーソル行のテキストを conceal 表示するモード" + +msgid "syntax, highlighting and spelling" +msgstr "構文ハイライトとスペルチェック" + +msgid "\"dark\" or \"light\"; the background color brightness" +msgstr "\"dark\" か \"light\"; 背景色の明るさ" + +msgid "type of file; triggers the FileType event when set" +msgstr "ファイルのタイプ; セットされると FileType イベントが発生する" + +msgid "name of syntax highlighting used" +msgstr "使用される構文ハイライトの名前" + +msgid "maximum column to look for syntax items" +msgstr "構文アイテムを検索する最大桁数" + +msgid "which highlighting to use for various occasions" +msgstr "様々な対象に対してどのハイライト表示を使うか" + +msgid "highlight all matches for the last used search pattern" +msgstr "最後の検索パターンに対する全てのマッチをハイライト表示する" + +msgid "use GUI colors for the terminal" +msgstr "端末で GUI カラーを使う" + +msgid "highlight the screen column of the cursor" +msgstr "カーソルのある画面上の桁をハイライト表示する" + +msgid "highlight the screen line of the cursor" +msgstr "カーソルのある画面上の行をハイライト表示する" + +msgid "specifies which area 'cursorline' highlights" +msgstr "'cursorline' がどの領域をハイライト表示するか指定する" + +msgid "columns to highlight" +msgstr "ハイライト表示する桁" + +msgid "highlight spelling mistakes" +msgstr "スペルミスをハイライト表示する" + +msgid "list of accepted languages" +msgstr "受け付ける言語のリスト" + +msgid "file that \"zg\" adds good words to" +msgstr "\"zg\" で正しい単語を追加するファイル" + +msgid "pattern to locate the end of a sentence" +msgstr "文の末尾を見つけるのに使うパターン" + +msgid "flags to change how spell checking works" +msgstr "どのようにスペルチェックが動作するかを変更するフラグ" + +msgid "methods used to suggest corrections" +msgstr "修正を提案する際に使われる方法" + +msgid "amount of memory used by :mkspell before compressing" +msgstr "圧縮の前に :mkspell で使われるメモリ量" + +msgid "multiple windows" +msgstr "複数ウィンドウ" + +msgid "0, 1, 2 or 3; when to use a status line for the last window" +msgstr "0, 1, 2 または 3; 最後のウィンドウのステータス行がいつ使われるか" + +msgid "custom format for the status column" +msgstr "ステータス列に使われる書式" + +msgid "alternate format to be used for a status line" +msgstr "ステータス行に使われる書式" + +msgid "make all windows the same size when adding/removing windows" +msgstr "ウィンドウを追加/削除するときに全ウィンドウのサイズを等しくする" + +msgid "in which direction 'equalalways' works: \"ver\", \"hor\" or \"both\"" +msgstr "どの方向に 'equalalways' が働くか: \"ver\", \"hor\" または \"both\"" + +msgid "minimal number of lines used for the current window" +msgstr "現在のウィンドウに使われる最小行数" + +msgid "minimal number of lines used for any window" +msgstr "任意のウィンドウに使われる最小行数" + +msgid "keep window focused on a single buffer" +msgstr "ウィンドウを単一のバッファにフォーカスする" + +msgid "keep the height of the window" +msgstr "ウィンドウの高さを保つ" + +msgid "keep the width of the window" +msgstr "ウィンドウの幅を保つ" + +msgid "minimal number of columns used for the current window" +msgstr "現在のウィンドウに使われる最小桁数" + +msgid "minimal number of columns used for any window" +msgstr "任意のウィンドウに使われる最小桁数" + +msgid "initial height of the help window" +msgstr "ヘルプウィンドウの開始時の高さ" + +msgid "default height for the preview window" +msgstr "プレビューウィンドウの既定の高さ" + +msgid "identifies the preview window" +msgstr "プレビューウィンドウを識別する" + +msgid "don't unload a buffer when no longer shown in a window" +msgstr "バッファがウィンドウに表示されていないときにアンロードしない" + +msgid "" +"\"useopen\" and/or \"split\"; which window to use when jumping\n" +"to a buffer" +msgstr "" +"\"useopen\" かつ/または \"split\"; バッファにジャンプするときに\n" +"どのウィンドウを使うか" + +msgid "a new window is put below the current one" +msgstr "新しいウィンドウは現在のものの下に置かれる" + +msgid "determines scroll behavior for split windows" +msgstr "ウィンドウ分割のスクロール動作を決める" + +msgid "a new window is put right of the current one" +msgstr "新しいウィンドウは現在のものの右に置かれる" + +msgid "this window scrolls together with other bound windows" +msgstr "このウィンドウは他の同調ウィンドウと一緒にスクロールする" + +msgid "\"ver\", \"hor\" and/or \"jump\"; list of options for 'scrollbind'" +msgstr "" +"\"ver\", \"hor\" かつ/または \"jump\"; 'scrollbind' のオプションの\n" +"リスト" + +msgid "this window's cursor moves together with other bound windows" +msgstr "このウィンドウのカーソルは他の同調ウィンドウと一緒に動く" + +msgid "size of a terminal window" +msgstr "端末ウィンドウのサイズ" + +msgid "key that precedes Vim commands in a terminal window" +msgstr "端末ウィンドウで Vim のコマンドの前に入力するキー" + +msgid "multiple tab pages" +msgstr "複数タブページ" + +msgid "0, 1 or 2; when to use a tab pages line" +msgstr "0, 1 または 2; タブページ行をいつ使うか" + +msgid "maximum number of tab pages to open for -p and \"tab all\"" +msgstr "-p と \"tab all\" で開かれるタブページの最大数" + +msgid "custom tab pages line" +msgstr "カスタムのタブページ行" + +msgid "custom tab page label for the GUI" +msgstr "カスタムの GUI のタブページラベル" + +msgid "custom tab page tooltip for the GUI" +msgstr "カスタムの GUI のタブページツールチップ" + +msgid "terminal" +msgstr "端末" + +msgid "minimal number of lines to scroll at a time" +msgstr "一度にスクロールする最小行数" + +msgid "specifies what the cursor looks like in different modes" +msgstr "それぞれのモード内でのカーソルの外観を指定" + +msgid "show info in the window title" +msgstr "ウィンドウタイトルに情報を表示" + +msgid "percentage of 'columns' used for the window title" +msgstr "ウィンドウタイトルに使われる 'columns' の割合 (パーセント単位)" + +msgid "when not empty, string to be used for the window title" +msgstr "空でないとき、ウィンドウタイトルに使われる文字列" + +msgid "string to restore the title to when exiting Vim" +msgstr "Vim の終了時にタイトルに復元する文字列" + +msgid "set the text of the icon for this window" +msgstr "このウィンドウのアイコンのテキストを設定" + +msgid "when not empty, text for the icon of this window" +msgstr "空でないとき、このウィンドウのアイコンに使われるテキスト" + +msgid "using the mouse" +msgstr "マウスの使用" + +msgid "list of flags for using the mouse" +msgstr "マウスを使うためのフラグのリスト" + +msgid "the window with the mouse pointer becomes the current one" +msgstr "マウスポインタのあるウィンドウがアクティブになる" + +msgid "hide the mouse pointer while typing" +msgstr "文字の入力中にマウスポインタを隠す" + +msgid "" +"\"extend\", \"popup\" or \"popup_setpos\"; what the right\n" +"mouse button is used for" +msgstr "" +"\"extend\", \"popup\" あるいは \"popup_setpos\"; マウスの右ボタンを\n" +"何に使うか" + +msgid "maximum time in msec to recognize a double-click" +msgstr "ダブルクリックとして認識する最大時間 (ミリ秒)" + +msgid "what the mouse pointer looks like in different modes" +msgstr "それぞれのモード内でのマウスポインタの外観を指定" + +msgid "GUI" +msgstr "GUI" + +msgid "list of font names to be used in the GUI" +msgstr "GUI で使われるフォント名のリスト" + +msgid "pair of fonts to be used, for multibyte editing" +msgstr "マルチバイトの編集で使われるフォントのペア" + +msgid "list of font names to be used for double-wide characters" +msgstr "全角文字に使われるフォント名のリスト" + +msgid "list of flags that specify how the GUI works" +msgstr "GUI がどう動くかを指定するフラグのリスト" + +msgid "\"icons\", \"text\" and/or \"tooltips\"; how to show the toolbar" +msgstr "" +"\"icons\", \"text\" かつ/あるいは \"tooltips\"; どのように\n" +"ツールバーを表示するか" + +msgid "size of toolbar icons" +msgstr "ツールバーアイコンのサイズ" + +msgid "" +"\"last\", \"buffer\" or \"current\": which directory used for the file " +"browser" +msgstr "" +"\"last\", \"buffer\" あるいは \"current\": ファイルブラウザでどの\n" +"ディレクトリを使うか" + +msgid "language to be used for the menus" +msgstr "メニューで使われる言語" + +msgid "maximum number of items in one menu" +msgstr "1 個のメニューの最大項目数" + +msgid "\"no\", \"yes\" or \"menu\"; how to use the ALT key" +msgstr "\"no\", \"yes\" または \"menu\"; ALT キーをどう使うか" + +msgid "number of pixel lines to use between characters" +msgstr "行間の幅のピクセル数" + +msgid "delay in milliseconds before a balloon may pop up" +msgstr "バルーン表示が出るまでの時間 (ミリ秒)" + +msgid "use balloon evaluation in the GUI" +msgstr "GUI でバルーン評価を使う" + +msgid "use balloon evaluation in the terminal" +msgstr "端末でバルーン評価を使う" + +msgid "expression to show in balloon eval" +msgstr "バルーン評価に表示する式" + +msgid "messages and info" +msgstr "メッセージと情報" + +msgid "add 's' flag in 'shortmess' (don't show search message)" +msgstr "'s' フラグを 'shortmess' に追加 (検索メッセージを表示しない)" + +msgid "list of flags to make messages shorter" +msgstr "メッセージを短くするためのフラグのリスト" + +msgid "show (partial) command keys in location given by 'showcmdloc'" +msgstr "コマンド (の一部) を 'showcmdloc' で指定された場所に表示" + +msgid "location where to show the (partial) command keys for 'showcmd'" +msgstr "'showcmd' でコマンド (の一部) を表示する場所" + +msgid "display the current mode in the status line" +msgstr "現在のモードをステータス行に表示" + +msgid "show cursor position below each window" +msgstr "カーソル位置をそれぞれのウィンドウの下に表示" + +msgid "alternate format to be used for the ruler" +msgstr "ルーラーに使われる代替書式" + +msgid "threshold for reporting number of changed lines" +msgstr "変更された行の数の報告が出る閾値" + +msgid "the higher the more messages are given" +msgstr "値が大きいほど詳細なメッセージが表示される" + +msgid "file to write messages in" +msgstr "メッセージを書込むファイル" + +msgid "pause listings when the screen is full" +msgstr "画面が一杯になったとき一覧表示を一時停止" + +msgid "start a dialog when a command fails" +msgstr "コマンドが失敗したときにダイアログを開く" + +msgid "ring the bell for error messages" +msgstr "エラーメッセージでベルを鳴らす" + +msgid "use a visual bell instead of beeping" +msgstr "ビープ音の代わりにビジュアルベルを使う" + +msgid "do not ring the bell for these reasons" +msgstr "これらの理由にはベルを鳴らさない" + +msgid "list of preferred languages for finding help" +msgstr "ヘルプを見つける際の望ましい言語のリスト" + +msgid "selecting text" +msgstr "テキスト選択" + +msgid "\"old\", \"inclusive\" or \"exclusive\"; how selecting text behaves" +msgstr "" +"\"old\", \"inclusive\" または \"exclusive\"; テキスト選択がどう振舞うか" + +msgid "" +"\"mouse\", \"key\" and/or \"cmd\"; when to start Select mode\n" +"instead of Visual mode" +msgstr "" +"\"mouse\", \"key\" かつ/または \"cmd\"; いつビジュアルモードでは\n" +"なく選択モードを開始するか" + +msgid "" +"\"unnamed\" to use the * register like unnamed register\n" +"\"autoselect\" to always put selected text on the clipboard" +msgstr "" +"\"unnamed\"; * レジスタを無名レジスタと同じように使う\n" +"\"autoselect\"; 常に選択されたテキストをクリップボードにコピー" + +msgid "\"startsel\" and/or \"stopsel\"; what special keys can do" +msgstr "\"startsel\" かつ/または \"stopsel\"; 特別なキーが何をするか" + +msgid "editing text" +msgstr "テキスト編集" + +msgid "maximum number of changes that can be undone" +msgstr "アンドゥ可能な変更の最大値" + +msgid "automatically save and restore undo history" +msgstr "アンドゥ履歴を自動で保存・復元" + +msgid "list of directories for undo files" +msgstr "アンドゥファイル用のディレクトリのリスト" + +msgid "maximum number lines to save for undo on a buffer reload" +msgstr "バッファのリロード時にアンドゥのために保存する最大行数" + +msgid "changes have been made and not written to a file" +msgstr "変更が行われたがファイルに書込まれていない" + +msgid "buffer is not to be written" +msgstr "バッファは書込まれない" + +msgid "changes to the text are possible" +msgstr "テキストの変更が可能" + +msgid "line length above which to break a line" +msgstr "これより長い行は改行される" + +msgid "margin from the right in which to break a line" +msgstr "改行する際の右からのマージン" + +msgid "specifies what <BS>, CTRL-W, etc. can do in Insert mode" +msgstr "挿入モードで <BS>, CTRL-W 等が何をできるかを指定" + +msgid "definition of what comment lines look like" +msgstr "コメント行がどうなっているかの定義" + +msgid "list of flags that tell how automatic formatting works" +msgstr "自動整形がどのように動作するかを決めるフラグのリスト" + +msgid "pattern to recognize a numbered list" +msgstr "数字付きの箇条書きを認識するパターン" + +msgid "expression used for \"gq\" to format lines" +msgstr "\"gq\" で行を整形するときに使われる式" + +msgid "specifies how Insert mode completion works for CTRL-N and CTRL-P" +msgstr "挿入モード補完が CTRL-N と CTRL-P でどう動作するかを指定" + +msgid "whether to use a popup menu for Insert mode completion" +msgstr "挿入モード補完でポップアップメニューを使うかどうか" + +msgid "maximum height of the popup menu" +msgstr "ポップアップメニューの最大高" + +msgid "minimum width of the popup menu" +msgstr "ポップアップメニューの最大幅" + +msgid "user defined function for Insert mode completion" +msgstr "挿入モード補完用のユーザー定義関数" + +msgid "function for filetype-specific Insert mode completion" +msgstr "ファイルタイプ固有の挿入モード補完用関数" + +msgid "list of dictionary files for keyword completion" +msgstr "キーワード補完用の辞書ファイルのリスト" + +msgid "list of thesaurus files for keyword completion" +msgstr "キーワード補完用の同義語ファイルのリスト" + +msgid "function used for thesaurus completion" +msgstr "同義語補完で使われる関数" + +msgid "adjust case of a keyword completion match" +msgstr "キーワード補完のマッチで大文字小文字を調整" + +msgid "enable entering digraphs with c1 <BS> c2" +msgstr "c1 <BS> c2 でダイグラフを入力可能にする" + +msgid "the \"~\" command behaves like an operator" +msgstr "\"~\" コマンドがオペレータのようにふるまう" + +msgid "function called for the \"g@\" operator" +msgstr "\"g@\" オペレータで呼ばれる関数" + +msgid "when inserting a bracket, briefly jump to its match" +msgstr "括弧を入力したときに、対応する括弧にわずかの間ジャンプ" + +msgid "tenth of a second to show a match for 'showmatch'" +msgstr "'showmatch' で対応を表示する時間 (0.1秒単位)" + +msgid "list of pairs that match for the \"%\" command" +msgstr "\"%\" コマンドでマッチするペアのリスト" + +msgid "use two spaces after '.' when joining a line" +msgstr "行を連結するときに '.' の後に空白を 2 個入れる" + +msgid "" +"\"alpha\", \"octal\", \"hex\", \"bin\" and/or \"unsigned\"; number formats\n" +"recognized for CTRL-A and CTRL-X commands" +msgstr "" +"\"alpha\", \"octal\", \"hex\", \"bin\" かつ/または \"unsigned\";\n" +"CTRL-A と CTRL-X コマンドで認識する数字の書式" + +msgid "tabs and indenting" +msgstr "タブとインデント" -msgid "E931: Buffer cannot be registered" -msgstr "E931: バッファを登録できません" +msgid "number of spaces a <Tab> in the text stands for" +msgstr "1 つの <Tab> に対応する空白の数" + +msgid "number of spaces used for each step of (auto)indent" +msgstr "(自動)インデントの各段階に使われる空白の数" + +msgid "list of number of spaces a tab counts for" +msgstr "1 つのタブが相当する空白の数のリスト" + +msgid "list of number of spaces a soft tabsstop counts for" +msgstr "1 つのソフトタブストップに相当する空白の数のリスト" + +msgid "a <Tab> in an indent inserts 'shiftwidth' spaces" +msgstr "インデント内での <Tab> は 'shiftwidth' 個の空白を挿入" + +msgid "if non-zero, number of spaces to insert for a <Tab>" +msgstr "0 でないとき、1 つの <Tab> で挿入される空白の数" + +msgid "round to 'shiftwidth' for \"<<\" and \">>\"" +msgstr "\"<<\" と \">>\" で 'shiftwidth' に丸める" + +msgid "expand <Tab> to spaces in Insert mode" +msgstr "挿入モードで <Tab> を空白に展開" + +msgid "automatically set the indent of a new line" +msgstr "新しい行のインデントを自動的に設定" + +msgid "do clever autoindenting" +msgstr "賢い自動インデントを行う" + +msgid "enable specific indenting for C code" +msgstr "C コードに特有のインデントを有効にする" + +msgid "options for C-indenting" +msgstr "C インデント処理用のオプション" + +msgid "keys that trigger C-indenting in Insert mode" +msgstr "挿入モードで C インデント処理を引き起こすキー" + +msgid "list of words that cause more C-indent" +msgstr "さらなる C インデントを発生させる単語のリスト" + +msgid "list of scope declaration names used by cino-g" +msgstr "cino-g に用いられるスコープ宣言名のリスト" + +msgid "expression used to obtain the indent of a line" +msgstr "行のインデントを得るために使われる式" + +msgid "keys that trigger indenting with 'indentexpr' in Insert mode" +msgstr "挿入モードで 'indentexpr' によるインデントを引き起こすキー" + +msgid "copy whitespace for indenting from previous line" +msgstr "前の行からインデントの空白をコピー" + +msgid "preserve kind of whitespace when changing indent" +msgstr "インデントを変更するときに空白の種類を保持" + +msgid "enable lisp mode" +msgstr "lisp モードを有効化" + +msgid "words that change how lisp indenting works" +msgstr "lisp インデント処理の動作を変更する単語のリスト" + +msgid "options for Lisp indenting" +msgstr "list インデント処理用のオプション" + +msgid "folding" +msgstr "折畳み" + +msgid "unset to display all folds open" +msgstr "全ての折畳みを開いて表示するにはオフにする" + +msgid "folds with a level higher than this number will be closed" +msgstr "この数値よりもレベルの高い折畳みは閉じられる" + +msgid "value for 'foldlevel' when starting to edit a file" +msgstr "ファイルを編集開始する際の 'foldlevel' の値" + +msgid "width of the column used to indicate folds" +msgstr "折畳みを表示するのに使われる列幅" + +msgid "expression used to display the text of a closed fold" +msgstr "閉じられた折畳みのテキストを表示するのに使われる式" + +msgid "set to \"all\" to close a fold when the cursor leaves it" +msgstr "カーソルが折畳みを離れたときに閉じるには \"all\" に設定" + +msgid "specifies for which commands a fold will be opened" +msgstr "どのコマンドが折畳みを開くかを指定" + +msgid "minimum number of screen lines for a fold to be closed" +msgstr "折畳みが閉じられる画面上の最小行数" + +msgid "template for comments; used to put the marker in" +msgstr "コメント用のテンプレート; マーカーを中に置くために使われる" + +msgid "" +"folding type: \"manual\", \"indent\", \"expr\", \"marker\",\n" +"\"syntax\" or \"diff\"" +msgstr "" +"折畳みの種類: \"manual\", \"indent\", \"expr\", \"marker\",\n" +"\"syntax\" または \"diff\"" + +msgid "expression used when 'foldmethod' is \"expr\"" +msgstr "'foldmethod' が \"expr\" の際に使われる式" + +msgid "used to ignore lines when 'foldmethod' is \"indent\"" +msgstr "'foldmethod' が \"indent\" の際に行を無視するために使われる" + +msgid "markers used when 'foldmethod' is \"marker\"" +msgstr "'foldmethod' が \"marker\" の際に使われるマーカー" + +msgid "maximum fold depth for when 'foldmethod' is \"indent\" or \"syntax\"" +msgstr "" +"'foldmethod' が \"indent\" または \"syntax\" の際の折畳みの\n" +"最大の深さ" + +msgid "diff mode" +msgstr "差分モード" + +msgid "use diff mode for the current window" +msgstr "現在のウィンドウで差分モードを使う" + +msgid "options for using diff mode" +msgstr "差分モードを使うためのオプション" + +msgid "expression used to obtain a diff file" +msgstr "差分ファイルを取得するために使われる式" + +msgid "expression used to patch a file" +msgstr "ファイルにパッチを当てるために使われる式" + +msgid "mapping" +msgstr "マッピング" + +msgid "maximum depth of mapping" +msgstr "マッピングの最大の深さ" + +msgid "allow timing out halfway into a mapping" +msgstr "マッピングの途中でのタイムアウトを許可" + +msgid "allow timing out halfway into a key code" +msgstr "キーコードの途中でのタイムアウトを許可" + +msgid "time in msec for 'timeout'" +msgstr "'timeout' の時間 (ミリ秒)" + +msgid "time in msec for 'ttimeout'" +msgstr "'ttimeout' の時間 (ミリ秒)" + +msgid "reading and writing files" +msgstr "ファイルの読み書き" + +msgid "enable using settings from modelines when reading a file" +msgstr "ファイル読込み時にモードラインからの設定の使用を有効にする" + +msgid "allow setting expression options from a modeline" +msgstr "モードラインから式であるオプションを設定することを許可する" + +msgid "number of lines to check for modelines" +msgstr "モードライン用にチェックする行数" + +msgid "binary file editing" +msgstr "バイナリファイルの編集" + +msgid "last line in the file has an end-of-line" +msgstr "ファイルの最終行に改行がある" + +msgid "last line in the file followed by CTRL-Z" +msgstr "ファイルの最終行が CTRL-Z で終わる" + +msgid "fixes missing end-of-line at end of text file" +msgstr "テキストファイルの末尾に改行がない場合に修正する" + +msgid "prepend a Byte Order Mark to the file" +msgstr "バイト順マーク (BOM) をファイル先頭につける" + +msgid "end-of-line format: \"dos\", \"unix\" or \"mac\"" +msgstr "改行の形式: \"dos\", \"unix\" または \"mac\"" + +msgid "list of file formats to look for when editing a file" +msgstr "ファイル編集時に調べる改行形式のリスト" + +msgid "writing files is allowed" +msgstr "ファイルの書込みが許可されている" + +msgid "write a backup file before overwriting a file" +msgstr "ファイルを上書きする前にバックアップに書込む" + +msgid "keep a backup after overwriting a file" +msgstr "ファイルの上書き後にバックアップを保持" + +msgid "patterns that specify for which files a backup is not made" +msgstr "どのファイルでバックアックが作られないかを指定するパターン" + +msgid "whether to make the backup as a copy or rename the existing file" +msgstr "バックアップを既存のファイルのコピーとするかリネームするか" + +msgid "list of directories to put backup files in" +msgstr "バックアップファイルを置くディレクトリのリスト" + +msgid "file name extension for the backup file" +msgstr "バックアップファイルの拡張子" + +msgid "automatically write a file when leaving a modified buffer" +msgstr "変更されたバッファを離れる際に自動的にファイルに書込む" + +msgid "as 'autowrite', but works with more commands" +msgstr "'autowrite' と同様だが、より多くのコマンドで動作する" + +msgid "always write without asking for confirmation" +msgstr "常に確認無しに書込む" + +msgid "automatically read a file when it was modified outside of Vim" +msgstr "Vim の外でファイルが変更された際に自動的に読込む" + +msgid "keep oldest version of a file; specifies file name extension" +msgstr "ファイルの最古のバージョンを保持; ファイルの拡張子を指定" + +msgid "forcibly sync the file to disk after writing it" +msgstr "ファイルを書込んだ後に強制的にディスクに同期させる" + +msgid "the swap file" +msgstr "スワップファイル" + +msgid "list of directories for the swap file" +msgstr "スワップファイル用のディレクトリのリスト" + +msgid "use a swap file for this buffer" +msgstr "このバッファでスワップファイルを使う" + +msgid "number of characters typed to cause a swap file update" +msgstr "何文字入力したらスワップファイルを更新するか" + +msgid "time in msec after which the swap file will be updated" +msgstr "スワップファイルを更新するまでの時間 (ミリ秒)" + +msgid "command line editing" +msgstr "コマンドライン編集" + +msgid "how many command lines are remembered" +msgstr "コマンドラインを何個まで記憶するか" + +msgid "key that triggers command-line expansion" +msgstr "コマンドライン展開を引き起こすキー" + +msgid "like 'wildchar' but can also be used in a mapping" +msgstr "'wildchar' と同様だがマッピング内でも使用できる" + +msgid "specifies how command line completion works" +msgstr "どのようにコマンドライン補完が動作するかを指定" + +msgid "empty or \"tagfile\" to list file name of matching tags" +msgstr "空、またはマッチしたファイル名を一覧表示するなら \"tagfile\"" + +msgid "list of file name extensions that have a lower priority" +msgstr "低い優先度を持つ拡張子のリスト" + +msgid "list of file name extensions added when searching for a file" +msgstr "ファイル検索時に追加される拡張子のリスト" + +msgid "list of patterns to ignore files for file name completion" +msgstr "ファイル名補完の際に無視するファイルパターンのリスト" + +msgid "ignore case when using file names" +msgstr "ファイル名を使う際に大文字小文字の違いを無視" + +msgid "ignore case when completing file names" +msgstr "ファイル名補完の際に大文字小文字の違いを無視" + +msgid "command-line completion shows a list of matches" +msgstr "コマンドライン補完はマッチの一覧を表示する" + +msgid "key used to open the command-line window" +msgstr "コマンドラインウィンドウを開くためのキー" + +msgid "height of the command-line window" +msgstr "コマンドラインウィンドウの高さ" + +msgid "executing external commands" +msgstr "外部コマンドの実行" + +msgid "name of the shell program used for external commands" +msgstr "外部コマンドに使われるシェルプログラムの名前" + +msgid "character(s) to enclose a shell command in" +msgstr "シェルコマンドを囲む引用符" + +msgid "like 'shellquote' but include the redirection" +msgstr "'shellquote' と同様だがリダイレクトを含む" + +msgid "characters to escape when 'shellxquote' is (" +msgstr "'shellxquote' が ( の時にエスケープされる文字" + +msgid "argument for 'shell' to execute a command" +msgstr "コマンドを実行する際の 'shell' の引数" + +msgid "used to redirect command output to a file" +msgstr "コマンドの出力をファイルにリダイレクトする際に使われる" + +msgid "use a temp file for shell commands instead of using a pipe" +msgstr "シェルコマンドにパイプを使わずに一時ファイルを使う" + +msgid "program used for \"=\" command" +msgstr "\"=\" コマンドに使われるプログラム" + +msgid "program used to format lines with \"gq\" command" +msgstr "\"gq\" コマンドで行を整形する際に使われるプログラム" + +msgid "program used for the \"K\" command" +msgstr "\"K\" コマンドに使われるプログラム" + +msgid "warn when using a shell command and a buffer has changes" +msgstr "バッファに変更がありシェルコマンドが実行された際に警告する" + +msgid "running make and jumping to errors (quickfix)" +msgstr "make の実行とエラーへのジャンプ (quickfix)" + +msgid "name of the file that contains error messages" +msgstr "エラーメッセージが入っているファイルの名前" + +msgid "list of formats for error messages" +msgstr "エラーメッセージの書式のリスト" + +msgid "program used for the \":make\" command" +msgstr "\":make\" コマンドに使われるプログラム" + +msgid "string used to put the output of \":make\" in the error file" +msgstr "\":make\" の出力をエラーファイルに書込むために使われる文字列" + +msgid "name of the errorfile for the 'makeprg' command" +msgstr "'makeprg' コマンド用のエラーファイルの名前" + +msgid "program used for the \":grep\" command" +msgstr "\":grep\" コマンドに使われるプログラム" + +msgid "list of formats for output of 'grepprg'" +msgstr "'grepprg' の出力用の書式のリスト" + +msgid "encoding of the \":make\" and \":grep\" output" +msgstr "\":make\" と \":grep\" の出力のエンコーディング" + +msgid "system specific" +msgstr "システム固有" + +msgid "use forward slashes in file names; for Unix-like shells" +msgstr "ファイル名でスラッシュを使う; Unix ライクなシェル用" + +msgid "specifies slash/backslash used for completion" +msgstr "補完に salsh/backslash のどちらを使うか指定" + +msgid "language specific" +msgstr "言語固有" + +msgid "specifies the characters in a file name" +msgstr "ファイル名に使われる文字を指定" + +msgid "specifies the characters in an identifier" +msgstr "識別子に使われる文字を指定" + +msgid "specifies the characters in a keyword" +msgstr "キーワードに使われる文字を指定" + +msgid "specifies printable characters" +msgstr "表示可能な文字を指定" + +msgid "specifies escape characters in a string" +msgstr "文字列内のエスケープ文字を指定" + +msgid "display the buffer right-to-left" +msgstr "バッファを右から左に表示" + +msgid "when to edit the command-line right-to-left" +msgstr "いつコマンドラインを右から左に編集するか" + +msgid "insert characters backwards" +msgstr "文字を逆方向に挿入" + +msgid "allow CTRL-_ in Insert and Command-line mode to toggle 'revins'" +msgstr "挿入・コマンドラインモードで CTRL-_ で 'revins' の切り替えを許可" + +msgid "the ASCII code for the first letter of the Hebrew alphabet" +msgstr "ヘブライ語アルファベットの最初の文字を表す ASCII コード" + +msgid "use Hebrew keyboard mapping" +msgstr "ヘブライキーボードのマッピングを使用" + +msgid "use phonetic Hebrew keyboard mapping" +msgstr "音声ヘブライキーボードのマッピングを使用" + +msgid "prepare for editing Arabic text" +msgstr "アラビア語のテキストを編集する準備" + +msgid "perform shaping of Arabic characters" +msgstr "アラビア文字の字形処理を行う" + +msgid "terminal will perform bidi handling" +msgstr "端末が双方向 (bidi) の処理を行う" + +msgid "name of a keyboard mapping" +msgstr "キーボードマッピングの名前" + +msgid "list of characters that are translated in Normal mode" +msgstr "ノーマルモードで変換される文字のリスト" + +msgid "apply 'langmap' to mapped characters" +msgstr "'langmap' をマップされた文字に適用" + +msgid "when set never use IM; overrules following IM options" +msgstr "オンのとき IM を全く使わない; 以下の IM 関連オプションに優先する" + +msgid "in Insert mode: 1: use :lmap; 2: use IM; 0: neither" +msgstr "挿入モード時: 1: :lmap を使用; 2: IM を使用; 0: どちらも不使用" + +msgid "entering a search pattern: 1: use :lmap; 2: use IM; 0: neither" +msgstr "" +"検索パターン入力時: 1: :lmap を使用; 2: IM を使用;\n" +"0: どちらも不使用" + +msgid "when set always use IM when starting to edit a command line" +msgstr "オンのときはコマンドライン編集開始時に常に IM を使用" + +msgid "function to obtain IME status" +msgstr "IME の状態を取得するための関数" + +msgid "function to enable/disable IME" +msgstr "IME を有効化/無効化するための関数" + +msgid "multi-byte characters" +msgstr "マルチバイト文字" + +msgid "character encoding used in Nvim: \"utf-8\"" +msgstr "Nvim で使われる文字エンコーディング: \"uft-8\"" + +msgid "character encoding for the current file" +msgstr "現在のファイルの文字エンコーディング" + +msgid "automatically detected character encodings" +msgstr "文字エンコーディングを自動検出" + +msgid "expression used for character encoding conversion" +msgstr "文字エンコーディング変換に使われる式" + +msgid "delete combining (composing) characters on their own" +msgstr "結合文字そのものを削除" + +msgid "maximum number of combining (composing) characters displayed" +msgstr "表示の際の結合文字の最大数" + +msgid "key that activates the X input method" +msgstr "X インプットメソッドを起動するためのキー" + +msgid "width of ambiguous width characters" +msgstr "あいまい幅文字の幅" + +msgid "emoji characters are full width" +msgstr "絵文字の幅は全角" + +msgid "various" +msgstr "その他" + +msgid "" +"when to use virtual editing: \"block\", \"insert\", \"all\"\n" +"and/or \"onemore\"" +msgstr "" +"いつ仮想編集を使うか: \"block\", \"insert\", \"all\"\n" +"かつ/または \"onemore\"" + +msgid "list of autocommand events which are to be ignored" +msgstr "自動コマンドイベントで無視するもののリスト" + +msgid "load plugin scripts when starting up" +msgstr "起動時にプラグインスクリプトを読込む" + +msgid "enable reading .vimrc/.exrc/.gvimrc in the current directory" +msgstr "" +"カレントディレクトリにある .vimrc/.exrc/.gvimrc の読込みを\n" +"有効化" + +msgid "safer working with script files in the current directory" +msgstr "カレントディレクトリのスクリプトファイルを安全に扱う" + +msgid "use the 'g' flag for \":substitute\"" +msgstr "\":substitute\" に 'g' フラグを使う" + +msgid "allow reading/writing devices" +msgstr "デバイスからの読み書きを許可する" + +msgid "maximum depth of function calls" +msgstr "関数呼出しの最大の深さ" + +msgid "list of words that specifies what to put in a session file" +msgstr "セッションファイルに何を保存するかを指定する単語のリスト" + +msgid "list of words that specifies what to save for :mkview" +msgstr ":mkview で何を保存するかを指定する単語のリスト" + +msgid "directory where to store files with :mkview" +msgstr ":mkview でファイルを保存するディレクトリ" + +msgid "list that specifies what to write in the ShaDa file" +msgstr "ShaDa ファイルに何を書くかを指定するリスト" + +msgid "what happens with a buffer when it's no longer in a window" +msgstr "バッファがウィンドウに表示されなくなった時の挙動" + +msgid "empty, \"nofile\", \"nowrite\", \"quickfix\", etc.: type of buffer" +msgstr "空, \"nofile\", \"nowrite\", \"quickfix\" など: バッファの種別" + +msgid "whether the buffer shows up in the buffer list" +msgstr "バッファをバッファ一覧に表示するかどうか" + +msgid "set to \"msg\" to see all error messages" +msgstr "全てのエラーメッセージを見るには \"msg\" に設定" + +msgid "whether to show the signcolumn" +msgstr "目印桁を表示するかどうか" + +msgid "name of the MzScheme dynamic library" +msgstr "MzScheme 動的ライブラリの名前" + +msgid "name of the MzScheme GC dynamic library" +msgstr "MzScheme GC 動的ライブラリの名前" + +msgid "whether to use Python 2 or 3" +msgstr "Python 2 と 3 のどちらを使うか" + +msgid "E249: Window layout changed unexpectedly" +msgstr "E249: 予期せずウィンドウの配置が変わりました" + +msgid "E1156: Cannot change the argument list recursively" +msgstr "E1156: 引数リストを再帰的に変更することはできません" + +msgid "E163: There is only one file to edit" +msgstr "E163: 編集するファイルは1つしかありません" + +msgid "E164: Cannot go before first file" +msgstr "E164: 最初のファイルより前には行けません" + +msgid "E165: Cannot go beyond last file" +msgstr "E165: 最後のファイルを越えて後には行けません" + +msgid "E610: No argument to delete" +msgstr "E610: 削除する引数がありません" + +msgid "E218: Autocommand nesting too deep" +msgstr "E218: 自動コマンドの入れ子が深過ぎます" + +msgid "--Deleted--" +msgstr "--削除済--" + +#, c-format +msgid "auto-removing autocommand: %s <buffer=%d>" +msgstr "自動コマンド: %s <バッファ=%d> が自動的に削除されます" + +#, c-format +msgid "E367: No such group: \"%s\"" +msgstr "E367: そのグループはありません: \"%s\"" + +msgid "E936: Cannot delete the current group" +msgstr "E936: 現在のグループは削除できません" + +msgid "W19: Deleting augroup that is still in use" +msgstr "W19: 使用中の augroup を消そうとしています" + +msgid "" +"\n" +"--- Autocommands ---" +msgstr "" +"\n" +"--- 自動コマンド ---" + +#, c-format +msgid "E680: <buffer=%d>: invalid buffer number " +msgstr "E680: <バッファ=%d>: 無効なバッファ番号です" + +msgid "E217: Can't execute autocommands for ALL events" +msgstr "E217: 全てのイベントに対しての自動コマンドは実行できません" + +#, c-format +msgid "No matching autocommands: %s" +msgstr "該当する自動コマンドは存在しません: %s" + +#, fuzzy, c-format +#~ msgid "%s Autocommands for \"%s\"" +#~ msgstr "%s Autocommands for \"%s\"" + +#, c-format +msgid "Executing %s" +msgstr "%s を実行しています" + +#, c-format +msgid "autocommand %s" +msgstr "自動コマンド %s" + +#, c-format +msgid "E215: Illegal character after *: %s" +msgstr "E215: * の後に不正な文字がありました: %s" + +#, c-format +msgid "E216: No such event: %s" +msgstr "E216: そのようなイベントはありません: %s" + +#, c-format +msgid "E216: No such group or event: %s" +msgstr "E216: そのようなグループもしくはイベントはありません: %s" #, c-format msgid "E937: Attempt to delete a buffer that is in use: %s" msgstr "E937: 使用中のバッファを削除しようと試みました: %s" +msgid "E82: Cannot allocate any buffer, exiting..." +msgstr "E82: バッファを1つも作成できないので、終了します..." + +msgid "E83: Cannot allocate buffer, using other one..." +msgstr "E83: バッファを作成できないので、他のを使用します..." + msgid "E515: No buffers were unloaded" msgstr "E515: 解放されたバッファはありません" @@ -70,26 +1338,20 @@ msgstr "E516: 削除されたバッファはありません" msgid "E517: No buffers were wiped out" msgstr "E517: 破棄されたバッファはありません" -msgid "1 buffer unloaded" -msgstr "1 個のバッファが解放されました" - #, c-format -msgid "%d buffers unloaded" -msgstr "%d 個のバッファが解放されました" - -msgid "1 buffer deleted" -msgstr "1 個のバッファが削除されました" +msgid "%d buffer unloaded" +msgid_plural "%d buffers unloaded" +msgstr[0] "%d 個のバッファが解放されました" #, c-format -msgid "%d buffers deleted" -msgstr "%d 個のバッファが削除されました" - -msgid "1 buffer wiped out" -msgstr "1 個のバッファが破棄されました" +msgid "%d buffer deleted" +msgid_plural "%d buffers deleted" +msgstr[0] "%d 個のバッファが削除されました" #, c-format -msgid "%d buffers wiped out" -msgstr "%d 個のバッファが破棄されました" +msgid "%d buffer wiped out" +msgid_plural "%d buffers wiped out" +msgstr[0] "%d 個のバッファが破棄されました" msgid "E90: Cannot unload last buffer" msgstr "E90: 最後のバッファは解放できません" @@ -107,8 +1369,13 @@ msgid "E88: Cannot go before first buffer" msgstr "E88: 最初のバッファより前へは移動できません" #, c-format -msgid "E89: No write since last change for buffer %ld (add ! to override)" -msgstr "E89: バッファ %ld の変更は保存されていません (! で変更を破棄)" +msgid "" +"E89: No write since last change for buffer %<PRId64> (add ! to override)" +msgstr "E89: バッファ %<PRId64> の変更は保存されていません (! で変更を破棄)" + +#, c-format +msgid "E89: %s will be killed (add ! to override)" +msgstr "E89: \"%s\" が存在します (上書するには ! を追加してください)" msgid "E948: Job still running (add ! to end the job)" msgstr "E948: ジョブはまだ実行中です (! を追加でジョブを終了)" @@ -126,8 +1393,8 @@ msgid "W14: Warning: List of file names overflow" msgstr "W14: 警告: ファイル名のリストが長過ぎます" #, c-format -msgid "E92: Buffer %ld not found" -msgstr "E92: バッファ %ld が見つかりません" +msgid "E92: Buffer %<PRId64> not found" +msgstr "E92: バッファ %<PRId64> が見つかりません" #, c-format msgid "E93: More than one match for %s" @@ -138,8 +1405,8 @@ msgid "E94: No matching buffer for %s" msgstr "E94: %s に該当するバッファはありませんでした" #, c-format -msgid "line %ld" -msgstr "行 %ld" +msgid "line %<PRId64>" +msgstr "行 %<PRId64>" msgid "E95: Buffer with this name already exists" msgstr "E95: この名前のバッファは既にあります" @@ -150,8 +1417,8 @@ msgstr " [変更あり]" msgid "[Not edited]" msgstr "[未編集]" -msgid "[New file]" -msgstr "[新ファイル]" +msgid "[New]" +msgstr "[新]" msgid "[Read errors]" msgstr "[読込エラー]" @@ -163,16 +1430,13 @@ msgid "[readonly]" msgstr "[読込専用]" #, c-format -msgid "1 line --%d%%--" -msgstr "1 行 --%d%%--" - -#, c-format -msgid "%ld lines --%d%%--" -msgstr "%ld 行 --%d%%--" +msgid "%<PRId64> line --%d%%--" +msgid_plural "%<PRId64> lines --%d%%--" +msgstr[0] "%<PRId64> 行 --%d%%--" #, c-format -msgid "line %ld of %ld --%d%%-- col " -msgstr "行 %ld (全体 %ld) --%d%%-- col " +msgid "line %<PRId64> of %<PRId64> --%d%%-- col " +msgstr "行 %<PRId64> (全体 %<PRId64>) --%d%%-- col " msgid "[No Name]" msgstr "[無名]" @@ -180,12 +1444,6 @@ msgstr "[無名]" msgid "help" msgstr "ヘルプ" -msgid "[Help]" -msgstr "[ヘルプ]" - -msgid "[Preview]" -msgstr "[プレビュー]" - msgid "All" msgstr "全て" @@ -195,141 +1453,246 @@ msgstr "末尾" msgid "Top" msgstr "先頭" -msgid "" -"\n" -"# Buffer list:\n" -msgstr "" -"\n" -"# バッファリスト:\n" +#, c-format +msgid "%d%%" +msgstr "%d%%" + +#, c-format +msgid " (%d of %d)" +msgstr " (%d of %d)" + +#, c-format +msgid " ((%d) of %d)" +msgstr " ((%d) of %d)" msgid "E382: Cannot write, 'buftype' option is set" msgstr "E382: 'buftype' オプションが設定されているので書込めません" +msgid "[Command Line]" +msgstr "[コマンドライン]" + msgid "[Prompt]" msgstr "[プロンプト]" msgid "[Scratch]" msgstr "[下書き]" -msgid "" -"\n" -"--- Signs ---" -msgstr "" -"\n" -"--- サイン ---" +msgid "[Location List]" +msgstr "[ロケーションリスト]" -#, c-format -msgid "Signs for %s:" -msgstr "%s のサイン:" +msgid "[Quickfix List]" +msgstr "[Quickfixリスト]" + +msgid "E206: Patchmode: can't touch empty original file" +msgstr "E206: Patchmode: 空の原本ファイルをtouchできません" + +msgid "E513: Write error, conversion failed (make 'fenc' empty to override)" +msgstr "E513: 書込みエラー、変換失敗 (上書するには 'fenc' を空にしてください)" + +#~ msgid "E513: Write error, conversion failed in line %" +#~ msgstr "" + +msgid "E514: Write error (file system full?)" +msgstr "E514: 書込みエラー (ファイルシステムが満杯?)" #, c-format -msgid " line=%ld id=%d name=%s" -msgstr " 行=%ld 識別子=%d 名前=%s" +msgid "E676: No matching autocommands for buftype=%s buffer" +msgstr "E676: buftype=%s バッファの該当する自動コマンドは存在しません" -msgid "E902: Cannot connect to port" -msgstr "E902: ポートに接続できません" +msgid "WARNING: The file has been changed since reading it!!!" +msgstr "警告: 読込んだ後にファイルに変更がありました!!!" -msgid "E901: gethostbyname() in channel_open()" -msgstr "E901: channel_open() 内の gethostbyname() が失敗しました" +msgid "Do you really want to write to it" +msgstr "本当に上書きしますか" -msgid "E898: socket() in channel_open()" -msgstr "E898: channel_open() 内の socket() が失敗しました" +msgid "E203: Autocommands deleted or unloaded buffer to be written" +msgstr "E203: 保存するバッファを自動コマンドが削除もしくは解放しました" -msgid "E903: received command with non-string argument" -msgstr "E903: 非文字列の引数のコマンドを受信しました" +msgid "E204: Autocommand changed number of lines in unexpected way" +msgstr "E204: 自動コマンドが予期せぬ方法で行数を変更しました" -msgid "E904: last argument for expr/call must be a number" -msgstr "E904: expr/call の最後の引数は数字でなければなりません" +msgid "is a directory" +msgstr "はディレクトリです" -msgid "E904: third argument for call must be a list" -msgstr "E904: call の3番目の引数はリスト型でなければなりません" +msgid "is not a file or writable device" +msgstr "はファイルでも書込み可能デバイスでもありません" + +msgid "is read-only (add ! to override)" +msgstr "は読込専用です (強制書込には ! を追加)" #, c-format -msgid "E905: received unknown command: %s" -msgstr "E905: 未知のコマンドを受信しました: %s" +msgid "E303: Unable to create directory \"%s\" for backup file: %s" +msgstr "" +"E303: バックアップファイル用のディレクトリ \"%s\" を作成できませんでした: %s" + +msgid "E509: Cannot create backup file (add ! to override)" +msgstr "E509: バックアップファイルを作れません (! を追加で強制書込)" + +msgid "E510: Can't make backup file (add ! to override)" +msgstr "E510: バックアップに失敗しました (! を追加で強制書込)" -msgid "E906: not an open channel" -msgstr "E906: 開いていないチャネルです" +msgid "E214: Can't find temp file for writing" +msgstr "E214: 保存用一時ファイルが見つかりません" + +msgid "E213: Cannot convert (add ! to write without conversion)" +msgstr "E213: 変換できません (! を追加で変換せずに保存)" + +msgid "E166: Can't open linked file for writing" +msgstr "E166: リンクされたファイルに書込めません" #, c-format -msgid "E630: %s(): write while not connected" -msgstr "E630: %s(): 非接続状態で書き込みました" +msgid "E212: Can't open file for writing: %s" +msgstr "E212: 書込み用にファイルを開けません: %s" #, c-format -msgid "E631: %s(): write failed" -msgstr "E631: %s(): 書き込みに失敗しました" +msgid "E512: Close failed: %s" +msgstr "E512: 閉じることに失敗: %s" + +msgid " CONVERSION ERROR" +msgstr " 変換エラー" #, c-format -msgid "E917: Cannot use a callback with %s()" -msgstr "E917: %s() にコールバックは使えません" +msgid " in line %<PRId64>;" +msgstr " 行 %<PRId64>;" + +msgid "[NOT converted]" +msgstr "[未変換]" + +msgid "[converted]" +msgstr "[変換済]" + +msgid "[Device]" +msgstr "[デバイス]" + +#, fuzzy +#~ msgid "[noeol]" +#~ msgstr "[noeol]" + +msgid " [a]" +msgstr " [a]" + +msgid " appended" +msgstr " 追加" + +msgid " [w]" +msgstr " [w]" + +msgid " written" +msgstr " 書込み" -msgid "E912: cannot use ch_evalexpr()/ch_sendexpr() with a raw or nl channel" +msgid "E205: Patchmode: can't save original file" +msgstr "E205: patchmode: 原本ファイルを保存できません" + +msgid "E207: Can't delete backup file" +msgstr "E207: バックアップファイルを消せません" + +msgid "" +"\n" +"WARNING: Original file may be lost or damaged\n" msgstr "" -"E912: raw や nl モードのチャネルに ch_evalexpr()/ch_sendexpr() は使えません" +"\n" +"警告: 原本ファイルが失われたか変更されました\n" -msgid "E920: _io file requires _name to be set" -msgstr "E920: _io ファイルは _name の設定が必要です" +msgid "don't quit the editor until the file is successfully written!" +msgstr "ファイルの保存に成功するまでエディタを終了しないでください!" -msgid "E915: in_io buffer requires in_buf or in_name to be set" -msgstr "E915: in_io バッファは in_buf か in_name の設定が必要です" +msgid "W10: Warning: Changing a readonly file" +msgstr "W10: 警告: 読込専用ファイルを変更します" -#, c-format -msgid "E918: buffer must be loaded: %s" -msgstr "E918: バッファがロードされてなければなりません: %s" +msgid "can only be opened in headless mode" +msgstr "ヘッドレスモードでのみ開くことができます" + +msgid "channel was already open" +msgstr "チャネルは既に開かれています" -msgid "E821: File is encrypted with unknown method" -msgstr "E821: ファイルが未知の方法で暗号化されています" +msgid "Can't send data to closed stream" +msgstr "閉じているストリームにデータを送ることはできません" -msgid "Warning: Using a weak encryption method; see :help 'cm'" -msgstr "警告: 弱い暗号方法を使っています; :help 'cm' を参照してください" +msgid "Can't send raw data to rpc channel" +msgstr "rpcチャネルに生データをに送ることはできません" -msgid "Enter encryption key: " -msgstr "暗号化用のキーを入力してください: " +msgid "tagname" +msgstr "タグ名" -msgid "Enter same key again: " -msgstr "もう一度同じキーを入力してください: " +msgid " kind file\n" +msgstr " ファイル種類\n" -msgid "Keys don't match!" -msgstr "キーが一致しません" +msgid "'history' option is zero" +msgstr "オプション 'history' がゼロです" -msgid "[crypted]" -msgstr "[暗号化]" +msgid "E548: Digit expected" +msgstr "E548: 数値が必要です" + +msgid "E545: Missing colon" +msgstr "E545: コロンがありません" + +msgid "E546: Illegal mode" +msgstr "E546: 不正なモードです" + +msgid "E549: Illegal percentage" +msgstr "E549: 不正なパーセンテージです" + +msgid "Entering Debug mode. Type \"cont\" to continue." +msgstr "デバッグモードに入ります。続けるには \"cont\" と入力してください。" #, c-format -msgid "E720: Missing colon in Dictionary: %s" -msgstr "E720: 辞書型にコロンがありません: %s" +msgid "Oldval = \"%s\"" +msgstr "古い値 = \"%s\"" #, c-format -msgid "E721: Duplicate key in Dictionary: \"%s\"" -msgstr "E721: 辞書型に重複キーがあります: \"%s\"" +msgid "Newval = \"%s\"" +msgstr "新しい値 = \"%s\"" #, c-format -msgid "E722: Missing comma in Dictionary: %s" -msgstr "E722: 辞書型にカンマがありません: %s" +msgid "line %<PRId64>: %s" +msgstr "行 %<PRId64>: %s" #, c-format -msgid "E723: Missing end of Dictionary '}': %s" -msgstr "E723: 辞書型の最後に '}' がありません: %s" +msgid "cmd: %s" +msgstr "コマンド: %s" -msgid "extend() argument" -msgstr "extend() の引数" +msgid "frame is zero" +msgstr "フレームが 0 です" #, c-format -msgid "E737: Key already exists: %s" -msgstr "E737: キーは既に存在します: %s" +msgid "frame at highest level: %d" +msgstr "最高レベルのフレーム: %d" + +#, c-format +msgid "Breakpoint in \"%s%s\" line %<PRId64>" +msgstr "ブレークポイント \"%s%s\" 行 %<PRId64>" + +#, c-format +msgid "E161: Breakpoint not found: %s" +msgstr "E161: ブレークポイントが見つかりません: %s" + +msgid "No breakpoints defined" +msgstr "ブレークポイントが定義されていません" + +#, c-format +msgid "%3d %s %s line %<PRId64>" +msgstr "%3d %s %s 行 %<PRId64>" + +#, c-format +msgid "%3d expr %s" +msgstr "%3d expr %s" #, c-format -msgid "E96: Cannot diff more than %ld buffers" -msgstr "E96: %ld 以上のバッファはdiffできません" +msgid "E96: Cannot diff more than %<PRId64> buffers" +msgstr "E96: %<PRId64> 以上のバッファはdiffできません" + +#, c-format +msgid "Not enough memory to use internal diff for buffer \"%s\"" +msgstr "バッファ \"%s\" 用に内部diffを使うためのメモリが不足しています" msgid "E810: Cannot read or write temp files" -msgstr "E810: 一時ファイルの読込もしくは書込ができません" +msgstr "E810: 一時ファイルの読込みもしくは書込みができません" msgid "E97: Cannot create diffs" msgstr "E97: 差分を作成できません" -msgid "Patch file" -msgstr "パッチファイル" +msgid "E960: Problem creating the internal diff" +msgstr "E960: 内部diff作成時に問題が発生しました" msgid "E816: Cannot read patch output" msgstr "E816: patchの出力を読込めません" @@ -359,173 +1722,236 @@ msgid "E103: Buffer \"%s\" is not in diff mode" msgstr "E103: バッファ \"%s\" は差分モードではありません" msgid "E787: Buffer changed unexpectedly" -msgstr "E787: 予期せずバッファが変更変更されました" +msgstr "E787: 予期せずバッファが変更されました" + +#, c-format +msgid "E1214: Digraph must be just two characters: %s" +msgstr "E1214: ダイグラフはちょうど2文字でなければなりません: %s" + +#, c-format +msgid "E1215: Digraph must be one character: %s" +msgstr "E1215: ダイグラフは1文字でなければなりません: %s" + +msgid "" +"E1216: digraph_setlist() argument must be a list of lists with two items" +msgstr "" +"E1216: digraph_setlist() の引数は2要素のリストのリストでなければなりません" msgid "E104: Escape not allowed in digraph" msgstr "E104: 合字にEscapeは使用できません" -msgid "E544: Keymap file not found" -msgstr "E544: キーマップファイルが見つかりません" +msgid "Custom" +msgstr "カスタム" -msgid "E105: Using :loadkeymap not in a sourced file" -msgstr "E105: :source で取込むファイル以外では :loadkeymap を使えません" +msgid "Latin supplement" +msgstr "ラテン補助" -msgid "E791: Empty keymap entry" -msgstr "E791: 空のキーマップエントリ" +msgid "Greek and Coptic" +msgstr "ギリシャとコプト" -msgid " Keyword completion (^N^P)" -msgstr " キーワード補完 (^N^P)" +msgid "Cyrillic" +msgstr "キリル" -msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)" -msgstr " ^X モード (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)" +msgid "Hebrew" +msgstr "ヘブライ" -msgid " Whole line completion (^L^N^P)" -msgstr " 行(全体)補完 (^L^N^P)" +msgid "Arabic" +msgstr "アラビア" -msgid " File name completion (^F^N^P)" -msgstr " ファイル名補完 (^F^N^P)" +msgid "Latin extended" +msgstr "ラテン拡張" -msgid " Tag completion (^]^N^P)" -msgstr " タグ補完 (^]^N^P)" +msgid "Greek extended" +msgstr "ギリシャ拡張" -msgid " Path pattern completion (^N^P)" -msgstr " パスパターン補完 (^N^P)" +msgid "Punctuation" +msgstr "句読点" -msgid " Definition completion (^D^N^P)" -msgstr " 定義補完 (^D^N^P)" +msgid "Super- and subscripts" +msgstr "上付き・下付き" -msgid " Dictionary completion (^K^N^P)" -msgstr " 辞書補完 (^K^N^P)" +msgid "Currency" +msgstr "通貨記号" -msgid " Thesaurus completion (^T^N^P)" -msgstr " シソーラス補完 (^T^N^P)" +msgid "Other" +msgstr "その他" -msgid " Command-line completion (^V^N^P)" -msgstr " コマンドライン補完 (^V^N^P)" +msgid "Roman numbers" +msgstr "ローマ数字" -msgid " User defined completion (^U^N^P)" -msgstr " ユーザー定義補完 (^U^N^P)" +msgid "Arrows" +msgstr "矢印" -msgid " Omni completion (^O^N^P)" -msgstr " オムニ補完 (^O^N^P)" +msgid "Mathematical operators" +msgstr "数学記号" -msgid " Spelling suggestion (s^N^P)" -msgstr " 綴り修正候補 (s^N^P)" +msgid "Technical" +msgstr "技術用記号" -msgid " Keyword Local completion (^N^P)" -msgstr " 局所キーワード補完 (^N^P)" +msgid "Box drawing" +msgstr "罫線素片" -msgid "Hit end of paragraph" -msgstr "段落の最後にヒット" +msgid "Block elements" +msgstr "ブロック要素" -msgid "E839: Completion function changed window" -msgstr "E839: 補間関数がウィンドウを変更しました" +msgid "Geometric shapes" +msgstr "幾何学模様" -msgid "E840: Completion function deleted text" -msgstr "E840: 補完関数がテキストを削除しました" +msgid "Symbols" +msgstr "記号" -msgid "'dictionary' option is empty" -msgstr "'dictionary' オプションが空です" +msgid "Dingbats" +msgstr "装飾記号" -msgid "'thesaurus' option is empty" -msgstr "'thesaurus' オプションが空です" +msgid "CJK symbols and punctuation" +msgstr "CJK記号及び句読点" -#, c-format -msgid "Scanning dictionary: %s" -msgstr "辞書をスキャン中: %s" +msgid "Hiragana" +msgstr "平仮名" -msgid " (insert) Scroll (^E/^Y)" -msgstr " (挿入) スクロール(^E/^Y)" +msgid "Katakana" +msgstr "片仮名" -msgid " (replace) Scroll (^E/^Y)" -msgstr " (置換) スクロール (^E/^Y)" +msgid "Bopomofo" +msgstr "注音字母" -#, c-format -msgid "Scanning: %s" -msgstr "スキャン中: %s" +msgid "E544: Keymap file not found" +msgstr "E544: キーマップファイルが見つかりません" -msgid "Scanning tags." -msgstr "タグをスキャン中." +msgid "E105: Using :loadkeymap not in a sourced file" +msgstr "E105: :source で取込むファイル以外では :loadkeymap を使えません" -msgid "match in file" -msgstr "ファイル内のマッチ" +msgid "E791: Empty keymap entry" +msgstr "E791: 空のキーマップエントリ" -msgid " Adding" -msgstr " 追加中" +msgid " TERMINAL" +msgstr "端末" -msgid "-- Searching..." -msgstr "-- 検索中..." +msgid " VREPLACE" +msgstr " 仮想置換" -msgid "Back at original" -msgstr "始めに戻る" +msgid " REPLACE" +msgstr " 置換" -msgid "Word from other line" -msgstr "他の行の単語" +msgid " REVERSE" +msgstr " 反転" -msgid "The only match" -msgstr "唯一の該当" +msgid " INSERT" +msgstr " 挿入" -#, c-format -msgid "match %d of %d" -msgstr "%d 番目の該当 (全該当 %d 個中)" +msgid " (terminal)" +msgstr "(端末)" -#, c-format -msgid "match %d" -msgstr "%d 番目の該当" +msgid " (insert)" +msgstr " (挿入)" -msgid "E18: Unexpected characters in :let" -msgstr "E18: 予期せぬ文字が :let にありました" +msgid " (replace)" +msgstr " (置換)" + +msgid " (vreplace)" +msgstr " (仮想置換)" + +msgid " Arabic" +msgstr " アラビア" + +msgid " (paste)" +msgstr " (貼り付け)" + +msgid " VISUAL" +msgstr " ビジュアル" + +msgid " VISUAL LINE" +msgstr " ビジュアル 行" + +msgid " VISUAL BLOCK" +msgstr " ビジュアル 矩形" + +msgid " SELECT" +msgstr " セレクト" + +msgid " SELECT LINE" +msgstr " 行指向選択" + +msgid " SELECT BLOCK" +msgstr " 矩形選択" + +msgid "recording" +msgstr "記録中" msgid "E111: Missing ']'" msgstr "E111: ']' が見つかりません" -msgid "E719: Cannot use [:] with a Dictionary" -msgstr "E719: [:] を辞書型と組み合わせては使えません" - -msgid "E806: using Float as a String" -msgstr "E806: 浮動小数点数を文字列として扱っています" +#, c-format +msgid "E697: Missing end of List ']': %s" +msgstr "E697: リスト型の最後に ']' がありません: %s" -msgid "E687: Less targets than List items" -msgstr "E687: ターゲットがリスト型内の要素よりも少ないです" +msgid "E719: Cannot slice a Dictionary" +msgstr "E719: 辞書型はスライスできません" -msgid "E688: More targets than List items" -msgstr "E688: ターゲットがリスト型内の要素よりも多いです" +msgid "E909: Cannot index a special variable" +msgstr "E909: 特殊変数はインデックスできません" -msgid "Double ; in list of variables" -msgstr "リスト型の値に2つ以上の ; が検出されました" +msgid "E274: No white space allowed before parenthesis" +msgstr "E274: 丸括弧の前にスペースは許されません" #, c-format -msgid "E738: Can't list variables for %s" -msgstr "E738: %s の値を一覧表示できません" +msgid "E80: Error while writing: %s" +msgstr "E80: 書込み中のエラー: %s" -msgid "E689: Can only index a List or Dictionary" -msgstr "E689: リスト型と辞書型以外はインデックス指定できません" +msgid "E695: Cannot index a Funcref" +msgstr "E695: 関数参照型はインデックスできません" -msgid "E708: [:] must come last" -msgstr "E708: [:] は最後でなければいけません" +msgid "E698: Variable nested too deep for making a copy" +msgstr "E698: コピーを取るには変数の入れ子が深過ぎます" -msgid "E709: [:] requires a List value" -msgstr "E709: [:] にはリスト型の値が必要です" +msgid "E1098: String, List or Blob required" +msgstr "E1098: 文字列型、リスト型またはBlob型が必要です" -msgid "E710: List value has more items than target" -msgstr "E710: リスト型変数にターゲットよりも多い要素があります" +#, c-format +msgid "E1169: Expression too recursive: %s" +msgstr "E1169: 式の再帰が深すぎます: %s" -msgid "E711: List value has not enough items" -msgstr "E711: リスト型変数に十分な数の要素がありません" +#, c-format +msgid "E1203: Dot can only be used on a dictionary: %s" +msgstr "E1203: ドットは辞書型でのみ使用できます: %s" -msgid "E690: Missing \"in\" after :for" -msgstr "E690: :for の後に \"in\" がありません" +msgid "E1192: Empty function name" +msgstr "E1192: 関数名が空です" #, c-format -msgid "E108: No such variable: \"%s\"" -msgstr "E108: その変数はありません: \"%s\"" +msgid "E1250: Argument of %s must be a List, String, Dictionary or Blob" +msgstr "E1250: %s の引数はリスト、文字列、辞書またはBlobでなければなりません" + +msgid "" +"E5700: Expression from 'spellsuggest' must yield lists with exactly two " +"values" +msgstr "" +"E5700: 'spellsuggest'からの式は正確に2つの値を持つリストを返す必要があります" #, c-format -msgid "E940: Cannot lock or unlock variable %s" -msgstr "E940: 変数 %s はロックまたはアンロックできません" +msgid "E121: Undefined variable: %.*s" +msgstr "E121: 未定義の変数です: %.*s" -msgid "E743: variable nested too deep for (un)lock" -msgstr "E743: (アン)ロックするには変数の入れ子が深過ぎます" +msgid "E689: Can only index a List, Dictionary or Blob" +msgstr "E689: リスト型、辞書型またはBlob型のみインデックスできます" + +msgid "E708: [:] must come last" +msgstr "E708: [:] は最後でなければいけません" + +msgid "E713: Cannot use empty key after ." +msgstr "E713: . の後に空のキーを使うことはできません" + +msgid "E709: [:] requires a List or Blob value" +msgstr "E709: [:] にはリスト型かBlob型の値が必要です" + +msgid "E996: Cannot lock a range" +msgstr "E996: 範囲はロックできません" + +msgid "E996: Cannot lock a list or dict" +msgstr "E996: リストあるいは辞書はロックできません" + +msgid "E690: Missing \"in\" after :for" +msgstr "E690: :for の後に \"in\" がありません" msgid "E109: Missing ':' after '?'" msgstr "E109: '?' の後に ':' がありません" @@ -539,12 +1965,6 @@ msgstr "E110: ')' が見つかりません" msgid "E260: Missing name after ->" msgstr "E260: -> の後に名前がありません" -msgid "E695: Cannot index a Funcref" -msgstr "E695: 関数参照型はインデックスできません" - -msgid "E909: Cannot index a special variable" -msgstr "E909: 特殊変数はインデックスできません" - #, c-format msgid "E112: Option name missing: %s" msgstr "E112: オプション名がありません: %s" @@ -553,169 +1973,448 @@ msgstr "E112: オプション名がありません: %s" msgid "E113: Unknown option: %s" msgstr "E113: 未知のオプションです: %s" +msgid "E973: Blob literal should have an even number of hex characters" +msgstr "E973: Blobリテラルは偶数個の16進数文字でなければなりません" + #, c-format msgid "E114: Missing quote: %s" -msgstr "E114: 引用符 (\") がありません: %s" +msgstr "E114: クォートがありません: %s" #, c-format msgid "E115: Missing quote: %s" -msgstr "E115: 引用符 (') がありません: %s" +msgstr "E115: クォートがありません: %s" + +#, c-format +msgid "E696: Missing comma in List: %s" +msgstr "E696: リスト型にコンマがありません: %s" msgid "Not enough memory to set references, garbage collection aborted!" msgstr "" "ガーベッジコレクションを中止しました! 参照を作成するのにメモリが不足しました" -msgid "E724: variable nested too deep for displaying" -msgstr "E724: 表示するには変数の入れ子が深過ぎます" +#, c-format +msgid "E720: Missing colon in Dictionary: %s" +msgstr "E720: 辞書型にコロンがありません: %s" -msgid "E805: Using a Float as a Number" -msgstr "E805: 浮動小数点数を数値として扱っています" +#, c-format +msgid "E721: Duplicate key in Dictionary: \"%s\"" +msgstr "E721: 辞書型に重複キーがあります: \"%s\"" -msgid "E703: Using a Funcref as a Number" -msgstr "E703: 関数参照型を数値として扱っています" +#, c-format +msgid "E722: Missing comma in Dictionary: %s" +msgstr "E722: 辞書型にコンマがありません: %s" -msgid "E745: Using a List as a Number" -msgstr "E745: リスト型を数値として扱っています" +#, c-format +msgid "E723: Missing end of Dictionary '}': %s" +msgstr "E723: 辞書型の最後に '}' がありません: %s" -msgid "E728: Using a Dictionary as a Number" -msgstr "E728: 辞書型を数値として扱っています" +msgid "map() argument" +msgstr "map() の引数" -msgid "E910: Using a Job as a Number" -msgstr "E910: ジョブを数値として扱っています" +msgid "mapnew() argument" +msgstr "mapnew() の引数" -msgid "E913: Using a Channel as a Number" -msgstr "E913: チャネルを数値として扱っています" +msgid "filter() argument" +msgstr "filter() の引数" -msgid "E891: Using a Funcref as a Float" -msgstr "E891: 関数参照型を浮動小数点数として扱っています" +msgid "foreach() argument" +msgstr "foreach() の引数" -msgid "E892: Using a String as a Float" -msgstr "E892: 文字列を浮動小数点数として扱っています" +#, c-format +msgid "E700: Unknown function: %s" +msgstr "E700: 未知の関数です: %s" -msgid "E893: Using a List as a Float" -msgstr "E893: リスト型を浮動小数点数として扱っています" +msgid "E923: Second argument of function() must be a list or a dict" +msgstr "E923: function() の第 2 引数はリスト型または辞書型でなければなりません" -msgid "E894: Using a Dictionary as a Float" -msgstr "E894: 辞書型を浮動小数点数として扱っています" +msgid "E5050: {opts} must be the only argument" +msgstr "E5050: {opts} は唯一の引数でなければなりません" -msgid "E907: Using a special value as a Float" -msgstr "E907: 特殊値を浮動小数点数として扱っています" +#, c-format +msgid "Executing command: \"%s\"" +msgstr "コマンドを実行中: %s" -msgid "E911: Using a Job as a Float" -msgstr "E911: ジョブを浮動小数点数として扱っています" +msgid "E921: Invalid callback argument" +msgstr "E921: 無効なコールバック引数です" -msgid "E914: Using a Channel as a Float" -msgstr "E914: チャネルを浮動小数点数として扱っています" +msgid "" +"\n" +"\tLast set from " +msgstr "" +"\n" +"\t最後にセットしたスクリプト: " -msgid "E729: using Funcref as a String" -msgstr "E729: 関数参照型を文字列として扱っています" +msgid "E977: Can only compare Blob with Blob" +msgstr "E977: Blob型はBlob型としか比較できません" -msgid "E730: using List as a String" -msgstr "E730: リスト型を文字列として扱っています" +msgid "E691: Can only compare List with List" +msgstr "E691: リスト型はリスト型としか比較できません" -msgid "E731: using Dictionary as a String" -msgstr "E731: 辞書型を文字列として扱っています" +msgid "E692: Invalid operation for List" +msgstr "E692: リスト型には無効な操作です" -msgid "E908: using an invalid value as a String" -msgstr "E908: 無効な値を文字列として扱っています" +msgid "E735: Can only compare Dictionary with Dictionary" +msgstr "E735: 辞書型は辞書型としか比較できません" + +msgid "E736: Invalid operation for Dictionary" +msgstr "E736: 辞書型には無効な操作です" + +msgid "E694: Invalid operation for Funcrefs" +msgstr "E694: 関数参照型には無効な操作です" #, c-format -msgid "E795: Cannot delete variable %s" -msgstr "E795: 変数 %s を削除できません" +msgid "E474: Expected comma before list item: %s" +msgstr "E474: リストの要素の前にコンマが必要です: %s" #, c-format -msgid "E704: Funcref variable name must start with a capital: %s" -msgstr "E704: 関数参照型変数名は大文字で始まらなければなりません: %s" +msgid "E474: Expected colon before dictionary value: %s" +msgstr "E474: 辞書型の値の前にコロンが必要です: %s" #, c-format -msgid "E705: Variable name conflicts with existing function: %s" -msgstr "E705: 変数名が既存の関数名と衝突します: %s" +msgid "E474: Expected string key: %s" +msgstr "E474: 文字列のキーが必要です: %s" #, c-format -msgid "E741: Value is locked: %s" -msgstr "E741: 値がロックされています: %s" +msgid "E474: Expected comma before dictionary key: %s" +msgstr "E474: 辞書型のキー前ににコンマが必要です: %s" -msgid "Unknown" -msgstr "不明" +#, c-format +msgid "E474: Unfinished escape sequence: %.*s" +msgstr "E474: 不完全なエスケープシーケンス: %.*s" #, c-format -msgid "E742: Cannot change value of %s" -msgstr "E742: %s の値を変更できません" +msgid "E474: Unfinished unicode escape sequence: %.*s" +msgstr "E474: 不完全な Unicode エスケープシーケンス: %.*s" -msgid "E698: variable nested too deep for making a copy" -msgstr "E698: コピーを取るには変数の入れ子が深過ぎます" +#, c-format +msgid "E474: Expected four hex digits after \\u: %.*s" +msgstr "E474: \\uの後に4桁の16進数が必要です: %.*s" + +#, c-format +msgid "E474: Unknown escape sequence: %.*s" +msgstr "E474: 未知のエスケープシーケンス: %.*s" + +#, c-format +msgid "E474: ASCII control characters cannot be present inside string: %.*s" +msgstr "E474: ASCII 制御文字は文字列内に存在できません: %.*s" +#, c-format +msgid "E474: Only UTF-8 strings allowed: %.*s" +msgstr "E474: UTF-8 文字列のみが使用可能です: %.*s" + +#, c-format msgid "" -"\n" -"# global variables:\n" +"E474: Only UTF-8 code points up to U+10FFFF are allowed to appear unescaped: " +"%.*s" msgstr "" -"\n" -"# グローバル変数:\n" +"E474: U+10FFFF までの UTF-8 コードポイントのみがエスケープなしで表示できま" +"す: %.*s" +#, c-format +msgid "E474: Expected string end: %.*s" +msgstr "E474: \" が必要です: %.*s" + +#, c-format +msgid "E474: Leading zeroes are not allowed: %.*s" +msgstr "E474: 先頭にゼロは使用できません: %.*s" + +#, c-format +msgid "E474: Missing number after minus sign: %.*s" +msgstr "E474: マイナス記号の後に数字がありません: %.*s" + +#, c-format +msgid "E474: Missing number after decimal dot: %.*s" +msgstr "E474: 小数点の後に数字がありません: %.*s" + +#, c-format +msgid "E474: Missing exponent: %.*s" +msgstr "E474: 指数がありません: %.*s" + +#, fuzzy, c-format msgid "" -"\n" -"\tLast set from " +"E685: internal error: while converting number \"%.*s\" to float string2float " +"consumed %zu bytes in place of %zu" msgstr "" -"\n" -"\t最後にセットしたスクリプト: " +"E685: 内部エラー: 数値\"%.*s\" をfloat型に変換中 string2float は %zu を %zu " +"バイトの代わりに消費しました" -msgid "E691: Can only compare List with List" -msgstr "E691: リスト型はリスト型としか比較できません" +#, fuzzy, c-format +msgid "" +"E685: internal error: while converting number \"%.*s\" to integer vim_str2nr " +"consumed %i bytes in place of %zu" +msgstr "" +"E685: 内部エラー: 数値\"%.*s\" をint型に変換中 vim_str2nr は %zu の代わりに " +"%i バイトを消費しました" -msgid "E692: Invalid operation for List" -msgstr "E692: リスト型には無効な操作です" +msgid "E474: Attempt to decode a blank string" +msgstr "E474: 空の文字列のデコードを試みました" -msgid "E735: Can only compare Dictionary with Dictionary" -msgstr "E735: 辞書型は辞書型としか比較できません" +#, c-format +msgid "E474: No container to close: %.*s" +msgstr "E474: 閉じるコンテナがありません: %.*s" -msgid "E736: Invalid operation for Dictionary" -msgstr "E736: 辞書型には無効な操作です" +#, c-format +msgid "E474: Closing list with curly bracket: %.*s" +msgstr "E474: リスト型を波括弧で閉じています: %.*s" -msgid "E694: Invalid operation for Funcrefs" -msgstr "E694: 関数参照型には無効な操作です" +#, c-format +msgid "E474: Closing dictionary with square bracket: %.*s" +msgstr "E474: 辞書型を角括弧で閉じています: %.*s" #, c-format -msgid "E686: Argument of %s must be a List" -msgstr "E686: %s の引数はリスト型でなければなりません" +msgid "E474: Trailing comma: %.*s" +msgstr "E474: 余分なコンマが後ろにあります: %.*s" -msgid "E808: Number or Float required" -msgstr "E808: 数値か浮動小数点数が必要です" +#, c-format +msgid "E474: Expected value after colon: %.*s" +msgstr "E474: コロンの後に値が必要です: %.*s" -msgid "E785: complete() can only be used in Insert mode" -msgstr "E785: complete() は挿入モードでしか利用できません" +#, c-format +msgid "E474: Expected value: %.*s" +msgstr "E474: 値が必要です: %.*s" -msgid "&Ok" -msgstr "&Ok" +#, c-format +msgid "E474: Comma not inside container: %.*s" +msgstr "E474: コンマがコンテナ内にありません: %.*s" #, c-format -msgid "E700: Unknown function: %s" -msgstr "E700: 未知の関数です: %s" +msgid "E474: Duplicate comma: %.*s" +msgstr "E474: コンマが重複しています: %.*s" -msgid "E922: expected a dict" -msgstr "E922: 辞書が期待されています" +#, c-format +msgid "E474: Comma after colon: %.*s" +msgstr "E474: コロンの後にコンマがあります: %.*s" -msgid "E923: Second argument of function() must be a list or a dict" -msgstr "E923: function() の第 2 引数はリスト型または辞書型でなければなりません" +#, c-format +msgid "E474: Using comma in place of colon: %.*s" +msgstr "E474: コロンではなくコンマを使用しています: %.*s" + +#, c-format +msgid "E474: Leading comma: %.*s" +msgstr "E474: 余分なコンマが前にあります: %.*s" + +#, c-format +msgid "E474: Colon not inside container: %.*s" +msgstr "E474: コロンがコンテナ内にありません: %.*s" + +#, c-format +msgid "E474: Using colon not in dictionary: %.*s" +msgstr "E474: 辞書にないコロンを使用しています: %.*s" + +#, c-format +msgid "E474: Unexpected colon: %.*s" +msgstr "E474: 予期しないコロンです: %.*s" + +#, c-format +msgid "E474: Colon after comma: %.*s" +msgstr "E474: コンマの後にコロンがあります: %.*s" + +#, c-format +msgid "E474: Duplicate colon: %.*s" +msgstr "E474: コロンが重複しています: %.*s" + +#, c-format +msgid "E474: Expected null: %.*s" +msgstr "E474: null が必要です: %.*s" + +#, c-format +msgid "E474: Expected true: %.*s" +msgstr "E474: true が必要です: %.*s" +#, c-format +msgid "E474: Expected false: %.*s" +msgstr "E474: false が必要です: %.*s" + +#, c-format +msgid "E474: Unidentified byte: %.*s" +msgstr "E474: 未定義のバイトです: %.*s" + +#, c-format +msgid "E474: Trailing characters: %.*s" +msgstr "E474: 余分な文字が後ろにあります: %.*s" + +#, c-format +msgid "E474: Unexpected end of input: %.*s" +msgstr "E474: 予期しない入力の終了: %.*s" + +#, c-format +msgid "key %s" +msgstr "キー %s" + +#, fuzzy, c-format +#~ msgid "key %s at index %i from special map" +#~ msgstr "カスタムマップからのインデックス %i のキー %s" + +#, c-format +msgid "index %i" +msgstr "インデックス %i" + +msgid "partial" +msgstr "部分的" + +#, c-format +msgid "argument %i" +msgstr "引数 %i" + +#, fuzzy +#~ msgid "partial self dictionary" +#~ msgstr "部分的なセルフ辞書" + +#, fuzzy +#~ msgid "itself" +#~ msgstr "自身" + +msgid "E724: unable to correctly dump variable with self-referencing container" +msgstr "E724: 自らを参照するコンテナの変数を正しくダンプできませんでした" + +msgid "E474: Unable to represent NaN value in JSON" +msgstr "E474: JSON は NaN に対応していません" + +msgid "E474: Unable to represent infinity in JSON" +msgstr "E474: JSON は無限大に対応していません" + +#, c-format msgid "" -"&OK\n" -"&Cancel" +"E474: String \"%.*s\" contains byte that does not start any UTF-8 character" msgstr "" -"決定(&O)\n" -"キャンセル(&C)" +"E474: 文字列 \"%.*s\" には UTF-8 文字で始まらないバイトが含まれています" + +#, c-format +msgid "" +"E474: UTF-8 string contains code point which belongs to a surrogate pair: " +"%.*s" +msgstr "" +"E474: UTF-8 文字列にサロゲートペアに属するコードポイントが含まれています: " +"%.*s" + +msgid "E474: Unable to convert EXT string to JSON" +msgstr "E474: EXT 文字列を JSON に変換できません" + +#, c-format +msgid "E474: Error while dumping %s, %s: attempt to dump function reference" +msgstr "" +"E474: %s のダンプ中にエラーが発生しました, %s: 関数参照をダンプしようとしまし" +"た" + +msgid "E474: Invalid key in special dictionary" +msgstr "E474: ユーザー辞書のキーが無効です" + +msgid "encode_tv2string() argument" +msgstr "encode_tv2string() の引数" + +msgid ":echo argument" +msgstr ":echo の引数" + +msgid "encode_tv2json() argument" +msgstr "encode_tv2json() の引数" + +#, c-format +msgid "E5004: Error while dumping %s, %s: attempt to dump function reference" +msgstr "" +"E5004: %s のダンプ中にエラーが発生しました, %s: 関数参照をダンプしようとしま" +"した" + +#, c-format +msgid "E5005: Unable to dump %s: container references itself in %s" +msgstr "E5005: %s をダンプできません: コンテナは %s で自身を参照しています" + +#, c-format +msgid "E684: List index out of range: %<PRId64>" +msgstr "E684: リストのインデックスが範囲外です: %<PRId64>" + +#, c-format +msgid "E899: Argument of %s must be a List or Blob" +msgstr "E899: %s の引数はリスト型またはBlob型でなければなりません" + +msgid "E957: Invalid window number" +msgstr "E957: 無効なウィンドウ番号です" + +#, c-format +msgid "E706: Argument of %s must be a List, String or Dictionary" +msgstr "E706: %s の引数はリスト型、文字列または辞書型でなければなりません" + +#, c-format +msgid "E935: Invalid submatch number: %d" +msgstr "E935: 無効なサブマッチ番号です: %d" + +#, c-format +msgid "E998: Reduce of an empty %s with no initial value" +msgstr "E998: reduce が初期値無しで空の %s で呼ばれました" + +msgid "E1132: Missing function argument" +msgstr "E1132: 引数に関数がありません" + +msgid "add() argument" +msgstr "add() の引数" + +#, c-format +msgid "E158: Invalid buffer name: %s" +msgstr "E158: 無効なバッファ名です: %s" + +#, c-format +msgid "Invalid channel stream \"%s\"" +msgstr "無効なチャネル ストリーム \"%s\"" + +msgid "&Ok" +msgstr "&Ok" + +msgid "Context stack is empty" +msgstr "コンテキストスタックは空です" + +msgid "dictwatcheradd() argument" +msgstr "dictwatcheradd() の引数" + +msgid "E900: maxdepth must be non-negative number" +msgstr "E900: maxdepth は非負数でなければなりません" + +msgid "flatten() argument" +msgstr "flatten() の引数" + +msgid "extend() argument" +msgstr "extend() の引数" + +msgid "extendnew() argument" +msgstr "extendnew() の引数" + +msgid "E5000: Cannot find tab number." +msgstr "E5000: タブ番号が見つかりません" + +#, fuzzy +#~ msgid "E5001: Higher scope cannot be -1 if lower scope is >= 0." +#~ msgstr "E5001: 低いスコープが 0 以上の場合高いスコープは -1 を指定できません" + +msgid "E5002: Cannot find window number." +msgstr "E5002: ウィンドウ番号が見つかりません" msgid "called inputrestore() more often than inputsave()" msgstr "inputrestore() が inputsave() よりも多く呼ばれました" +msgid "insert() argument" +msgstr "insert() の引数" + msgid "E786: Range not allowed" msgstr "E786: 範囲指定は許可されていません" +msgid "E474: Failed to convert list to string" +msgstr "E474: リスト型の文字列への変換に失敗しました" + +#, c-format +msgid "E474: Failed to parse %.*s" +msgstr "E474: 構文解析に失敗しました: %.*s" + msgid "E701: Invalid type for len()" msgstr "E701: len() には無効な型です" +#, fuzzy, c-format +#~ msgid "msgpackdump() argument, index %i" +#~ msgstr "msgpackdump() の引数, インデックス %i" + +msgid "E5070: Character number must not be less than zero" +msgstr "E5070: 文字番号は 0 未満でなければなりません" + #, c-format -msgid "E798: ID is reserved for \":match\": %ld" -msgstr "E798: ID は \":match\" のために予約されています: %ld" +msgid "E5071: Character number must not be greater than INT_MAX (%i)" +msgstr "E5071: 文字番号は INT_MAX (%i) より大きくてはなりません" msgid "E726: Stride is zero" msgstr "E726: ストライド(前進量)が 0 です" @@ -726,490 +2425,730 @@ msgstr "E727: 開始位置が終了位置を越えました" msgid "<empty>" msgstr "<空>" -msgid "E240: No connection to the X server" -msgstr "E240: X サーバーへの接続がありません" +msgid "remove() argument" +msgstr "remove() の引数" -#, c-format -msgid "E241: Unable to send to %s" -msgstr "E241: %s へ送ることができません" +msgid "E655: Too many symbolic links (cycle?)" +msgstr "E655: シンボリックリンクが多過ぎます (循環している可能性があります)" -msgid "E277: Unable to read a server reply" -msgstr "E277: サーバーの応答がありません" +msgid "reverse() argument" +msgstr "reverse() の引数" -msgid "E941: already started a server" -msgstr "E941: サーバーはすでに開始しています" +#, fuzzy, c-format +#~ msgid "E5010: List item %d of the second argument is not a string" +#~ msgstr "E5010: リスト項目 %d の二つ目の引数は文字列ではありません" -msgid "E942: +clientserver feature not available" -msgstr "E942: +clientserver 機能が無効になっています" +#, c-format +msgid "E962: Invalid action: '%s'" +msgstr "E962: 無効な操作です: '%s'" -# Added at 10-Mar-2004. -msgid "E655: Too many symbolic links (cycle?)" -msgstr "E655: シンボリックリンクが多過ぎます (循環している可能性があります)" +#, c-format +msgid "connection failed: %s" +msgstr "接続に失敗しました: %s" -msgid "E258: Unable to send to client" -msgstr "E258: クライアントへ送ることができません" +#, c-format +msgid "E6100: \"%s\" is not a valid stdpath" +msgstr "E6100: \"%s\" は有効な stdpath ではありません" msgid "(Invalid)" msgstr "(無効)" +msgid "Can only call this function in an unmodified buffer" +msgstr "この関数は未変更のバッファ内でのみ呼び出すことができます" + +msgid "writefile() first argument must be a List or a Blob" +msgstr "writefile() の第1引数はリスト型またはBlob型でなければなりません" + #, c-format -msgid "E935: invalid submatch number: %d" -msgstr "E935: 無効なサブマッチ番号: %d" +msgid "E5060: Unknown flag: %s" +msgstr "E5060: 未知のフラグ: %s" -msgid "E921: Invalid callback argument" -msgstr "E921: 無効なコールバック引数です" +msgid "E482: Can't open file with an empty name" +msgstr "E482: 空の名前のファイルは開けません" #, c-format -msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s" -msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o, ダイグラフ %s" +msgid "E482: Can't open file %s for writing: %s" +msgstr "E482: %s を書込み用として開けません: %s" #, c-format -msgid "<%s>%s%s %d, Hex %02x, Octal %03o" -msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o" +msgid "E80: Error when closing file %s: %s" +msgstr "E80: %s を閉じる時にエラーです: %s" + +msgid "E743: Variable nested too deep for (un)lock" +msgstr "E743: (アン)ロックするには変数の入れ子が深過ぎます" + +msgid "E908: Using an invalid value as a String" +msgstr "E908: 無効な値を文字列として扱っています" #, c-format -msgid "> %d, Hex %04x, Oct %o, Digr %s" -msgstr "> %d, 16進数 %04x, 8進数 %o, ダイグラフ %s" +msgid "E1174: String required for argument %d" +msgstr "E1174: 引数 %d には文字列が必要です" #, c-format -msgid "> %d, Hex %08x, Oct %o, Digr %s" -msgstr "> %d, 16進数 %08x, 8進数 %o, ダイグラフ %s" +msgid "E1175: Non-empty string required for argument %d" +msgstr "E1175: 引数 %d には空ではない文字列が必要です" #, c-format -msgid "> %d, Hex %04x, Octal %o" -msgstr "> %d, 16進数 %04x, 8進数 %o" +msgid "E1206: Dictionary required for argument %d" +msgstr "E1206: 引数 %d には辞書型が必要です" #, c-format -msgid "> %d, Hex %08x, Octal %o" -msgstr "> %d, 16進数 %08x, 8進数 %o" +msgid "E1210: Number required for argument %d" +msgstr "E1210: 引数 %d には数値が必要です" -msgid "E134: Move lines into themselves" -msgstr "E134: 行をそれ自身には移動できません" +#, c-format +msgid "E1211: List required for argument %d" +msgstr "E1211: 引数 %d にはリスト型が必要です" -msgid "1 line moved" -msgstr "1 行が移動されました" +#, c-format +msgid "E1212: Bool required for argument %d" +msgstr "E1212: 引数 %d にはBool型が必要です" #, c-format -msgid "%ld lines moved" -msgstr "%ld 行が移動されました" +msgid "E1219: Float or Number required for argument %d" +msgstr "E1219: 引数 %d には浮動小数点数または数値が必要です" #, c-format -msgid "%ld lines filtered" -msgstr "%ld 行がフィルタ処理されました" +msgid "E1220: String or Number required for argument %d" +msgstr "E1220: 引数 %d には文字列または数値が必要です" -msgid "E135: *Filter* Autocommands must not change current buffer" -msgstr "E135: *フィルタ* autocommandは現在のバッファを変更してはいけません" +#, c-format +msgid "E1222: String or List required for argument %d" +msgstr "E1222: 引数 %d には文字列またはリスト型が必要です" -msgid "[No write since last change]\n" -msgstr "[最後の変更が保存されていません]\n" +#, c-format +msgid "E1226: List or Blob required for argument %d" +msgstr "E1226: 引数 %d にはリスト型またはBlob型が必要です" -msgid "Save As" -msgstr "別名で保存" +#, c-format +msgid "E1238: Blob required for argument %d" +msgstr "E1238: 引数 %d にはBlob型が必要です" -msgid "Write partial file?" -msgstr "ファイルを部分的に保存しますか?" +#, c-format +msgid "E1239: Invalid value for blob: %d" +msgstr "E1239: blobとして無効な値です: %d" -msgid "E140: Use ! to write partial buffer" -msgstr "E140: バッファを部分的に保存するには ! を使ってください" +#, c-format +msgid "E1252: String, List or Blob required for argument %d" +msgstr "E1252: 引数 %d には文字列、リスト型またはBlob型が必要です" #, c-format -msgid "Overwrite existing file \"%s\"?" -msgstr "既存のファイル \"%s\" を上書きしますか?" +msgid "E1256: String or function required for argument %d" +msgstr "E1256: 引数 %d には文字列または関数が必要です" #, c-format -msgid "Swap file \"%s\" exists, overwrite anyway?" -msgstr "スワップファイル \"%s\" が存在します。上書きを強制しますか?" +msgid "E1297: Non-NULL Dictionary required for argument %d" +msgstr "E1297: 引数 %d には非NULLの辞書が必要です" + +msgid "E710: List value has more items than target" +msgstr "E710: リスト型変数にターゲットよりも多い要素があります" + +msgid "E711: List value has not enough items" +msgstr "E711: リスト型変数に十分な数の要素がありません" + +msgid "E702: Sort compare function failed" +msgstr "E702: ソートの比較関数が失敗しました" + +msgid "E882: Uniq compare function failed" +msgstr "E882: Uniq の比較関数が失敗しました" + +msgid "sort() argument" +msgstr "sort() の引数" + +msgid "uniq() argument" +msgstr "uniq() の引数" + +msgid "E6000: Argument is not a function or function name" +msgstr "E6000: 引数は関数または関数名ではありません" #, c-format -msgid "E768: Swap file exists: %s (:silent! overrides)" -msgstr "E768: スワップファイルが存在します: %s (:silent! を追加で上書)" +msgid "E737: Key already exists: %s" +msgstr "E737: キーは既に存在します: %s" + +msgid "E972: Blob value does not have the right number of bytes" +msgstr "E972: Blob値のバイト数が正しくありません" #, c-format -msgid "E141: No file name for buffer %ld" -msgstr "E141: バッファ %ld には名前がありません" +msgid "E741: Value is locked: %.*s" +msgstr "E741: 値がロックされています: %.*s" -msgid "E142: File not written: Writing is disabled by 'write' option" -msgstr "E142: ファイルは保存されませんでした: 'write' オプションにより無効です" +#, c-format +msgid "E742: Cannot change value of %.*s" +msgstr "E742: %.*s の値を変更できません" + +msgid "Unknown" +msgstr "不明" + +msgid "E805: Expected a Number or a String, Float found" +msgstr "E805: 数値か文字列が必要ですが、浮動小数点数が見つかりました" + +msgid "E703: Expected a Number or a String, Funcref found" +msgstr "E703: 数値か文字列が必要ですが、関数参照型が見つかりました" + +msgid "E745: Expected a Number or a String, List found" +msgstr "E745: 数値か文字列が必要ですが、リスト型が見つかりました" + +msgid "E728: Expected a Number or a String, Dictionary found" +msgstr "E728: 数値か文字列が必要ですが、辞書型が見つかりました" + +msgid "E974: Expected a Number or a String, Blob found" +msgstr "E974: 数値か文字列が必要ですが、Blob型が見つかりました" + +msgid "E5299: Expected a Number or a String, Boolean found" +msgstr "E5299: 数値か文字列が必要ですが、論理型が見つかりました" + +msgid "E5300: Expected a Number or a String" +msgstr "E5300: 数値か文字列が必要です" + +msgid "E745: Using a List as a Number" +msgstr "E745: リスト型を数値として扱っています" + +msgid "E728: Using a Dictionary as a Number" +msgstr "E728: 辞書型を数値として扱っています" + +msgid "E805: Using a Float as a Number" +msgstr "E805: 浮動小数点数を数値として扱っています" + +msgid "E974: Using a Blob as a Number" +msgstr "E974: Blob型を数値として扱っています" + +msgid "E685: using an invalid value as a Number" +msgstr "E685: 無効な値を数字として扱っています" + +msgid "E730: Using a List as a String" +msgstr "E730: リスト型を文字列として扱っています" + +msgid "E731: Using a Dictionary as a String" +msgstr "E731: 辞書型を文字列として扱っています" + +msgid "E976: Using a Blob as a String" +msgstr "E976: Blob型を文字列として扱っています" + +msgid "E891: Using a Funcref as a Float" +msgstr "E891: 関数参照型を浮動小数点数として扱っています" + +msgid "E892: Using a String as a Float" +msgstr "E892: 文字列を浮動小数点数として扱っています" + +msgid "E893: Using a List as a Float" +msgstr "E893: リスト型を浮動小数点数として扱っています" + +msgid "E894: Using a Dictionary as a Float" +msgstr "E894: 辞書型を浮動小数点数として扱っています" + +msgid "E362: Using a boolean value as a Float" +msgstr "E362: ブール値を浮動小数点数として扱っています" + +msgid "E907: Using a special value as a Float" +msgstr "E907: 特殊値を浮動小数点数として扱っています" + +msgid "E975: Using a Blob as a Float" +msgstr "E975: Blob型を浮動小数点数として扱っています" + +msgid "E808: Number or Float required" +msgstr "E808: 数値か浮動小数点数が必要です" #, c-format -msgid "" -"'readonly' option is set for \"%s\".\n" -"Do you wish to write anyway?" -msgstr "" -"\"%s\" には 'readonly' オプションが設定されています.\n" -"上書き強制をしますか?" +msgid "E117: Unknown function: %s" +msgstr "E117: 未知の関数です: %s" #, c-format -msgid "" -"File permissions of \"%s\" are read-only.\n" -"It may still be possible to write it.\n" -"Do you wish to try?" -msgstr "" -"ファイル \"%s\" のパーミッションが読込専用です.\n" -"それでも恐らく書き込むことは可能です.\n" -"継続しますか?" +msgid "E122: Function %s already exists, add ! to replace it" +msgstr "E122: 関数 %s は定義済です、再定義するには ! を追加してください" + +msgid "E717: Dictionary entry already exists" +msgstr "E717: 辞書型内にエントリが既に存在します" + +msgid "E718: Funcref required" +msgstr "E718: 関数参照型が要求されます" #, c-format -msgid "E505: \"%s\" is read-only (add ! to override)" -msgstr "E505: \"%s\" は読込専用です (強制書込には ! を追加)" +msgid "E130: Unknown function: %s" +msgstr "E130: 未知の関数です: %s" -msgid "Edit File" -msgstr "ファイルを編集" +msgid "E454: Function list was modified" +msgstr "E454: 関数リストが変更されました" + +msgid "E1058: Function nesting too deep" +msgstr "E1058: 関数の入れ子が深過ぎます" #, c-format -msgid "E143: Autocommands unexpectedly deleted new buffer %s" -msgstr "E143: autocommandが予期せず新しいバッファ %s を削除しました" +msgid "E1068: No white space allowed before '%s': %s" +msgstr "E1068: '%s' の前にスペースは許されません: %s" -msgid "E144: non-numeric argument to :z" -msgstr "E144: 数ではない引数が :z に渡されました" +#, c-format +msgid "E1145: Missing heredoc end marker: %s" +msgstr "E1145: heredocの終端マーカーがありません '%s'" -msgid "E146: Regular expressions can't be delimited by letters" -msgstr "E146: 正規表現は文字で区切ることができません" +msgid "E1300: Cannot use a partial with dictionary for :defer" +msgstr "E1300: :defer で辞書付き部分適用は使用できません" #, c-format -msgid "replace with %s (y/n/a/q/l/^E/^Y)?" -msgstr "%s に置換しますか? (y/n/a/q/l/^E/^Y)" +msgid "E125: Illegal argument: %s" +msgstr "E125: 不正な引数です: %s" -msgid "(Interrupted) " -msgstr "(割込まれました) " +#, c-format +msgid "E853: Duplicate argument name: %s" +msgstr "E853: 引数名が重複しています: %s" -msgid "1 match" -msgstr "1 箇所該当しました" +msgid "E989: Non-default argument follows default argument" +msgstr "E989: 非デフォルト引数がデフォルト引数の後にあります" -msgid "1 substitution" -msgstr "1 箇所置換しました" +#, c-format +msgid "E451: Expected }: %s" +msgstr "E451: } が必要です: %s" #, c-format -msgid "%ld matches" -msgstr "%ld 箇所該当しました" +msgid "E740: Too many arguments for function %s" +msgstr "E740: 関数の引数が多過ぎます: %s" #, c-format -msgid "%ld substitutions" -msgstr "%ld 箇所置換しました" +msgid "E116: Invalid arguments for function %s" +msgstr "E116: 関数の無効な引数です: %s" -msgid " on 1 line" -msgstr " (計 1 行内)" +msgid "E132: Function call depth is higher than 'maxfuncdepth'" +msgstr "E132: 関数呼出しの入れ子数が 'maxfuncdepth' を超えました" #, c-format -msgid " on %ld lines" -msgstr " (計 %ld 行内)" +msgid "calling %s" +msgstr "%s を実行中です" -msgid "E147: Cannot do :global recursive with a range" -msgstr "E147: :global を範囲付きで再帰的には使えません" +#, c-format +msgid "%s aborted" +msgstr "%s が中断されました" -msgid "E148: Regular expression missing from global" -msgstr "E148: globalコマンドに正規表現が指定されていません" +#, c-format +msgid "%s returning #%<PRId64>" +msgstr "%s が #%<PRId64> を返しました" #, c-format -msgid "Pattern found in every line: %s" -msgstr "パターンが全ての行で見つかりました: %s" +msgid "%s returning %s" +msgstr "%s が %s を返しました" #, c-format -msgid "Pattern not found: %s" -msgstr "パターンは見つかりませんでした: %s" +msgid "continuing in %s" +msgstr "%s の実行を継続中です" -msgid "E478: Don't panic!" -msgstr "E478: 慌てないでください" +msgid "E699: Too many arguments" +msgstr "E699: 引数が多過ぎます" #, c-format -msgid "E661: Sorry, no '%s' help for %s" -msgstr "E661: 残念ですが '%s' のヘルプが %s にはありません" +msgid "E276: Cannot use function as a method: %s" +msgstr "E276: 関数をメソッドとして使用できません: %s" #, c-format -msgid "E149: Sorry, no help for %s" -msgstr "E149: 残念ですが %s にはヘルプがありません" +msgid "E933: Function was deleted: %s" +msgstr "E933: 関数は削除されました: %s" #, c-format -msgid "Sorry, help file \"%s\" not found" -msgstr "残念ですがヘルプファイル \"%s\" が見つかりません" +msgid "E120: Using <SID> not in a script context: %s" +msgstr "E120: スクリプト以外で<SID>が使われました: %s" #, c-format -msgid "E151: No match: %s" -msgstr "E151: マッチはありません: %s" +msgid "E725: Calling dict function without Dictionary: %s" +msgstr "E725: 辞書用関数が呼ばれましたが辞書がありません: %s" + +msgid "E129: Function name required" +msgstr "E129: 関数名が要求されます" #, c-format -msgid "E152: Cannot open %s for writing" -msgstr "E152: 書込み用に %s を開けません" +msgid "E128: Function name must start with a capital or \"s:\": %s" +msgstr "E128: 関数名は大文字か \"s:\" で始まらなければなりません: %s" #, c-format -msgid "E153: Unable to open %s for reading" -msgstr "E153: 読込用に %s を開けません" +msgid "E884: Function name cannot contain a colon: %s" +msgstr "E884: 関数名にはコロンは含められません: %s" -# Added at 29-Apr-2004. #, c-format -msgid "E670: Mix of help file encodings within a language: %s" -msgstr "E670: 1つの言語のヘルプファイルに複数のエンコードが混在しています: %s" +msgid "E123: Undefined function: %s" +msgstr "E123: 未定義の関数です: %s" #, c-format -msgid "E154: Duplicate tag \"%s\" in file %s/%s" -msgstr "E154: タグ \"%s\" がファイル %s/%s に重複しています" +msgid "E124: Missing '(': %s" +msgstr "E124: '(' がありません: %s" + +msgid "E862: Cannot use g: here" +msgstr "E862: ここでは g: は使えません" #, c-format -msgid "E150: Not a directory: %s" -msgstr "E150: ディレクトリではありません: %s" +msgid "E932: Closure function should not be at top level: %s" +msgstr "E932: クロージャー関数はトップレベルに記述できません: %s" + +msgid "E126: Missing :endfunction" +msgstr "E126: :endfunction がありません" #, c-format -msgid "E160: Unknown sign command: %s" -msgstr "E160: 未知のsignコマンドです: %s" +msgid "W22: Text found after :endfunction: %s" +msgstr "W22: :endfunction の後に文字があります: %s" -msgid "E156: Missing sign name" -msgstr "E156: sign名がありません" +#, c-format +msgid "E707: Function name conflicts with variable: %s" +msgstr "E707: 関数名が変数名と衝突します: %s" -msgid "E612: Too many signs defined" -msgstr "E612: signの定義が多数見つかりました" +#, c-format +msgid "E127: Cannot redefine function %s: It is in use" +msgstr "E127: 関数 %s を再定義できません: 使用中です" #, c-format -msgid "E239: Invalid sign text: %s" -msgstr "E239: 無効なsignのテキストです: %s" +msgid "E746: Function name does not match script file name: %s" +msgstr "E746: 関数名がスクリプトのファイル名と一致しません: %s" #, c-format -msgid "E155: Unknown sign: %s" -msgstr "E155: 未知のsignです: %s" +msgid "E131: Cannot delete function %s: It is in use" +msgstr "E131: 関数 %s を削除できません: 使用中です" -msgid "E159: Missing sign number" -msgstr "E159: signの番号がありません" +#, c-format +msgid "Cannot delete function %s: It is being used internally" +msgstr "関数 %s を削除できません: 使用中です" + +msgid "E133: :return not inside a function" +msgstr "E133: 関数外に :return がありました" + +msgid "E18: Unexpected characters in :let" +msgstr "E18: 予期せぬ文字が :let にありました" #, c-format -msgid "E158: Invalid buffer name: %s" -msgstr "E158: 無効なバッファ名です: %s" +msgid "E940: Cannot lock or unlock variable %s" +msgstr "E940: 変数 %s はロックまたはアンロックできません" -msgid "E934: Cannot jump to a buffer that does not have a name" -msgstr "E934: 名前の無いバッファへはジャンプできません" +#, c-format +msgid "E963: Setting v:%s to value with wrong type" +msgstr "E963: v:%s を間違った型の値で設定しています" + +msgid "E991: Cannot use =<< here" +msgstr "E991: ここでは =<< は使えません" + +msgid "E221: Marker cannot start with lower case letter" +msgstr "E221: マーカーは英小文字で始まってはいけません" + +msgid "E172: Missing marker" +msgstr "E172: マーカーがありません" #, c-format -msgid "E157: Invalid sign ID: %ld" -msgstr "E157: 無効なsign識別子です: %ld" +msgid "E990: Missing end marker '%s'" +msgstr "E990: 終端マーカーがありません '%s'" + +msgid "E687: Less targets than List items" +msgstr "E687: ターゲットがリスト型内の要素よりも少ないです" + +msgid "E688: More targets than List items" +msgstr "E688: ターゲットがリスト型内の要素よりも多いです" + +msgid "E452: Double ; in list of variables" +msgstr "E452: リスト型の値に2つ以上の ; が検出されました" #, c-format -msgid "E885: Not possible to change sign %s" -msgstr "E885: 変更できない sign です: %s" +msgid "E738: Can't list variables for %s" +msgstr "E738: %s の値を一覧表示できません" -# Added at 27-Jan-2004. -msgid " (NOT FOUND)" -msgstr " (見つかりません)" +msgid "E996: Cannot lock an environment variable" +msgstr "E996: 環境変数はロックできません" -msgid " (not supported)" -msgstr " (非サポート)" +msgid "E996: Cannot lock an option" +msgstr "E996: オプションはロックできません" -msgid "[Deleted]" -msgstr "[削除済]" +msgid "E996: Cannot lock a register" +msgstr "E996: レジスタはロックできません" -msgid "No old files" -msgstr "古いファイルはありません" +#, c-format +msgid "E108: No such variable: \"%s\"" +msgstr "E108: その変数はありません: \"%s\"" -msgid "Entering Debug mode. Type \"cont\" to continue." -msgstr "デバッグモードに入ります. 続けるには \"cont\" と入力してください." +#, c-format +msgid "E794: Cannot set variable in the sandbox: \"%.*s\"" +msgstr "E794: サンドボックスでは変数 \"%.*s\" に値を設定できません" #, c-format -msgid "Oldval = \"%s\"" -msgstr "古い値 = \"%s\"" +msgid "E1122: Variable is locked: %*s" +msgstr "E1122: 変数がロックされています: %*s" #, c-format -msgid "Newval = \"%s\"" -msgstr "新しい値 = \"%s\"" +msgid "E795: Cannot delete variable %.*s" +msgstr "E795: 変数 %.*s を削除できません" #, c-format -msgid "line %ld: %s" -msgstr "行 %ld: %s" +msgid "E704: Funcref variable name must start with a capital: %s" +msgstr "E704: 関数参照型変数名は大文字で始まらなければなりません: %s" #, c-format -msgid "cmd: %s" -msgstr "コマンド: %s" +msgid "E705: Variable name conflicts with existing function: %s" +msgstr "E705: 変数名が既存の関数名と衝突します: %s" -msgid "frame is zero" -msgstr "フレームが 0 です" +#, c-format +msgid "E521: Number required: &%s = '%s'" +msgstr "E521: 数字が必要です: &%s = '%s'" + +msgid "E1308: Cannot resize a window in another tab page" +msgstr "E1308: 別のタブページのウィンドウをリサイズできません" + +msgid "tcp address must be host:port" +msgstr "TCP アドレスは ホスト名:ポート番号 でなければなりません" + +msgid "failed to lookup host or port" +msgstr "ホストまたはポートの検索に失敗しました" + +msgid "connection refused" +msgstr "接続が拒否されました" + +msgid "E144: Non-numeric argument to :z" +msgstr "E144: 数ではない引数が :z に渡されました" #, c-format -msgid "frame at highest level: %d" -msgstr "最高レベルのフレーム: %d" +msgid "<%s>%s%s %d, Hex %02x, Oct %03o, Digr %s" +msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o, ダイグラフ %s" #, c-format -msgid "Breakpoint in \"%s%s\" line %ld" -msgstr "ブレークポイント \"%s%s\" 行 %ld" +msgid "<%s>%s%s %d, Hex %02x, Octal %03o" +msgstr "<%s>%s%s %d, 16進数 %02x, 8進数 %03o" #, c-format -msgid "E161: Breakpoint not found: %s" -msgstr "E161: ブレークポイントが見つかりません: %s" +msgid "> %d, Hex %04x, Oct %o, Digr %s" +msgstr "> %d, 16進数 %04x, 8進数 %o, ダイグラフ %s" -msgid "No breakpoints defined" -msgstr "ブレークポイントが定義されていません" +#, c-format +msgid "> %d, Hex %08x, Oct %o, Digr %s" +msgstr "> %d, 16進数 %08x, 8進数 %o, ダイグラフ %s" #, c-format -msgid "%3d %s %s line %ld" -msgstr "%3d %s %s 行 %ld" +msgid "> %d, Hex %04x, Octal %o" +msgstr "> %d, 16進数 %04x, 8進数 %o" #, c-format -msgid "%3d expr %s" -msgstr "%3d expr %s" +msgid "> %d, Hex %08x, Octal %o" +msgstr "> %d, 16進数 %08x, 8進数 %o" -msgid "E750: First use \":profile start {fname}\"" -msgstr "E750: 初めに \":profile start {fname}\" を実行してください" +msgid "E134: Cannot move a range of lines into itself" +msgstr "E134: 行の範囲をそれ自身には移動できません" #, c-format -msgid "Save changes to \"%s\"?" -msgstr "変更を \"%s\" に保存しますか?" +msgid "%<PRId64> line moved" +msgid_plural "%<PRId64> lines moved" +msgstr[0] "%<PRId64> 行が移動されました" #, c-format -msgid "E947: Job still running in buffer \"%s\"" -msgstr "E947: ジョブはバッファ \"%s\" でまだ実行中です" +msgid "E482: Can't create file %s" +msgstr "E482: ファイル %s を作成できません" #, c-format -msgid "E162: No write since last change for buffer \"%s\"" -msgstr "E162: バッファ \"%s\" の変更は保存されていません" +msgid "%<PRId64> lines filtered" +msgstr "%<PRId64> 行がフィルタ処理されました" -msgid "Warning: Entered other buffer unexpectedly (check autocommands)" -msgstr "警告: 予期せず他バッファへ移動しました (autocommands を調べてください)" +msgid "E135: *Filter* Autocommands must not change current buffer" +msgstr "E135: *Filter* 自動コマンドは現在のバッファを変更してはいけません" -msgid "E163: There is only one file to edit" -msgstr "E163: 編集するファイルは1つしかありません" +msgid "[No write since last change]\n" +msgstr "[最後の変更が保存されていません]\n" -msgid "E164: Cannot go before first file" -msgstr "E164: 最初のファイルより前には行けません" +#, c-format +msgid "E503: \"%s\" is not a file or writable device" +msgstr "E503: \"%s\" はファイルでも書込み可能デバイスでもありません" -msgid "E165: Cannot go beyond last file" -msgstr "E165: 最後のファイルを越えて後には行けません" +msgid "Write partial file?" +msgstr "ファイルを部分的に保存しますか?" + +msgid "E140: Use ! to write partial buffer" +msgstr "E140: バッファを部分的に保存するには ! を使ってください" #, c-format -msgid "E666: compiler not supported: %s" -msgstr "E666: そのコンパイラには対応していません: %s" +msgid "Overwrite existing file \"%s\"?" +msgstr "既存のファイル \"%s\" を上書きしますか?" #, c-format -msgid "W20: Required python version 2.x not supported, ignoring file: %s" -msgstr "W20: 要求されたpython 2.xは対応していません、ファイルを無視します: %s" +msgid "Swap file \"%s\" exists, overwrite anyway?" +msgstr "スワップファイル \"%s\" が存在します。上書きを強制しますか?" #, c-format -msgid "W21: Required python version 3.x not supported, ignoring file: %s" -msgstr "W21: 要求されたpython 3.xは対応していません、ファイルを無視します: %s" +msgid "E768: Swap file exists: %s (:silent! overrides)" +msgstr "E768: スワップファイルが存在します: %s (:silent! を追加で上書)" #, c-format -msgid "Current %slanguage: \"%s\"" -msgstr "現在の %s言語: \"%s\"" +msgid "E141: No file name for buffer %<PRId64>" +msgstr "E141: バッファ %<PRId64> には名前がありません" + +msgid "E142: File not written: Writing is disabled by 'write' option" +msgstr "E142: ファイルは保存されませんでした: 'write' オプションにより無効です" #, c-format -msgid "E197: Cannot set language to \"%s\"" -msgstr "E197: 言語を \"%s\" に設定できません" +msgid "" +"'readonly' option is set for \"%s\".\n" +"Do you wish to write anyway?" +msgstr "" +"\"%s\" には 'readonly' オプションが設定されています.\n" +"上書き強制をしますか?" -msgid "Entering Ex mode. Type \"visual\" to go to Normal mode." +#, c-format +msgid "" +"File permissions of \"%s\" are read-only.\n" +"It may still be possible to write it.\n" +"Do you wish to try?" msgstr "" -"Exモードに入ります. ノーマルモードに戻るには\"visual\"と入力してください." +"ファイル \"%s\" のパーミッションが読込専用です.\n" +"それでも恐らく書込むことは可能です.\n" +"継続しますか?" -msgid "E501: At end-of-file" -msgstr "E501: ファイルの終了位置" +#, c-format +msgid "E505: \"%s\" is read-only (add ! to override)" +msgstr "E505: \"%s\" は読込専用です (強制書込には ! を追加)" -msgid "E169: Command too recursive" -msgstr "E169: コマンドが再帰的過ぎます" +#, c-format +msgid "E143: Autocommands unexpectedly deleted new buffer %s" +msgstr "E143: 自動コマンドが予期せず新しいバッファ %s を削除しました" + +msgid "E146: Regular expressions can't be delimited by letters" +msgstr "E146: 正規表現は文字で区切ることができません" #, c-format -msgid "E605: Exception not caught: %s" -msgstr "E605: 例外が捕捉されませんでした: %s" +msgid "replace with %s (y/n/a/q/l/^E/^Y)?" +msgstr "%s に置換しますか? (y/n/a/q/l/^E/^Y)" -msgid "End of sourced file" -msgstr "取込ファイルの最後です" +msgid "(Interrupted) " +msgstr "(割込まれました) " -msgid "End of function" -msgstr "関数の最後です" +#, c-format +msgid "%<PRId64> match on %<PRId64> line" +msgid_plural "%<PRId64> matches on %<PRId64> line" +msgstr[0] "%<PRId64> 箇所該当しました (計 %<PRId64> 行内)" -msgid "E464: Ambiguous use of user-defined command" -msgstr "E464: ユーザー定義コマンドのあいまいな使用です" +#, c-format +msgid "%<PRId64> substitution on %<PRId64> line" +msgid_plural "%<PRId64> substitutions on %<PRId64> line" +msgstr[0] "%<PRId64> 箇所置換しました (計 %<PRId64> 行内)" -msgid "E492: Not an editor command" -msgstr "E492: エディタのコマンドではありません" +#, c-format +msgid "%<PRId64> match on %<PRId64> lines" +msgid_plural "%<PRId64> matches on %<PRId64> lines" +msgstr[0] "%<PRId64> 箇所該当しました (計 %<PRId64> 行内)" -msgid "E493: Backwards range given" -msgstr "E493: 逆さまの範囲が指定されました" +#, c-format +msgid "%<PRId64> substitution on %<PRId64> lines" +msgid_plural "%<PRId64> substitutions on %<PRId64> lines" +msgstr[0] "%<PRId64> 箇所置換しました (計 %<PRId64> 行内)" -msgid "Backwards range given, OK to swap" -msgstr "逆さまの範囲が指定されました、入替えますか?" +msgid "E147: Cannot do :global recursive with a range" +msgstr "E147: :global を範囲付きで再帰的には使えません" -msgid "E494: Use w or w>>" -msgstr "E494: w もしくは w>> を使用してください" +msgid "E148: Regular expression missing from global" +msgstr "E148: :global に正規表現が指定されていません" -msgid "E943: Command table needs to be updated, run 'make cmdidxs'" -msgstr "" -"E943: コマンドテーブルを更新する必要があります、'make cmdidxs' を実行してくだ" -"さい" +#, c-format +msgid "Pattern found in every line: %s" +msgstr "パターンが全ての行で見つかりました: %s" -msgid "E319: Sorry, the command is not available in this version" -msgstr "E319: このバージョンではこのコマンドは利用できません、ごめんなさい" +#, c-format +msgid "Pattern not found: %s" +msgstr "パターンは見つかりませんでした: %s" -msgid "1 more file to edit. Quit anyway?" -msgstr "編集すべきファイルが 1 個ありますが、終了しますか?" +msgid "No old files" +msgstr "古いファイルはありません" #, c-format -msgid "%d more files to edit. Quit anyway?" -msgstr "編集すべきファイルがあと %d 個ありますが、終了しますか?" +msgid "E666: Compiler not supported: %s" +msgstr "E666: そのコンパイラには対応していません: %s" -msgid "E173: 1 more file to edit" -msgstr "E173: 編集すべきファイルが 1 個あります" +#, c-format +msgid "Save changes to \"%s\"?" +msgstr "変更を \"%s\" に保存しますか?" #, c-format -msgid "E173: %ld more files to edit" -msgstr "E173: 編集すべきファイルがあと %ld 個あります" +msgid "Close \"%s\"?" +msgstr "\"%s\"を閉じますか?" -msgid "E174: Command already exists: add ! to replace it" -msgstr "E174: コマンドが既にあります: 再定義するには ! を追加してください" +#, c-format +msgid "E947: Job still running in buffer \"%s\"" +msgstr "E947: ジョブはバッファ \"%s\" でまだ実行中です" -msgid "" -"\n" -" Name Args Address Complete Definition" -msgstr "" -"\n" -" 名前 引数 アドレス 補完 定義" +#, c-format +msgid "E162: No write since last change for buffer \"%s\"" +msgstr "E162: バッファ \"%s\" の変更は保存されていません" -msgid "No user-defined commands found" -msgstr "ユーザー定義コマンドが見つかりませんでした" +msgid "Warning: Entered other buffer unexpectedly (check autocommands)" +msgstr "警告: 予期せず他バッファへ移動しました (自動コマンドを調べてください)" -msgid "E175: No attribute specified" -msgstr "E175: 属性は定義されていません" +msgid "E464: Ambiguous use of user-defined command" +msgstr "E464: ユーザー定義コマンドのあいまいな使用です" -msgid "E176: Invalid number of arguments" -msgstr "E176: 引数の数が無効です" +msgid "E489: No call stack to substitute for \"<stack>\"" +msgstr "E489: \"<stack>\" を置き換えるコールスタックがありません" -msgid "E177: Count cannot be specified twice" -msgstr "E177: カウントを2重指定することはできません" +msgid "E492: Not an editor command" +msgstr "E492: エディタのコマンドではありません" -msgid "E178: Invalid default value for count" -msgstr "E178: カウントの省略値が無効です" +msgid "E495: No autocommand file name to substitute for \"<afile>\"" +msgstr "E495: \"<afile>\" を置き換える自動コマンドのファイル名がありません" -msgid "E179: argument required for -complete" -msgstr "E179: -complete には引数が必要です" +msgid "E496: No autocommand buffer number to substitute for \"<abuf>\"" +msgstr "E496: \"<abuf>\" を置き換える自動コマンドバッファ番号がありません" -msgid "E179: argument required for -addr" -msgstr "E179: -addr には引数が必要です" +msgid "E497: No autocommand match name to substitute for \"<amatch>\"" +msgstr "E497: \"<amatch>\" を置き換える自動コマンドの該当名がありません" -#, c-format -msgid "E181: Invalid attribute: %s" -msgstr "E181: 無効な属性です: %s" +msgid "E498: No :source file name to substitute for \"<sfile>\"" +msgstr "E498: \"<sfile>\" を置き換える :source 対象ファイル名がありません" -msgid "E182: Invalid command name" -msgstr "E182: 無効なコマンド名です" +msgid "E842: No line number to use for \"<slnum>\"" +msgstr "E842: \"<slnum>\" を置き換える行番号がありません" -msgid "E183: User defined commands must start with an uppercase letter" -msgstr "E183: ユーザー定義コマンドは英大文字で始まらなければなりません" +msgid "E961: No line number to use for \"<sflnum>\"" +msgstr "E961: \"<sflnum>\" を置き換える行番号がありません" -msgid "E841: Reserved name, cannot be used for user defined command" -msgstr "E841: 予約名なので、ユーザー定義コマンドに利用できません" +msgid "E1274: No script file name to substitute for \"<script>\"" +msgstr "E1274: \"<script>\" を置き換えるスクリプトファイル名がありません" -#, c-format -msgid "E184: No such user-defined command: %s" -msgstr "E184: そのユーザー定義コマンドはありません: %s" +msgid "Entering Ex mode. Type \"visual\" to go to Normal mode." +msgstr "" +"Exモードに入ります。ノーマルモードに戻るには \"visual\" と入力してください。" + +msgid "E501: At end-of-file" +msgstr "E501: ファイルの終了位置" #, c-format -msgid "E180: Invalid address type value: %s" -msgstr "E180: 無効なアドレスタイプ値です: %s" +msgid "Executing: %s" +msgstr "実行中: %s" + +#~ msgid "line %" +#~ msgstr "" + +msgid "End of sourced file" +msgstr "取込みファイルの最後です" + +msgid "End of function" +msgstr "関数の最後です" #, c-format -msgid "E180: Invalid complete value: %s" -msgstr "E180: 無効な補完指定です: %s" +msgid "E605: Exception not caught: %s" +msgstr "E605: 例外が捕捉されませんでした: %s" -msgid "E468: Completion argument only allowed for custom completion" -msgstr "E468: 補完引数はカスタム補完でしか使用できません" +msgid "" +"INTERNAL: Cannot use EX_DFLALL with ADDR_NONE, ADDR_UNSIGNED or ADDR_QUICKFIX" +msgstr "" +"内部エラー: EX_DFLALL を ADDR_NONE, ADDR_UNSIGNED または ADDR_QUICKFIX と使用" +"できません" -msgid "E467: Custom completion requires a function argument" -msgstr "E467: カスタム補完には引数として関数が必要です" +msgid "E493: Backwards range given" +msgstr "E493: 逆さまの範囲が指定されました" -msgid "unknown" -msgstr "不明" +msgid "Backwards range given, OK to swap" +msgstr "逆さまの範囲が指定されました、入替えますか?" + +msgid "E494: Use w or w>>" +msgstr "E494: w もしくは w>> を使用してください" + +msgid "E943: Command table needs to be updated, run 'make'" +msgstr "" +"E943: コマンドテーブルを更新する必要があります。 'make' を実行してください" + +msgid "E319: The command is not available in this version" +msgstr "E319: このバージョンではこのコマンドは利用できません" + +#, c-format +msgid "%d more file to edit. Quit anyway?" +msgid_plural "%d more files to edit. Quit anyway?" +msgstr[0] "編集すべきファイルがあと %d 個ありますが、終了しますか?" + +#, c-format +msgid "E173: %<PRId64> more file to edit" +msgid_plural "E173: %<PRId64> more files to edit" +msgstr[0] "E173: 編集すべきファイルがあと %<PRId64> 個あります" #, c-format msgid "E185: Cannot find color scheme '%s'" @@ -1224,58 +3163,26 @@ msgstr "E784: 最後のタブページを閉じることはできません" msgid "Already only one tab page" msgstr "既にタブページは1つしかありません" -msgid "Edit File in new tab page" -msgstr "新しいタブページでファイルを編集します" - -msgid "Edit File in new window" -msgstr "新しいウィンドウでファイルを編集します" - #, c-format msgid "Tab page %d" msgstr "タブページ %d" +msgid "E25: Nvim does not have a built-in GUI" +msgstr "E25: Nvim は組み込みの GUI がありません" + msgid "No swap file" msgstr "スワップファイルがありません" -msgid "Append File" -msgstr "追加ファイル" - -msgid "E747: Cannot change directory, buffer is modified (add ! to override)" -msgstr "" -"E747: バッファが修正されているので、ディレクトリを変更できません (! を追加で" -"上書)" - msgid "E186: No previous directory" msgstr "E186: 前のディレクトリはありません" msgid "E187: Unknown" -msgstr "E187: 未知" +msgstr "E187: 不明" msgid "E465: :winsize requires two number arguments" msgstr "E465: :winsize には2つの数値の引数が必要です" #, c-format -msgid "Window position: X %d, Y %d" -msgstr "ウィンドウ位置: X %d, Y %d" - -msgid "E188: Obtaining window position not implemented for this platform" -msgstr "" -"E188: このプラットホームにはウィンドウ位置の取得機能は実装されていません" - -msgid "E466: :winpos requires two number arguments" -msgstr "E466: :winpos には2つの数値の引数が必要です" - -msgid "E930: Cannot use :redir inside execute()" -msgstr "E930: execute() の中では :redir は使えません" - -msgid "Save Redirection" -msgstr "リダイレクトを保存します" - -#, c-format -msgid "E739: Cannot create directory: %s" -msgstr "E739: ディレクトリを作成できません: %s" - -#, c-format msgid "E189: \"%s\" exists (add ! to override)" msgstr "E189: \"%s\" が存在します (上書するには ! を追加してください)" @@ -1289,27 +3196,9 @@ msgstr "E191: 引数は1文字の英字か引用符 (' か `) でなければい msgid "E192: Recursive use of :normal too deep" msgstr "E192: :normal の再帰利用が深くなり過ぎました" -msgid "E809: #< is not available without the +eval feature" -msgstr "E809: #< は +eval 機能が無いと利用できません" - msgid "E194: No alternate file name to substitute for '#'" msgstr "E194: '#'を置き換える副ファイルの名前がありません" -msgid "E495: no autocommand file name to substitute for \"<afile>\"" -msgstr "E495: \"<afile>\"を置き換えるautocommandのファイル名がありません" - -msgid "E496: no autocommand buffer number to substitute for \"<abuf>\"" -msgstr "E496: \"<abuf>\"を置き換えるautocommandバッファ番号がありません" - -msgid "E497: no autocommand match name to substitute for \"<amatch>\"" -msgstr "E497: \"<amatch>\"を置き換えるautocommandの該当名がありません" - -msgid "E498: no :source file name to substitute for \"<sfile>\"" -msgstr "E498: \"<sfile>\"を置き換える :source 対象ファイル名がありません" - -msgid "E842: no line number to use for \"<slnum>\"" -msgstr "E842: \"<slnum>\"を置き換える行番号がありません" - #, no-c-format msgid "E499: Empty file name for '%' or '#', only works with \":p:h\"" msgstr "" @@ -1321,8 +3210,21 @@ msgstr "E500: 空文字列として評価されました" msgid "Untitled" msgstr "無題" -msgid "E196: No digraphs in this version" -msgstr "E196: このバージョンに合字はありません" +msgid "E5009: $VIMRUNTIME is empty or unset" +msgstr "E5009: $VIMRUNTIME が空か未設定です" + +#, c-format +msgid "E5009: Invalid $VIMRUNTIME: %s" +msgstr "E5009:無効な $VIMRUNTIME です: %s" + +msgid "E5009: Invalid 'runtimepath'" +msgstr "E5009:無効な 'runtimepath' です" + +msgid "E583: Multiple :else" +msgstr "E583: 複数の :else があります" + +msgid "E607: Multiple :finally" +msgstr "E607: 複数の :finally があります" msgid "E608: Cannot :throw exceptions with 'Vim' prefix" msgstr "E608: 'Vim' で始まる例外は :throw できません" @@ -1332,16 +3234,16 @@ msgid "Exception thrown: %s" msgstr "例外が発生しました: %s" #, c-format -msgid "Exception finished: %s" -msgstr "例外が収束しました: %s" - -#, c-format msgid "Exception discarded: %s" msgstr "例外が破棄されました: %s" #, c-format -msgid "%s, line %ld" -msgstr "%s, 行 %ld" +msgid "Exception finished: %s" +msgstr "例外が収束しました: %s" + +#, c-format +msgid "%s, line %<PRId64>" +msgstr "%s, 行 %<PRId64>" #, c-format msgid "Exception caught: %s" @@ -1383,9 +3285,6 @@ msgstr "E581: :if のない :else があります" msgid "E582: :elseif without :if" msgstr "E582: :if のない :elseif があります" -msgid "E583: multiple :else" -msgstr "E583: 複数の :else があります" - msgid "E584: :elseif after :else" msgstr "E584: :else の後に :elseif があります" @@ -1416,68 +3315,82 @@ msgstr "E604: :finally の後に :catch があります" msgid "E606: :finally without :try" msgstr "E606: :try のない :finally があります" -msgid "E607: multiple :finally" -msgstr "E607: 複数の :finally があります" - msgid "E602: :endtry without :try" msgstr "E602: :try のない :endtry です" -msgid "E193: :endfunction not inside a function" -msgstr "E193: 関数の外に :endfunction がありました" - -msgid "E788: Not allowed to edit another buffer now" -msgstr "E788: 現在は他のバッファを編集することは許されません" +msgid "E199: Active window or buffer changed or deleted" +msgstr "E199: アクティブなウィンドウかバッファが変更されたか削除されました" msgid "E811: Not allowed to change buffer information now" msgstr "E811: 現在はバッファ情報を変更することは許されません" #, c-format -msgid "" -"\n" -"# %s History (newest to oldest):\n" -msgstr "" -"\n" -"# %s 項目の履歴 (新しいものから古いものへ):\n" +msgid "E5408: Unable to get g:Nvim_color_cmdline callback: %s" +msgstr "E5408: g:Nvim_color_cmdline コールバックを取得できません: %s" + +#, c-format +msgid "E5407: Callback has thrown an exception: %s" +msgstr "E5407: コールバックで例外が発生しました: %s" + +msgid "E5400: Callback should return list" +msgstr "E5400: コールバックはリストを返す必要があります" + +#, c-format +msgid "E5401: List item %i is not a List" +msgstr "E5401: リストの要素 %i はリストではありません" + +#, c-format +msgid "E5402: List item %i has incorrect length: %d /= 3" +msgstr "E5402: リスト項目 %i の長さが正しくありません: %d /= 3" -msgid "Command Line" -msgstr "コマンドライン" +#~ msgid "E5403: Chunk %i start %" +#~ msgstr "" -msgid "Search String" -msgstr "検索文字列" +#~ msgid "E5405: Chunk %i start %" +#~ msgstr "" -msgid "Expression" -msgstr "式" +#~ msgid "E5404: Chunk %i end %" +#~ msgstr "" -msgid "Input Line" -msgstr "入力行" +#~ msgid "E5406: Chunk %i end %" +#~ msgstr "" -msgid "Debug Line" -msgstr "デバッグ行" +msgid "E854: Path too long for completion" +msgstr "E854: パスが長過ぎて補完できません" -msgid "E198: cmd_pchar beyond the command length" -msgstr "E198: cmd_pchar がコマンド長を超えました" +#, c-format +msgid "" +"E343: Invalid path: '**[number]' must be at the end of the path or be " +"followed by '%s'." +msgstr "" +"E343: 無効なパスです: '**[数値]' はpathの最後か '%s' が続いてないといけませ" +"ん。" -msgid "E199: Active window or buffer deleted" -msgstr "E199: アクティブなウィンドウかバッファが削除されました" +#, c-format +msgid "E344: Can't find directory \"%s\" in cdpath" +msgstr "E344: cdpathには \"%s\" というディレクトリがありません" + +#, c-format +msgid "E345: Can't find file \"%s\" in path" +msgstr "E345: pathには \"%s\" というファイルがありません" + +#, c-format +msgid "E346: No more directory \"%s\" found in cdpath" +msgstr "E346: cdpathにはこれ以上 \"%s\" というディレクトリがありません" + +#, c-format +msgid "E347: No more file \"%s\" found in path" +msgstr "E347: パスにはこれ以上 \"%s\" というファイルがありません" msgid "E812: Autocommands changed buffer or buffer name" -msgstr "E812: autocommandがバッファかバッファ名を変更しました" +msgstr "E812: 自動コマンドがバッファかバッファ名を変更しました" msgid "Illegal file name" msgstr "不正なファイル名" -msgid "is a directory" -msgstr "はディレクトリです" - msgid "is not a file" msgstr "はファイルではありません" -msgid "is a device (disabled with 'opendevice' option)" -msgstr "はデバイスです ('opendevice' オプションで回避できます)" - -msgid "[New File]" -msgstr "[新ファイル]" - msgid "[New DIRECTORY]" msgstr "[新規ディレクトリ]" @@ -1488,23 +3401,14 @@ msgid "[Permission Denied]" msgstr "[権限がありません]" msgid "E200: *ReadPre autocommands made the file unreadable" -msgstr "E200: *ReadPre autocommand がファイルを読込不可にしました" +msgstr "E200: *ReadPre 自動コマンド がファイルを読込不可にしました" msgid "E201: *ReadPre autocommands must not change current buffer" -msgstr "E201: *ReadPre autocommand は現在のバッファを変えられません" - -msgid "Vim: Reading from stdin...\n" -msgstr "Vim: 標準入力から読込中...\n" - -msgid "Reading from stdin..." -msgstr "標準入力から読込み中..." +msgstr "E201: *ReadPre 自動コマンド は現在のバッファを変えられません" msgid "E202: Conversion made file unreadable!" msgstr "E202: 変換がファイルを読込不可にしました" -msgid "[fifo/socket]" -msgstr "[FIFO/ソケット]" - msgid "[fifo]" msgstr "[FIFO]" @@ -1520,19 +3424,13 @@ msgstr "[CR無]" msgid "[long lines split]" msgstr "[長行分割]" -msgid "[NOT converted]" -msgstr "[未変換]" - -msgid "[converted]" -msgstr "[変換済]" - #, c-format -msgid "[CONVERSION ERROR in line %ld]" -msgstr "[%ld 行目で変換エラー]" +msgid "[CONVERSION ERROR in line %<PRId64>]" +msgstr "[%<PRId64> 行目で変換エラー]" #, c-format -msgid "[ILLEGAL BYTE in line %ld]" -msgstr "[%ld 行目の不正なバイト]" +msgid "[ILLEGAL BYTE in line %<PRId64>]" +msgstr "[%<PRId64> 行目の不正なバイト]" msgid "[READ ERRORS]" msgstr "[読込エラー]" @@ -1546,151 +3444,24 @@ msgstr "'charconvert' による変換が失敗しました" msgid "can't read output of 'charconvert'" msgstr "'charconvert' の出力を読込めませんでした" -msgid "E676: No matching autocommands for acwrite buffer" -msgstr "E676: acwriteバッファの該当するautocommandは存在しません" - -msgid "E203: Autocommands deleted or unloaded buffer to be written" -msgstr "E203: 保存するバッファをautocommandが削除か解放しました" - -msgid "E204: Autocommand changed number of lines in unexpected way" -msgstr "E204: autocommandが予期せぬ方法で行数を変更しました" - -# Added at 19-Jan-2004. -msgid "NetBeans disallows writes of unmodified buffers" -msgstr "NetBeansは未変更のバッファを上書することは許可していません" - -msgid "Partial writes disallowed for NetBeans buffers" -msgstr "NetBeansバッファの一部を書き出すことはできません" - -msgid "is not a file or writable device" -msgstr "はファイルでも書込み可能デバイスでもありません" - -msgid "writing to device disabled with 'opendevice' option" -msgstr "'opendevice' オプションによりデバイスへの書き込みはできません" - -msgid "is read-only (add ! to override)" -msgstr "は読込専用です (強制書込には ! を追加)" - -msgid "E506: Can't write to backup file (add ! to override)" -msgstr "E506: バックアップファイルを保存できません (! を追加で強制保存)" - -msgid "E507: Close error for backup file (add ! to override)" -msgstr "" -"E507: バックアップファイルを閉じる際にエラーが発生しました (! を追加で強制)" - -msgid "E508: Can't read file for backup (add ! to override)" -msgstr "E508: バックアップ用ファイルを読込めません (! を追加で強制読込)" - -msgid "E509: Cannot create backup file (add ! to override)" -msgstr "E509: バックアップファイルを作れません (! を追加で強制作成)" - -msgid "E510: Can't make backup file (add ! to override)" -msgstr "E510: バックアップファイルを作れません (! を追加で強制作成)" - -msgid "E214: Can't find temp file for writing" -msgstr "E214: 保存用一時ファイルが見つかりません" - -msgid "E213: Cannot convert (add ! to write without conversion)" -msgstr "E213: 変換できません (! を追加で変換せずに保存)" - -msgid "E166: Can't open linked file for writing" -msgstr "E166: リンクされたファイルに書込めません" - -msgid "E212: Can't open file for writing" -msgstr "E212: 書込み用にファイルを開けません" - -msgid "E949: File changed while writing" -msgstr "E949: 書込み中にファイルが変更されました" - -msgid "E512: Close failed" -msgstr "E512: 閉じることに失敗" - -msgid "E513: write error, conversion failed (make 'fenc' empty to override)" -msgstr "E513: 書込みエラー、変換失敗 (上書するには 'fenc' を空にしてください)" - -#, c-format -msgid "" -"E513: write error, conversion failed in line %ld (make 'fenc' empty to " -"override)" -msgstr "" -"E513: 書込みエラー、変換失敗、行数 %ld (上書するには 'fenc' を空にしてくださ" -"い)" - -msgid "E514: write error (file system full?)" -msgstr "E514: 書込みエラー (ファイルシステムが満杯?)" - -msgid " CONVERSION ERROR" -msgstr " 変換エラー" - -#, c-format -msgid " in line %ld;" -msgstr " 行 %ld;" - -msgid "[Device]" -msgstr "[デバイス]" - -msgid "[New]" -msgstr "[新]" - -msgid " [a]" -msgstr " [a]" - -msgid " appended" -msgstr " 追加" - -msgid " [w]" -msgstr " [w]" - -msgid " written" -msgstr " 書込み" - -msgid "" -"\n" -"WARNING: Original file may be lost or damaged\n" -msgstr "" -"\n" -"警告: 原本ファイルが失われたか変更されました\n" - -msgid "don't quit the editor until the file is successfully written!" -msgstr "ファイルの保存に成功するまでエディタを終了しないでください!" - msgid "[dos]" msgstr "[dos]" -msgid "[dos format]" -msgstr "[dosフォーマット]" - msgid "[mac]" msgstr "[mac]" -msgid "[mac format]" -msgstr "[macフォーマット]" - msgid "[unix]" msgstr "[unix]" -msgid "[unix format]" -msgstr "[unixフォーマット]" - -msgid "1 line, " -msgstr "1 行, " - #, c-format -msgid "%ld lines, " -msgstr "%ld 行, " - -msgid "1 character" -msgstr "1 文字" +msgid "%<PRId64> line, " +msgid_plural "%<PRId64> lines, " +msgstr[0] "%<PRId64> 行, " #, c-format -msgid "%lld characters" -msgstr "%lld 文字" - -msgid "[noeol]" -msgstr "[noeol]" - -msgid "[Incomplete last line]" -msgstr "[最終行が不完全]" +msgid "%<PRId64> byte" +msgid_plural "%<PRId64> bytes" +msgstr[0] "%<PRId64> バイト" #, c-format msgid "E208: Error writing to \"%s\"" @@ -1702,10 +3473,10 @@ msgstr "E209: \"%s\" を閉じる時にエラーです" #, c-format msgid "E210: Error reading \"%s\"" -msgstr "E210: \"%s\" を読込中のエラーです" +msgstr "E210: \"%s\" を読込み中のエラーです" msgid "E246: FileChangedShell autocommand deleted buffer" -msgstr "E246: autocommand の FileChangedShell がバッファを削除しました" +msgstr "E246: FileChangedShell 自動コマンドがバッファを削除しました" #, c-format msgid "E211: File \"%s\" no longer available" @@ -1743,10 +3514,12 @@ msgstr "警告" msgid "" "&OK\n" -"&Load File" +"&Load File\n" +"Load File &and Options" msgstr "" "&OK\n" -"ファイル読込(&L)" +"ファイル読込(&L)\n" +"ファイルとオプションを読込(&A)" #, c-format msgid "E462: Could not prepare for reloading \"%s\"" @@ -1756,72 +3529,11 @@ msgstr "E462: \"%s\" をリロードする準備ができませんでした" msgid "E321: Could not reload \"%s\"" msgstr "E321: \"%s\" はリロードできませんでした" -msgid "--Deleted--" -msgstr "--削除済--" - -#, c-format -msgid "auto-removing autocommand: %s <buffer=%d>" -msgstr "autocommand: %s <バッファ=%d> が自動的に削除されます" - -#, c-format -msgid "E367: No such group: \"%s\"" -msgstr "E367: そのグループはありません: \"%s\"" - -msgid "E936: Cannot delete the current group" -msgstr "E936: 現在のグループは削除できません" - -msgid "W19: Deleting augroup that is still in use" -msgstr "W19: 使用中の augroup を消そうとしています" - -#, c-format -msgid "E215: Illegal character after *: %s" -msgstr "E215: * の後に不正な文字がありました: %s" - -#, c-format -msgid "E216: No such event: %s" -msgstr "E216: そのようなイベントはありません: %s" - -#, c-format -msgid "E216: No such group or event: %s" -msgstr "E216: そのようなグループもしくはイベントはありません: %s" - -msgid "" -"\n" -"--- Autocommands ---" -msgstr "" -"\n" -"--- Autocommands ---" - -#, c-format -msgid "E680: <buffer=%d>: invalid buffer number " -msgstr "E680: <バッファ=%d>: 無効なバッファ番号です " - -msgid "E217: Can't execute autocommands for ALL events" -msgstr "E217: 全てのイベントに対してのautocommandは実行できません" - -msgid "No matching autocommands" -msgstr "該当するautocommandは存在しません" - -msgid "E218: autocommand nesting too deep" -msgstr "E218: autocommandの入れ子が深過ぎます" - -#, c-format -msgid "%s Autocommands for \"%s\"" -msgstr "%s Autocommands for \"%s\"" - -#, c-format -msgid "Executing %s" -msgstr "%s を実行しています" - -#, c-format -msgid "autocommand %s" -msgstr "autocommand %s" - msgid "E219: Missing {." -msgstr "E219: { がありません." +msgstr "E219: { がありません。" msgid "E220: Missing }." -msgstr "E220: } がありません." +msgstr "E220: } がありません。" msgid "E490: No fold found" msgstr "E490: 折畳みがありません" @@ -1833,1151 +3545,1084 @@ msgid "E351: Cannot delete fold with current 'foldmethod'" msgstr "E351: 現在の 'foldmethod' では折畳みを削除できません" #, c-format -msgid "+--%3ld line folded " -msgid_plural "+--%3ld lines folded " -msgstr[0] "+--%3ld 行が折畳まれました" +msgid "+--%3d line folded" +msgid_plural "+--%3d lines folded " +msgstr[0] "+--%3d 行が折畳まれました" #, c-format -msgid "+-%s%3ld line: " -msgid_plural "+-%s%3ld lines: " -msgstr[0] "+-%s%3ld 行: " +msgid "+-%s%3d line: " +msgid_plural "+-%s%3d lines: " +msgstr[0] "+-%s%3d 行: " -msgid "E222: Add to read buffer" -msgstr "E222: 読込バッファへ追加" - -msgid "E223: recursive mapping" +msgid "E223: Recursive mapping" msgstr "E223: 再帰的マッピング" -msgid "E851: Failed to create a new process for the GUI" -msgstr "E851: GUI用のプロセスの起動に失敗しました" - -msgid "E852: The child process failed to start the GUI" -msgstr "E852: 子プロセスがGUIの起動に失敗しました" - -msgid "E229: Cannot start the GUI" -msgstr "E229: GUIを開始できません" - -#, c-format -msgid "E230: Cannot read from \"%s\"" -msgstr "E230: \"%s\"から読込むことができません" - -msgid "E665: Cannot start GUI, no valid font found" -msgstr "E665: 有効なフォントが見つからないので、GUIを開始できません" - -msgid "E231: 'guifontwide' invalid" -msgstr "E231: 'guifontwide' が無効です" - -msgid "E599: Value of 'imactivatekey' is invalid" -msgstr "E599: 'imactivatekey' に設定された値が無効です" - -#, c-format -msgid "E254: Cannot allocate color %s" -msgstr "E254: %s の色を割り当てられません" +msgid "E1255: <Cmd> mapping must end with <CR>" +msgstr "E1255: <Cmd> マッピングは <CR> で終わらなければなりません" -msgid "No match at cursor, finding next" -msgstr "カーソルの位置にマッチはありません、次を検索しています" +msgid "E1136: <Cmd> mapping must end with <CR> before second <Cmd>" +msgstr "" +"E1136: <Cmd> マッピングは次の <Cmd> の前に <CR> で終わらなければなりません" -msgid "<cannot open> " -msgstr "<開けません> " +msgid "E222: Add to read buffer" +msgstr "E222: 読み取りバッファに追加" #, c-format -msgid "E616: vim_SelFile: can't get font %s" -msgstr "E616: vim_SelFile: フォント %s を取得できません" - -msgid "E614: vim_SelFile: can't return to current directory" -msgstr "E614: vim_SelFile: 現在のディレクトリに戻れません" - -msgid "Pathname:" -msgstr "パス名:" - -msgid "E615: vim_SelFile: can't get current directory" -msgstr "E615: vim_SelFile: 現在のディレクトリを取得できません" - -msgid "OK" -msgstr "OK" - -msgid "Cancel" -msgstr "キャンセル" - -msgid "Scrollbar Widget: Could not get geometry of thumb pixmap." -msgstr "スクロールバー: 画像を取得できませんでした。" +msgid "Cannot open for reading: \"%s\": %s\n" +msgstr "読込み用として開けません: \"%s\": %s\n" -msgid "Vim dialog" -msgstr "Vim ダイアログ" +msgid "--No lines in buffer--" +msgstr "--バッファに行がありません--" -msgid "E232: Cannot create BalloonEval with both message and callback" -msgstr "E232: メッセージとコールバックのある BalloonEval を作成できません" +msgid "E470: Command aborted" +msgstr "E470: コマンドが中断されました" -msgid "_Cancel" -msgstr "キャンセル(_C)" +msgid "E905: Cannot set this option after startup" +msgstr "E905: 起動後はこのオプションを設定できません" -msgid "_Save" -msgstr "保存(_S)" +#, fuzzy +#~ msgid "E903: Could not spawn API job" +#~ msgstr "E903: API タスクの開始に失敗しました" -msgid "_Open" -msgstr "開く(_O)" +msgid "E471: Argument required" +msgstr "E471: 引数が必要です" -msgid "_OK" -msgstr "_OK" +msgid "E10: \\ should be followed by /, ? or &" +msgstr "E10: \\ の後は / か ? か & でなければなりません" -msgid "" -"&Yes\n" -"&No\n" -"&Cancel" +msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits" msgstr "" -"はい(&Y)\n" -"いいえ(&N)\n" -"キャンセル(&C)" - -msgid "Yes" -msgstr "はい" - -msgid "No" -msgstr "いいえ" - -msgid "Input _Methods" -msgstr "インプットメソッド" - -msgid "VIM - Search and Replace..." -msgstr "VIM - 検索と置換..." - -msgid "VIM - Search..." -msgstr "VIM - 検索..." - -msgid "Find what:" -msgstr "検索文字列:" +"E11: コマンドラインウィンドウでは使用できません。<CR> で実行、CTRL-C で終了し" +"ます。" -msgid "Replace with:" -msgstr "置換文字列:" +#, fuzzy +#~ msgid "E12: Command not allowed in secure mode in current dir or tag search" +#~ msgstr "E12: このコマンドは現在のディレクトリやタグ検索では使用できません" -msgid "Match whole word only" -msgstr "正確に該当するものだけ" +msgid "E169: Command too recursive" +msgstr "E169: コマンドが再帰的過ぎます" -msgid "Match case" -msgstr "大文字/小文字を区別する" +msgid "E681: Buffer is not loaded" +msgstr "E681: バッファは読込まれませんでした" -msgid "Direction" -msgstr "方向" +msgid "E171: Missing :endif" +msgstr "E171: :endif がありません" -msgid "Up" -msgstr "上" +msgid "E600: Missing :endtry" +msgstr "E600: :endtry がありません" -msgid "Down" -msgstr "下" +msgid "E170: Missing :endwhile" +msgstr "E170: :endwhile がありません" -msgid "Find Next" -msgstr "次を検索" +msgid "E170: Missing :endfor" +msgstr "E170: :endfor がありません" -msgid "Replace" -msgstr "置換" +msgid "E588: :endwhile without :while" +msgstr "E588: :while のない :endwhile があります" -msgid "Replace All" -msgstr "全て置換" +msgid "E588: :endfor without :for" +msgstr "E588: :endfor のない :for があります" -msgid "_Close" -msgstr "閉じる(_C)" +msgid "E13: File exists (add ! to override)" +msgstr "E13: ファイルが存在します (! を追加で上書)" -msgid "Vim: Received \"die\" request from session manager\n" -msgstr "Vim: セッションマネージャから \"die\" 要求を受け取りました\n" +msgid "E472: Command failed" +msgstr "E472: コマンドが失敗しました" -msgid "Close tab" -msgstr "タブページを閉じる" +msgid "E473: Internal error" +msgstr "E473: 内部エラーです" -msgid "New tab" -msgstr "新規タブページ" +#, c-format +msgid "E685: Internal error: %s" +msgstr "E685: 内部エラーです: %s" -msgid "Open Tab..." -msgstr "タブページを開く..." +msgid "Interrupted" +msgstr "割込まれました" -msgid "Vim: Main window unexpectedly destroyed\n" -msgstr "Vim: メインウィンドウが不意に破壊されました\n" +msgid "E474: Invalid argument" +msgstr "E474: 無効な引数です" -msgid "&Filter" -msgstr "フィルタ(&F)" +#, c-format +msgid "E475: Invalid argument: %s" +msgstr "E475: 無効な引数です: %s" -msgid "&Cancel" -msgstr "キャンセル(&C)" +#, c-format +msgid "E475: Invalid value for argument %s" +msgstr "E475: 引数 %s に対して無効な値です" -msgid "Directories" -msgstr "ディレクトリ" +#, c-format +msgid "E475: Invalid value for argument %s: %s" +msgstr "E475: 引数 %s に対して無効な値です: %s" -msgid "Filter" -msgstr "フィルタ" +#, c-format +msgid "E983: Duplicate argument: %s" +msgstr "E983: 引数が重複しています: %s" -msgid "&Help" -msgstr "ヘルプ(&H)" +#, c-format +msgid "E15: Invalid expression: \"%s\"" +msgstr "E15: 無効な式です: \"%s\"" -msgid "Files" -msgstr "ファイル" +msgid "E16: Invalid range" +msgstr "E16: 無効な範囲です" -msgid "&OK" -msgstr "&OK" +msgid "E476: Invalid command" +msgstr "E476: 無効なコマンドです" -msgid "Selection" -msgstr "選択" +#, c-format +msgid "E17: \"%s\" is a directory" +msgstr "E17: \"%s\" はディレクトリです" -msgid "Find &Next" -msgstr "次を検索(&N)" +msgid "E756: Spell checking is not possible" +msgstr "E756: スペルチェックは使用できません" -msgid "&Replace" -msgstr "置換(&R)" +msgid "E900: Invalid channel id" +msgstr "E900: 無効なチャネルIDです" -msgid "Replace &All" -msgstr "全て置換(&A)" +msgid "E900: Invalid channel id: not a job" +msgstr "E900: 無効なチャネルIDです: タスクではありません" -msgid "&Undo" -msgstr "アンドゥ(&U)" +msgid "E901: Job table is full" +msgstr "E901: タスクテーブルがフルです" -msgid "Open tab..." -msgstr "タブページを開く" +#, c-format +msgid "E903: Process failed to start: %s: \"%s\"" +msgstr "E903: プロセスの開始に失敗しました: %s: \"%s\"" -msgid "Find string (use '\\\\' to find a '\\')" -msgstr "検索文字列 ('\\' を検索するには '\\\\')" +msgid "E904: channel is not a pty" +msgstr "E904: チャネルは疑似端末ではありません" -msgid "Find & Replace (use '\\\\' to find a '\\')" -msgstr "検索・置換 ('\\' を検索するには '\\\\')" +#, c-format +msgid "E905: Couldn't open stdio channel: %s" +msgstr "E905: 標準出力チャネルを開けませんでした: %s" -msgid "Not Used" -msgstr "使われません" +msgid "E906: invalid stream for channel" +msgstr "E906: チャネルのストリームが無効です" -msgid "Directory\t*.nothing\n" -msgstr "ディレクトリ\t*.nothing\n" +msgid "E906: invalid stream for rpc channel, use 'rpc'" +msgstr "E906: rpc チャネルのストリームが無効です。 rpc を使用してください" #, c-format -msgid "E671: Cannot find window title \"%s\"" -msgstr "E671: タイトルが \"%s\" のウィンドウは見つかりません" +msgid "" +"E5210: dict key '%s' already set for buffered stream in channel %<PRIu64>" +msgstr "" +"E5210: 辞書キー '%s' はチャネル %<PRIu64> のバッファされたストリームにすでに" +"設定されています" #, c-format -msgid "E243: Argument not supported: \"-%s\"; Use the OLE version." -msgstr "E243: 引数はサポートされません: \"-%s\"; OLE版を使用してください." - -msgid "E672: Unable to open window inside MDI application" -msgstr "E672: MDIアプリの中ではウィンドウを開けません" - -msgid "Vim E458: Cannot allocate colormap entry, some colors may be incorrect" -msgstr "Vim E458: 色指定が正しくないのでエントリを割り当てられません" +msgid "E364: Library call failed for \"%s()\"" +msgstr "E364: \"%s()\" のライブラリ呼出しに失敗しました" #, c-format -msgid "E250: Fonts for the following charsets are missing in fontset %s:" -msgstr "E250: 以下の文字セットのフォントがありません %s:" +msgid "E667: Fsync failed: %s" +msgstr "E667: fsync に失敗しました: %s" #, c-format -msgid "E252: Fontset name: %s" -msgstr "E252: フォントセット名: %s" +msgid "E739: Cannot create directory %s: %s" +msgstr "E739: %s ディレクトリを作成できません: %s" -#, c-format -msgid "Font '%s' is not fixed-width" -msgstr "フォント '%s' は固定幅ではありません" +msgid "E19: Mark has invalid line number" +msgstr "E19: マークに無効な行番号が指定されていました" -#, c-format -msgid "E253: Fontset name: %s" -msgstr "E253: フォントセット名: %s" +msgid "E20: Mark not set" +msgstr "E20: マークは設定されていません" -#, c-format -msgid "Font0: %s" -msgstr "フォント0: %s" +msgid "E21: Cannot make changes, 'modifiable' is off" +msgstr "E21: 'modifiable' がオフなので、変更できません" -#, c-format -msgid "Font1: %s" -msgstr "フォント1: %s" +msgid "E22: Scripts nested too deep" +msgstr "E22: スクリプトの入れ子が深過ぎます" -#, c-format -msgid "Font%ld width is not twice that of font0" -msgstr "フォント%ld の幅がフォント0の2倍ではありません" +msgid "E23: No alternate file" +msgstr "E23: 副ファイルはありません" -#, c-format -msgid "Font0 width: %ld" -msgstr "フォント0の幅: %ld" +msgid "E24: No such abbreviation" +msgstr "E24: そのような短縮入力はありません" -#, c-format -msgid "Font1 width: %ld" -msgstr "フォント1の幅: %ld" +msgid "E477: No ! allowed" +msgstr "E477: ! は許可されていません" -msgid "Invalid font specification" -msgstr "無効なフォント指定です" +#, c-format +msgid "E28: No such highlight group name: %s" +msgstr "E28: そのような名のハイライトグループはありません: %s" -msgid "&Dismiss" -msgstr "却下する(&D)" +msgid "E29: No inserted text yet" +msgstr "E29: まだテキストが挿入されていません" -msgid "no specific match" -msgstr "マッチするものがありません" +msgid "E30: No previous command line" +msgstr "E30: 以前にコマンド行がありません" -msgid "Vim - Font Selector" -msgstr "Vim - フォント選択" +msgid "E31: No such mapping" +msgstr "E31: そのようなマッピングはありません" -msgid "Name:" -msgstr "名前:" +msgid "E479: No match" +msgstr "E479: 該当はありません" -msgid "Show size in Points" -msgstr "サイズをポイントで表示する" +#, c-format +msgid "E480: No match: %s" +msgstr "E480: 該当はありません: %s" -msgid "Encoding:" -msgstr "エンコード:" +msgid "E32: No file name" +msgstr "E32: ファイル名がありません" -msgid "Font:" -msgstr "フォント:" +msgid "E33: No previous substitute regular expression" +msgstr "E33: 正規表現置換がまだ実行されていません" -msgid "Style:" -msgstr "スタイル:" +msgid "E34: No previous command" +msgstr "E34: コマンドがまだ実行されていません" -msgid "Size:" -msgstr "サイズ:" +msgid "E35: No previous regular expression" +msgstr "E35: 正規表現がまだ実行されていません" -msgid "E256: Hangul automata ERROR" -msgstr "E256: ハングルオートマトンエラー" +msgid "E481: No range allowed" +msgstr "E481: 範囲指定は許可されていません" -#, c-format -msgid "E799: Invalid ID: %d (must be greater than or equal to 1)" -msgstr "E799: 無効な ID: %d (1 以上でなければなりません)" +msgid "E36: Not enough room" +msgstr "E36: ウィンドウに十分な高さもしくは幅がありません" -#, c-format -msgid "E801: ID already taken: %d" -msgstr "E801: ID はすでに利用中です: %d" +msgid "E483: Can't get temp file name" +msgstr "E483: 一時ファイルの名前を取得できません" #, c-format -msgid "E802: Invalid ID: %d (must be greater than or equal to 1)" -msgstr "E802: 無効な ID: %d (1 以上でなければなりません)" +msgid "E484: Can't open file %s" +msgstr "E484: ファイル %s を開けません" #, c-format -msgid "E803: ID not found: %d" -msgstr "E803: ID はありません: %d" +msgid "E484: Can't open file %s: %s" +msgstr "E484: ファイル %s を開けません: %s" #, c-format -msgid "E798: ID is reserved for \":match\": %d" -msgstr "E798: ID は \":match\" のために予約されています: %d" - -msgid "Add a new database" -msgstr "新データベースを追加" +msgid "E485: Can't read file %s" +msgstr "E485: ファイル %s を読込めません" -msgid "Query for a pattern" -msgstr "パターンのクエリーを追加" +msgid "E38: Null argument" +msgstr "E38: 引数が null です" -msgid "Show this message" -msgstr "このメッセージを表示する" +msgid "E39: Number expected" +msgstr "E39: 数値が要求されています" -msgid "Kill a connection" -msgstr "接続を終了する" +#, c-format +msgid "E40: Can't open errorfile %s" +msgstr "E40: エラーファイル %s を開けません" -msgid "Reinit all connections" -msgstr "全ての接続を再初期化する" +msgid "E41: Out of memory!" +msgstr "E41: メモリが尽き果てました!" -msgid "Show connections" -msgstr "接続を表示する" +msgid "Pattern not found" +msgstr "パターンは見つかりませんでした" #, c-format -msgid "E560: Usage: cs[cope] %s" -msgstr "E560: 使用方法: cs[cope] %s" +msgid "E486: Pattern not found: %s" +msgstr "E486: パターンは見つかりませんでした: %s" -msgid "This cscope command does not support splitting the window.\n" -msgstr "このcscopeコマンドは分割ウィンドウではサポートされません.\n" +msgid "E487: Argument must be positive" +msgstr "E487: 引数は正の値でなければなりません" -msgid "E562: Usage: cstag <ident>" -msgstr "E562: 使用法: cstag <ident>" +msgid "E459: Cannot go back to previous directory" +msgstr "E459: 前のディレクトリに戻れません" -msgid "E257: cstag: tag not found" -msgstr "E257: cstag: タグが見つかりません" +msgid "E42: No Errors" +msgstr "E42: エラーはありません" -#, c-format -msgid "E563: stat(%s) error: %d" -msgstr "E563: stat(%s) エラー: %d" +msgid "E776: No location list" +msgstr "E776: ロケーションリストはありません" -msgid "E563: stat error" -msgstr "E563: stat エラー" +msgid "E43: Damaged match string" +msgstr "E43: マッチした文字列が破損しています" -#, c-format -msgid "E564: %s is not a directory or a valid cscope database" -msgstr "E564: %s はディレクトリ及び有効なcscopeのデータベースではありません" +msgid "E44: Corrupted regexp program" +msgstr "E44: 正規表現プログラムが壊れています" -#, c-format -msgid "Added cscope database %s" -msgstr "cscopeデータベース %s を追加" +msgid "E45: 'readonly' option is set (add ! to override)" +msgstr "E45: 'readonly' オプションが設定されています (! を追加で上書き)" #, c-format -msgid "E262: error reading cscope connection %ld" -msgstr "E262: cscopeの接続 %ld を読込み中のエラーです" - -msgid "E561: unknown cscope search type" -msgstr "E561: 未知のcscope検索型です" +msgid "E734: Wrong variable type for %s=" +msgstr "E734: 異なった型の変数です %s=" -msgid "E566: Could not create cscope pipes" -msgstr "E566: cscopeパイプを作成できませんでした" - -msgid "E622: Could not fork for cscope" -msgstr "E622: cscopeの起動準備(fork)に失敗しました" +#, c-format +msgid "E461: Illegal variable name: %s" +msgstr "E461: 不正な変数名です: %s" -msgid "cs_create_connection setpgid failed" -msgstr "cs_create_connection への setpgid に失敗しました" +msgid "E995: Cannot modify existing variable" +msgstr "E995: 既存の変数を変更できません" -msgid "cs_create_connection exec failed" -msgstr "cs_create_connection の実行に失敗しました" +#, c-format +msgid "E46: Cannot change read-only variable \"%.*s\"" +msgstr "E46: 読取専用変数 \"%.*s\" には値を設定できません" -msgid "cs_create_connection: fdopen for to_fp failed" -msgstr "cs_create_connection: to_fp の fdopen に失敗しました" +msgid "E928: String required" +msgstr "E928: 文字列が必要です" -msgid "cs_create_connection: fdopen for fr_fp failed" -msgstr "cs_create_connection: fr_fp の fdopen に失敗しました" +msgid "E715: Dictionary required" +msgstr "E715: 辞書型が必要です" -msgid "E623: Could not spawn cscope process" -msgstr "E623: cscopeプロセスを起動できませんでした" +#, c-format +msgid "E979: Blob index out of range: %<PRId64>" +msgstr "E979: Blobのインデックスが範囲外です: %<PRId64>" -msgid "E567: no cscope connections" -msgstr "E567: cscope接続に失敗しました" +msgid "E978: Invalid operation for Blob" +msgstr "E978: Blob型には無効な操作です" #, c-format -msgid "E469: invalid cscopequickfix flag %c for %c" -msgstr "E469: 無効な cscopequickfix フラグ %c の %c です" +msgid "E118: Too many arguments for function: %s" +msgstr "E118: 関数の引数が多過ぎます: %s" #, c-format -msgid "E259: no matches found for cscope query %s of %s" -msgstr "E259: cscopeクエリー %s of %s に該当がありませんでした" - -msgid "cscope commands:\n" -msgstr "cscopeコマンド:\n" +msgid "E119: Not enough arguments for function: %s" +msgstr "E119: 関数の引数が足りません: %s" #, c-format -msgid "%-5s: %s%*s (Usage: %s)" -msgstr "%-5s: %s%*s (使用法: %s)" - -msgid "" -"\n" -" a: Find assignments to this symbol\n" -" c: Find functions calling this function\n" -" d: Find functions called by this function\n" -" e: Find this egrep pattern\n" -" f: Find this file\n" -" g: Find this definition\n" -" i: Find files #including this file\n" -" s: Find this C symbol\n" -" t: Find this text string\n" -msgstr "" -"\n" -" a: このシンボルに対する代入を探す\n" -" c: この関数を呼んでいる関数を探す\n" -" d: この関数から呼んでいる関数を探す\n" -" e: このegrepパターンを探す\n" -" f: このファイルを探す\n" -" g: この定義を探す\n" -" i: このファイルを#includeしているファイルを探す\n" -" s: このCシンボルを探す\n" -" t: このテキスト文字列を探す\n" +msgid "E716: Key not present in Dictionary: \"%s\"" +msgstr "E716: 辞書型にキーが存在しません: \"%s\"" #, c-format -msgid "E625: cannot open cscope database: %s" -msgstr "E625: cscopeデータベース: %s を開くことができません" +msgid "E716: Key not present in Dictionary: \"%.*s\"" +msgstr "E716: 辞書型にキーが存在しません: \"%.*s\"" -msgid "E626: cannot get cscope database information" -msgstr "E626: cscopeデータベースの情報を取得できません" +msgid "E714: List required" +msgstr "E714: リスト型が必要です" -msgid "E568: duplicate cscope database not added" -msgstr "E568: 重複するcscopeデータベースは追加されませんでした" +msgid "E897: List or Blob required" +msgstr "E897: リスト型またはBlob型が必要です" #, c-format -msgid "E261: cscope connection %s not found" -msgstr "E261: cscope接続 %s が見つかりませんでした" +msgid "E712: Argument of %s must be a List or Dictionary" +msgstr "E712: %s の引数はリスト型または辞書型でなければなりません" #, c-format -msgid "cscope connection %s closed" -msgstr "cscope接続 %s が閉じられました" - -msgid "E570: fatal error in cs_manage_matches" -msgstr "E570: cs_manage_matches で致命的なエラーです" +msgid "E896: Argument of %s must be a List, Dictionary or Blob" +msgstr "E896: %s の引数はリスト型、辞書型またはBlob型でなければなりません" -#, c-format -msgid "Cscope tag: %s" -msgstr "Cscope タグ: %s" +msgid "E47: Error while reading errorfile" +msgstr "E47: エラーファイルの読込み中にエラーが発生しました" -msgid "" -"\n" -" # line" -msgstr "" -"\n" -" # 行番号" +msgid "E48: Not allowed in sandbox" +msgstr "E48: サンドボックスでは許されません" -msgid "filename / context / line\n" -msgstr "ファイル名 / 文脈 / 行\n" +msgid "E523: Not allowed here" +msgstr "E523: ここでは許可されません" -#, c-format -msgid "E609: Cscope error: %s" -msgstr "E609: cscopeエラー: %s" +msgid "E565: Not allowed to change text or change window" +msgstr "E565: テキストを変更したりウィンドウを変更することは許可されません" -msgid "All cscope databases reset" -msgstr "全てのcscopeデータベースをリセットします" +msgid "E359: Screen mode setting not supported" +msgstr "E359: スクリーンモードの設定には対応していません" -msgid "no cscope connections\n" -msgstr "cscope接続がありません\n" +msgid "E49: Invalid scroll size" +msgstr "E49: 無効なスクロール量です" -msgid " # pid database name prepend path\n" -msgstr " # pid データベース名 prepend パス\n" +msgid "E91: 'shell' option is empty" +msgstr "E91: 'shell' オプションが空です" -msgid "Lua library cannot be loaded." -msgstr "Luaライブラリをロードできません。" +msgid "E255: Couldn't read in sign data!" +msgstr "E255: sign のデータを読込めませんでした" -msgid "cannot save undo information" -msgstr "アンドゥ情報が保存できません" +msgid "E72: Close error on swap file" +msgstr "E72: スワップファイルのクローズ時エラーです" -msgid "" -"E815: Sorry, this command is disabled, the MzScheme libraries could not be " -"loaded." -msgstr "E815: このコマンドは無効です。MzScheme ライブラリをロードできません。" +msgid "E74: Command too complex" +msgstr "E74: コマンドが複雑過ぎます" -msgid "" -"E895: Sorry, this command is disabled, the MzScheme's racket/base module " -"could not be loaded." -msgstr "" -"E895: このコマンドは無効です、ごめんなさい。MzScheme の racket/base モジュー" -"ルがロードできませんでした。" +msgid "E75: Name too long" +msgstr "E75: 名前が長過ぎます" -msgid "invalid expression" -msgstr "無効な式です" +msgid "E76: Too many [" +msgstr "E76: [ が多過ぎます" -msgid "expressions disabled at compile time" -msgstr "式はコンパイル時に無効にされています" +msgid "E77: Too many file names" +msgstr "E77: ファイル名が多過ぎます" -msgid "hidden option" -msgstr "隠しオプション" +msgid "E488: Trailing characters" +msgstr "E488: 余分な文字が後ろにあります" -msgid "unknown option" -msgstr "未知のオプションです" +#, c-format +msgid "E488: Trailing characters: %s" +msgstr "E488: 余分な文字が後ろにあります: %s" -msgid "window index is out of range" -msgstr "範囲外のウィンドウ番号です" +msgid "E78: Unknown mark" +msgstr "E78: 未知のマーク" -msgid "couldn't open buffer" -msgstr "バッファを開けません" +msgid "E79: Cannot expand wildcards" +msgstr "E79: ワイルドカードを展開できません" -msgid "cannot delete line" -msgstr "行を消せません" +msgid "E591: 'winheight' cannot be smaller than 'winminheight'" +msgstr "E591: 'winheight' は 'winminheight' より小さくできません" -msgid "cannot replace line" -msgstr "行を置換できません" +msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'" +msgstr "E592: 'winwidth' は 'winminwidth' より小さくできません" -msgid "cannot insert line" -msgstr "行を挿入できません" +msgid "E80: Error while writing" +msgstr "E80: 書込み中のエラー" -msgid "string cannot contain newlines" -msgstr "文字列には改行文字を含められません" +msgid "E939: Positive count required" +msgstr "E939: 正のカウントが必要です" -msgid "error converting Scheme values to Vim" -msgstr "Scheme値のVimへの変換エラー" +msgid "E81: Using <SID> not in a script context" +msgstr "E81: スクリプト以外で<SID>が使われました" -msgid "Vim error: ~a" -msgstr "Vim エラー: ~a" +#, c-format +msgid "E107: Missing parentheses: %s" +msgstr "E107: カッコ '(' がありません: %s" -msgid "Vim error" -msgstr "Vim エラー" +msgid "E749: Empty buffer" +msgstr "E749: バッファが空です" -msgid "buffer is invalid" -msgstr "バッファは無効です" +#, c-format +msgid "E86: Buffer %<PRId64> does not exist" +msgstr "E86: バッファ %<PRId64> はありません" -msgid "window is invalid" -msgstr "ウィンドウは無効です" +#, c-format +msgid "E193: %s not inside a function" +msgstr "E193: 関数の外に %s がありました" -msgid "linenr out of range" -msgstr "範囲外の行番号です" +msgid "E682: Invalid search pattern or delimiter" +msgstr "E682: 検索パターンか区切り記号が不正です" -msgid "not allowed in the Vim sandbox" -msgstr "サンドボックスでは許されません" +msgid "E139: File is loaded in another buffer" +msgstr "E139: 同じ名前のファイルが他のバッファで読込まれています" #, c-format -msgid "E370: Could not load library %s" -msgstr "E370: ライブラリ %s をロードできませんでした" - -msgid "Sorry, this command is disabled: the Perl library could not be loaded." -msgstr "" -"このコマンドは無効です、ごめんなさい: Perlライブラリをロードできませんでした." - -msgid "E299: Perl evaluation forbidden in sandbox without the Safe module" -msgstr "" -"E299: サンドボックスでは Safe モジュールを使用しないPerlスクリプトは禁じられ" -"ています" +msgid "E764: Option '%s' is not set" +msgstr "E764: オプション '%s' は設定されていません" -msgid "E836: This Vim cannot execute :python after using :py3" -msgstr "E836: このVimでは :py3 を使った後に :python を使えません" +msgid "E850: Invalid register name" +msgstr "E850: 無効なレジスタ名です" -msgid "" -"E263: Sorry, this command is disabled, the Python library could not be " -"loaded." -msgstr "" -"E263: このコマンドは無効です、ごめんなさい: Pythonライブラリをロードできませ" -"んでした。" +#, c-format +msgid "E919: Directory not found in '%s': \"%s\"" +msgstr "E919: ディレクトリが '%s' の中にありません: \"%s\"" -msgid "" -"E887: Sorry, this command is disabled, the Python's site module could not be " -"loaded." -msgstr "" -"E887: このコマンドは無効です、ごめんなさい。Python の site モジュールをロード" -"できませんでした。" +msgid "E952: Autocommand caused recursive behavior" +msgstr "E952: 自動コマンドが再帰を引き起こしました" -# Added at 07-Feb-2004. -msgid "E659: Cannot invoke Python recursively" -msgstr "E659: Python を再帰的に実行することはできません" +msgid "E328: Menu only exists in another mode" +msgstr "E328: メニューは他のモードにだけあります" -msgid "E837: This Vim cannot execute :py3 after using :python" -msgstr "E837: このVimでは :python を使った後に :py3 を使えません" +msgid "E813: Cannot close autocmd window" +msgstr "E813: autocmdウィンドウは閉じられません" -msgid "E265: $_ must be an instance of String" -msgstr "E265: $_ は文字列のインスタンスでなければなりません" +#, c-format +msgid "E686: Argument of %s must be a List" +msgstr "E686: %s の引数はリスト型でなければなりません" -msgid "" -"E266: Sorry, this command is disabled, the Ruby library could not be loaded." -msgstr "" -"E266: このコマンドは無効です、ごめんなさい: Rubyライブラリをロードできません" -"でした。" +msgid "E519: Option not supported" +msgstr "E519: オプションはサポートされていません" -msgid "E267: unexpected return" -msgstr "E267: 予期せぬ return です" +msgid "E856: Filename too long" +msgstr "E856: ファイル名が長過ぎます" -msgid "E268: unexpected next" -msgstr "E268: 予期せぬ next です" +msgid "E806: Using a Float as a String" +msgstr "E806: 浮動小数点数を文字列として扱っています" -msgid "E269: unexpected break" -msgstr "E269: 予期せぬ break です" +msgid "E788: Not allowed to edit another buffer now" +msgstr "E788: 現在は他のバッファを編集することは許されません" -msgid "E270: unexpected redo" -msgstr "E270: 予期せぬ redo です" +#, c-format +msgid "E1023: Using a Number as a Bool: %d" +msgstr "E1023: 数値をBoolとして扱っています: %d" -msgid "E271: retry outside of rescue clause" -msgstr "E271: rescue の外の retry です" +#, c-format +msgid "E1085: Not a callable type: %s" +msgstr "E1085: 呼出し可能な型ではありません: %s" -msgid "E272: unhandled exception" -msgstr "E272: 取り扱われなかった例外があります" +msgid "E855: Autocommands caused command to abort" +msgstr "E855: 自動コマンドがコマンドの停止を引き起こしました" #, c-format -msgid "E273: unknown longjmp status %d" -msgstr "E273: 未知のlongjmp状態: %d" +msgid "E5555: API call: %s" +msgstr "E5555: API の呼び出し: %s" -msgid "invalid buffer number" -msgstr "無効なバッファ番号です" +#, c-format +msgid "E5560: %s must not be called in a lua loop callback" +msgstr "E5560: %s は lua ループコールバックで呼び出されてはなりません" -msgid "not implemented yet" -msgstr "まだ実装されていません" +msgid "E5601: Cannot close window, only floating window would remain" +msgstr "" +"E5601: フローティングウィンドウしか残らないため、ウィンドウは閉じられません" -msgid "cannot set line(s)" -msgstr "行を設定できません" +#, fuzzy +#~ msgid "E5602: Cannot exchange or rotate float" +#~ msgstr "E5602: フローティングウィンドウを交換または回転できません" -msgid "invalid mark name" -msgstr "無効なマーク名です" +msgid "E1155: Cannot define autocommands for ALL events" +msgstr "E1155: 全てのイベントに対しての自動コマンドは定義できません" -msgid "mark not set" -msgstr "マークは設定されていません" +msgid "E1240: Resulting text too long" +msgstr "E1240: テキストが長くなりすぎました" -#, c-format -msgid "row %d column %d" -msgstr "行 %d 列 %d" +msgid "E1247: Line number out of range" +msgstr "E1247: 範囲外の行番号です" -msgid "cannot insert/append line" -msgstr "行の挿入/追加をできません" +msgid "E5248: Invalid character in group name" +msgstr "E5248: グループ名に不正な文字があります" -msgid "line number out of range" -msgstr "範囲外の行番号です" +msgid "E1249: Highlight group name too long" +msgstr "E1249: ハイライトグループ名が長すぎます" -msgid "unknown flag: " -msgstr "未知のフラグ: " +#, c-format +msgid "E964: Invalid column number: %ld" +msgstr "E964: 無効な列番号です: %ld" -msgid "unknown vimOption" -msgstr "未知の vimOption です" +#, c-format +msgid "E966: Invalid line number: %ld" +msgstr "E966: 無効な行番号です: %ld" -msgid "keyboard interrupt" -msgstr "キーボード割込み" +#, c-format +msgid "E1278: Stray '}' without a matching '{': %s" +msgstr "E1278: 対応する '{' がないはぐれた '}' です: %s" -msgid "cannot create buffer/window command: object is being deleted" -msgstr "" -"バッファ/ウィンドウ作成コマンドを作成できません: オブジェクトが消去されていま" -"した" +#, c-format +msgid "E1279: Missing '}': %s" +msgstr "E1279: '}' がありません: %s" -msgid "" -"cannot register callback command: buffer/window is already being deleted" -msgstr "" -"コールバックコマンドを登録できません: バッファ/ウィンドウが既に消去されました" +#, c-format +msgid "E1510: Value too large: %s" +msgstr "E1510: 値が大き過ぎます: %s" -msgid "" -"E280: TCL FATAL ERROR: reflist corrupt!? Please report this to vim-dev@vim." -"org" +msgid "E5767: Cannot use :undo! to redo or move to a different undo branch" msgstr "" -"E280: TCL 致命的エラー: reflist 汚染!? vim-dev@vim.org に報告してください" +"E5767: :undo! を使用して redo したり、別の undo ブランチに移動したりすること" +"はできません" -msgid "cannot register callback command: buffer/window reference not found" -msgstr "" -"コールバックコマンドを登録できません: バッファ/ウィンドウの参照が見つかりませ" -"ん" +msgid "E1513: Cannot switch buffer. 'winfixbuf' is enabled" +msgstr "E1513: バッファを切り替えられません。'winfixbuf' が有効になっています" -msgid "" -"E571: Sorry, this command is disabled: the Tcl library could not be loaded." -msgstr "" -"E571: このコマンドは無効です、ごめんなさい: Tclライブラリをロードできませんで" -"した。" +#, fuzzy, c-format +#~ msgid "E5570: Cannot update trust file: %s" +#~ msgstr "E5570: 信頼されたファイルは更新できません: %s" #, c-format -msgid "E572: exit code %d" -msgstr "E572: 終了コード %d" +msgid "E355: Unknown option: %s" +msgstr "E355: 未知のオプションです: %s" -msgid "cannot get line" -msgstr "行を取得できません" +msgid "search hit TOP, continuing at BOTTOM" +msgstr "上まで検索したので下に戻ります" -msgid "Unable to register a command server name" -msgstr "命令サーバーの名前を登録できません" +msgid "search hit BOTTOM, continuing at TOP" +msgstr "下まで検索したので上に戻ります" -msgid "E248: Failed to send command to the destination program" -msgstr "E248: 目的のプログラムへのコマンド送信に失敗しました" +msgid " line " +msgstr " 行 " #, c-format -msgid "E573: Invalid server id used: %s" -msgstr "E573: 無効なサーバーIDが使われました: %s" +msgid "E685: Internal error: hash_add(): duplicate key \"%s\"" +msgstr "E685: 内部エラーです: hash_add(): \"%s\" キーが重複しています" -msgid "E251: VIM instance registry property is badly formed. Deleted!" -msgstr "E251: VIM 実体の登録プロパティが不正です. 消去しました!" +msgid "E478: Don't panic!" +msgstr "E478: 慌てないでください!" #, c-format -msgid "E938: Duplicate key in JSON: \"%s\"" -msgstr "E938: JSONに重複キーがあります: \"%s\"" +msgid "E661: Sorry, no '%s' help for %s" +msgstr "E661: 残念ですが '%s' のヘルプが %s にはありません" #, c-format -msgid "E899: Argument of %s must be a List or Blob" -msgstr "E899: %s の引数はリスト型またはBlob型でなければなりません" +msgid "E149: Sorry, no help for %s" +msgstr "E149: 残念ですが %s にはヘルプがありません" #, c-format -msgid "E696: Missing comma in List: %s" -msgstr "E696: リスト型にカンマがありません: %s" +msgid "Sorry, help file \"%s\" not found" +msgstr "残念ですがヘルプファイル \"%s\" が見つかりません" #, c-format -msgid "E697: Missing end of List ']': %s" -msgstr "E697: リスト型の最後に ']' がありません: %s" +msgid "E151: No match: %s" +msgstr "E151: マッチはありません: %s" -msgid "Unknown option argument" -msgstr "未知のオプション引数です" +#, c-format +msgid "E152: Cannot open %s for writing" +msgstr "E152: 書込み用に %s を開けません" -msgid "Too many edit arguments" -msgstr "編集引数が多過ぎます" +#, c-format +msgid "E153: Unable to open %s for reading" +msgstr "E153: 読込み用に %s を開けません" -msgid "Argument missing after" -msgstr "引数がありません" +#, c-format +msgid "E670: Mix of help file encodings within a language: %s" +msgstr "E670: 1つの言語のヘルプファイルに複数のエンコードが混在しています: %s" -msgid "Garbage after option argument" -msgstr "オプション引数の後にゴミがあります" +#, c-format +msgid "E154: Duplicate tag \"%s\" in file %s/%s" +msgstr "E154: タグ \"%s\" がファイル %s/%s に重複しています" -msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments" -msgstr "\"+command\", \"-c command\", \"--cmd command\" の引数が多過ぎます" +#, c-format +msgid "E150: Not a directory: %s" +msgstr "E150: ディレクトリではありません: %s" -msgid "Invalid argument for" -msgstr "無効な引数です: " +msgid "E424: Too many different highlighting attributes in use" +msgstr "E424: 多くの異なるハイライト属性が使われ過ぎています" #, c-format -msgid "%d files to edit\n" -msgstr "%d 個のファイルが編集を控えています\n" - -msgid "netbeans is not supported with this GUI\n" -msgstr "netbeans はこのGUIでは利用できません\n" +msgid "E411: Highlight group not found: %s" +msgstr "E411: ハイライトグループが見つかりません: %s" -msgid "'-nb' cannot be used: not enabled at compile time\n" -msgstr "'-nb' 使用不可能です: コンパイル時に無効にされています\n" +msgid "E414: Group has settings, highlight link ignored" +msgstr "E414: グループが設定されているのでハイライトリンクは無視されます" -msgid "This Vim was not compiled with the diff feature." -msgstr "このVimにはdiff機能がありません(コンパイル時設定)。" +#, c-format +msgid "E415: Unexpected equal sign: %s" +msgstr "E415: 予期せぬ等号です: %s" -msgid "Attempt to open script file again: \"" -msgstr "スクリプトファイルを再び開こうとしました: \"" +#, c-format +msgid "E416: Missing equal sign: %s" +msgstr "E416: 等号がありません: %s" -msgid "Cannot open for reading: \"" -msgstr "読込用として開けません" +#, c-format +msgid "E417: Missing argument: %s" +msgstr "E417: 引数がありません: %s" -msgid "Cannot open for script output: \"" -msgstr "スクリプト出力用を開けません" +#, c-format +msgid "E412: Not enough arguments: \":highlight link %s\"" +msgstr "E412: 引数が充分ではない: \":highlight link %s\"" -msgid "Vim: Error: Failure to start gvim from NetBeans\n" -msgstr "Vim: エラー: NetBeansからgvimをスタートできません\n" +#, c-format +msgid "E413: Too many arguments: \":highlight link %s\"" +msgstr "E413: 引数が多過ぎます: \":highlight link %s\"" -msgid "Vim: Error: This version of Vim does not run in a Cygwin terminal\n" -msgstr "Vim: エラー: このバージョンのVimはCygwin端末では動作しません\n" +msgid "E423: Illegal argument" +msgstr "E423: 不正な引数です" -msgid "Vim: Warning: Output is not to a terminal\n" -msgstr "Vim: 警告: 端末への出力ではありません\n" +#, c-format +msgid "E418: Illegal value: %s" +msgstr "E418: 不正な値です: %s" -msgid "Vim: Warning: Input is not from a terminal\n" -msgstr "Vim: 警告: 端末からの入力ではありません\n" +msgid "E419: FG color unknown" +msgstr "E419: 未知の前景色です" -msgid "pre-vimrc command line" -msgstr "vimrc前のコマンドライン" +msgid "E420: BG color unknown" +msgstr "E420: 未知の背景色です" #, c-format -msgid "E282: Cannot read from \"%s\"" -msgstr "E282: \"%s\"から読込むことができません" +msgid "E421: Color name or number not recognized: %s" +msgstr "E421: カラー名や番号を認識できません: %s" -msgid "" -"\n" -"More info with: \"vim -h\"\n" -msgstr "" -"\n" -"より詳細な情報は: \"vim -h\"\n" +#, c-format +msgid "E423: Illegal argument: %s" +msgstr "E423: 不正な引数です: %s" -msgid "[file ..] edit specified file(s)" -msgstr "[ファイル..] あるファイルを編集する" +msgid "E669: Unprintable character in group name" +msgstr "E669: グループ名に印刷不可能な文字があります" -msgid "- read text from stdin" -msgstr "- 標準入力からテキストを読込む" +msgid "E849: Too many highlight and syntax groups" +msgstr "E849: ハイライトと構文グループが多過ぎます" -msgid "-t tag edit file where tag is defined" -msgstr "-t タグ タグが定義されたところから編集する" +msgid "Type number and <Enter> or click with the mouse (q or empty cancels): " +msgstr "" +"番号と<Enter>を入力するかマウスでクリックしてください (q か空でキャンセル): " -msgid "-q [errorfile] edit file with first error" -msgstr "-q [errorfile] 最初のエラーで編集する" +msgid "Type number and <Enter> (q or empty cancels): " +msgstr "番号と<Enter>を入力してください (q か空でキャンセル): " -msgid "" -"\n" -"\n" -"Usage:" -msgstr "" -"\n" -"\n" -"使用法:" +msgid " Keyword completion (^N^P)" +msgstr " キーワード補完 (^N^P)" -msgid " vim [arguments] " -msgstr " vim [引数] " +msgid " ^X mode (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)" +msgstr " ^X モード (^]^D^E^F^I^K^L^N^O^Ps^U^V^Y)" -msgid "" -"\n" -" or:" -msgstr "" -"\n" -" もしくは:" +msgid " Whole line completion (^L^N^P)" +msgstr " 行(全体)補完 (^L^N^P)" -msgid "" -"\n" -"Where case is ignored prepend / to make flag upper case" -msgstr "" -"\n" -"大小文字が無視される場合は大文字にするために / を前置してください" +msgid " File name completion (^F^N^P)" +msgstr " ファイル名補完 (^F^N^P)" -msgid "" -"\n" -"\n" -"Arguments:\n" -msgstr "" -"\n" -"\n" -"引数:\n" +msgid " Tag completion (^]^N^P)" +msgstr " タグ補完 (^]^N^P)" -msgid "--\t\t\tOnly file names after this" -msgstr "--\t\t\tこのあとにはファイル名だけ" +msgid " Path pattern completion (^N^P)" +msgstr " パスパターン補完 (^N^P)" -msgid "--literal\t\tDon't expand wildcards" -msgstr "--literal\t\tワイルドカードを展開しない" +msgid " Definition completion (^D^N^P)" +msgstr " 定義補完 (^D^N^P)" -msgid "-register\t\tRegister this gvim for OLE" -msgstr "-register\t\tこのgvimをOLEとして登録する" +msgid " Dictionary completion (^K^N^P)" +msgstr " 辞書補完 (^K^N^P)" -msgid "-unregister\t\tUnregister gvim for OLE" -msgstr "-unregister\t\tgvimのOLE登録を解除する" +msgid " Thesaurus completion (^T^N^P)" +msgstr " シソーラス補完 (^T^N^P)" -msgid "-g\t\t\tRun using GUI (like \"gvim\")" -msgstr "-g\t\t\tGUIで起動する (\"gvim\" と同じ)" +msgid " Command-line completion (^V^N^P)" +msgstr " コマンドライン補完 (^V^N^P)" -msgid "-f or --nofork\tForeground: Don't fork when starting GUI" -msgstr "-f or --nofork\tフォアグラウンド: GUIを始めるときにforkしない" +msgid " User defined completion (^U^N^P)" +msgstr " ユーザー定義補完 (^U^N^P)" -msgid "-v\t\t\tVi mode (like \"vi\")" -msgstr "-v\t\t\tViモード (\"vi\" と同じ)" +msgid " Omni completion (^O^N^P)" +msgstr " オムニ補完 (^O^N^P)" -msgid "-e\t\t\tEx mode (like \"ex\")" -msgstr "-e\t\t\tExモード (\"ex\" と同じ)" +msgid " Spelling suggestion (s^N^P)" +msgstr " 綴り修正候補 (s^N^P)" -msgid "-E\t\t\tImproved Ex mode" -msgstr "-E\t\t\t改良Exモード" +msgid " Keyword Local completion (^N^P)" +msgstr " 局所キーワード補完 (^N^P)" -msgid "-s\t\t\tSilent (batch) mode (only for \"ex\")" -msgstr "-s\t\t\tサイレント(バッチ)モード (\"ex\" 専用)" +msgid "Hit end of paragraph" +msgstr "段落の最後にヒット" -msgid "-d\t\t\tDiff mode (like \"vimdiff\")" -msgstr "-d\t\t\t差分モード (\"vidiff\" と同じ)" +msgid "E840: Completion function deleted text" +msgstr "E840: 補完関数がテキストを削除しました" -msgid "-y\t\t\tEasy mode (like \"evim\", modeless)" -msgstr "-y\t\t\tイージーモード (\"evim\" と同じ、モード無)" +msgid "'dictionary' option is empty" +msgstr "'dictionary' オプションが空です" -msgid "-R\t\t\tReadonly mode (like \"view\")" -msgstr "-R\t\t\t読込専用モード (\"view\" と同じ)" +msgid "'thesaurus' option is empty" +msgstr "'thesaurus' オプションが空です" -msgid "-m\t\t\tModifications (writing files) not allowed" -msgstr "-m\t\t\t変更 (ファイル保存時) をできないようにする" +#, c-format +msgid "Scanning dictionary: %s" +msgstr "辞書をスキャン中: %s" -msgid "-M\t\t\tModifications in text not allowed" -msgstr "-M\t\t\tテキストの編集を行なえないようにする" +msgid " (insert) Scroll (^E/^Y)" +msgstr " (挿入) スクロール(^E/^Y)" -msgid "-b\t\t\tBinary mode" -msgstr "-b\t\t\tバイナリモード" +msgid " (replace) Scroll (^E/^Y)" +msgstr " (置換) スクロール (^E/^Y)" -msgid "-l\t\t\tLisp mode" -msgstr "-l\t\t\tLispモード" +msgid "E785: complete() can only be used in Insert mode" +msgstr "E785: complete() は挿入モードでしか利用できません" -msgid "-C\t\t\tCompatible with Vi: 'compatible'" -msgstr "-C\t\t\tVi互換モード: 'compatible'" +#, c-format +msgid "Scanning: %s" +msgstr "スキャン中: %s" -msgid "-N\t\t\tNot fully Vi compatible: 'nocompatible'" -msgstr "-N\t\t\tVi非互換モード: 'nocompatible" +msgid "Scanning tags." +msgstr "タグをスキャン中。" -msgid "-V[N][fname]\t\tBe verbose [level N] [log messages to fname]" -msgstr "-V[N][fname]\t\tログ出力設定 [レベル N] [ログファイル名 fname]" +msgid "match in file" +msgstr "ファイル内のマッチ" -msgid "-D\t\t\tDebugging mode" -msgstr "-D\t\t\tデバッグモード" +msgid " Adding" +msgstr " 追加中" -msgid "-n\t\t\tNo swap file, use memory only" -msgstr "-n\t\t\tスワップファイルを使用せずメモリだけ" +msgid "-- Searching..." +msgstr "-- 検索中..." -msgid "-r\t\t\tList swap files and exit" -msgstr "-r\t\t\tスワップファイルを列挙し終了" +msgid "Back at original" +msgstr "始めに戻る" -msgid "-r (with file name)\tRecover crashed session" -msgstr "-r (ファイル名)\tクラッシュしたセッションを復帰" +msgid "Word from other line" +msgstr "他の行の単語" -msgid "-L\t\t\tSame as -r" -msgstr "-L\t\t\t-rと同じ" +msgid "The only match" +msgstr "唯一の該当" -msgid "-f\t\t\tDon't use newcli to open window" -msgstr "-f\t\t\tウィンドウを開くのに newcli を使用しない" +#, c-format +msgid "match %d of %d" +msgstr "%d 番目の該当 (全該当 %d 個中)" -msgid "-dev <device>\t\tUse <device> for I/O" -msgstr "-dev <device>\t\tI/Oに <device> を使用する" +#, c-format +msgid "match %d" +msgstr "%d 番目の該当" -msgid "-A\t\t\tStart in Arabic mode" -msgstr "-A\t\t\tアラビア語モードで起動する" +#, c-format +msgid "E1502: Lua failed to grow stack to %i" +msgstr "E1502: Lua はスタックを %i に増やすことができませんでした" -msgid "-H\t\t\tStart in Hebrew mode" -msgstr "-H\t\t\tヘブライ語モードで起動する" +msgid "" +"E5100: Cannot convert given lua table: table should contain either only " +"integer keys or only string keys" +msgstr "" +"E5100: 指定された lua テーブルを変換できません: テーブルには整数キーのみまた" +"は文字列キーのみが含まれている必要があります" -msgid "-F\t\t\tStart in Farsi mode" -msgstr "-F\t\t\tペルシア語モードで起動する" +msgid "E5101: Cannot convert given lua type" +msgstr "E5101: 指定された lua タイプを変換できません" -msgid "-T <terminal>\tSet terminal type to <terminal>" -msgstr "-T <terminal>\t端末を <terminal> に設定する" +#, c-format +msgid "E5102: Lua failed to grow stack to %i" +msgstr "E5102: Lua はスタックを %i に増やすことができませんでした" -msgid "--not-a-term\t\tSkip warning for input/output not being a terminal" -msgstr "--not-a-term\t\t入出力が端末でないとの警告をスキップする" +#, c-format +msgid "Error executing vim.schedule lua callback: %.*s" +msgstr "vim.schedule lua コールバックの実行中にエラーが発生しました: %.*s" -msgid "--ttyfail\t\tExit if input or output is not a terminal" -msgstr "--ttyfail\t\t入出力が端末でなければ終了する" +#, c-format +msgid "E970: Failed to initialize lua interpreter\n" +msgstr "E970: lua インタープリターの初期化に失敗しました\n" -msgid "-u <vimrc>\t\tUse <vimrc> instead of any .vimrc" -msgstr "-u <vimrc>\t\t.vimrcの代わりに <vimrc> を使う" +#, c-format +msgid "E970: Failed to initialize builtin lua modules\n" +msgstr "E970: 組み込み lua モジュールの初期化に失敗しました\n" -msgid "-U <gvimrc>\t\tUse <gvimrc> instead of any .gvimrc" -msgstr "-U <gvimrc>\t\t.gvimrcの代わりに <gvimrc> を使う" +#, fuzzy, c-format +#~ msgid "E5114: Error while converting print argument #%i: %.*s" +#~ msgstr "E5114: 出力引数 #%i の変換中にエラーが発生しました: %.*s" -msgid "--noplugin\t\tDon't load plugin scripts" -msgstr "--noplugin\t\tプラグインスクリプトをロードしない" +#, fuzzy, c-format +#~ msgid "E5115: Error while loading debug string: %.*s" +#~ msgstr "E5115: デバッグ文字列の読み込み中にエラーが発生しました: %.*s" -msgid "-p[N]\t\tOpen N tab pages (default: one for each file)" -msgstr "-p[N]\t\tN 個タブページを開く(省略値: ファイルにつき1個)" +#, fuzzy, c-format +#~ msgid "E5116: Error while calling debug string: %.*s" +#~ msgstr "E5116: デバッグ文字列の呼び出し中にエラーが発生しました: %.*s" -msgid "-o[N]\t\tOpen N windows (default: one for each file)" -msgstr "-o[N]\t\tN 個ウィンドウを開く(省略値: ファイルにつき1個)" +#, c-format +msgid "E5108: Error executing Lua function: %.*s" +msgstr "E5108: Lua 関数の実行中にエラーが発生しました: %.*s" -msgid "-O[N]\t\tLike -o but split vertically" -msgstr "-O[N]\t\t-oと同じだが垂直分割" +#, c-format +msgid "E5107: Error loading lua %.*s" +msgstr "E5107: lua %.*s の読み込み中にエラーが発生しました" -msgid "+\t\t\tStart at end of file" -msgstr "+\t\t\tファイルの最後からはじめる" +#, c-format +msgid "E5108: Error executing lua %.*s" +msgstr "E5108: lua %.*s の実行中にエラーが発生しました" -msgid "+<lnum>\t\tStart at line <lnum>" -msgstr "+<lnum>\t\t<lnum> 行からはじめる" +#, c-format +msgid "Error executing lua callback: %.*s" +msgstr "lua コールバックの実行中にエラーが発生しました: %.*s" -msgid "--cmd <command>\tExecute <command> before loading any vimrc file" -msgstr "--cmd <command>\tvimrcをロードする前に <command> を実行する" +msgid "cannot save undo information" +msgstr "アンドゥ情報が保存できません" -msgid "-c <command>\t\tExecute <command> after loading the first file" -msgstr "-c <command>\t\t最初のファイルをロード後 <command> を実行する" +#, c-format +msgid "E5109: Error loading lua: %.*s" +msgstr "E5109: lua の読み込み中にエラーが発生しました: %.*s" -msgid "-S <session>\t\tSource file <session> after loading the first file" -msgstr "-S <session>\t\t最初のファイルをロード後ファイル <session> を取込む" +#, c-format +msgid "E5110: Error executing lua: %.*s" +msgstr "E5110: lua の実行中にエラーが発生しました: %.*s" -msgid "-s <scriptin>\tRead Normal mode commands from file <scriptin>" -msgstr "-s <scriptin>\tファイル <scriptin> からノーマルコマンドを読込む" +#, c-format +msgid "E5111: Error calling lua: %.*s" +msgstr "E5111: lua の呼び出し中にエラーが発生しました: %.*s" -msgid "-w <scriptout>\tAppend all typed commands to file <scriptout>" -msgstr "-w <scriptout>\t入力した全コマンドをファイル <scriptout> に追加する" +#, c-format +msgid "E5112: Error while creating lua chunk: %.*s" +msgstr "E5112: lua チャンクの作成中にエラーが発生しました: %.*s" -msgid "-W <scriptout>\tWrite all typed commands to file <scriptout>" -msgstr "-W <scriptout>\t入力した全コマンドをファイル <scriptout> に保存する" +#, c-format +msgid "E5113: Error while calling lua chunk: %.*s" +msgstr "E5113: lua チャンクの呼び出し中にエラーが発生しました: %.*s" -msgid "-x\t\t\tEdit encrypted files" -msgstr "-x\t\t\t暗号化されたファイルを編集する" +#, c-format +msgid "Error executing vim._expand_pat: %.*s" +msgstr "vim._expand_pat の実行中にエラーが発生しました: %.*s" -msgid "-display <display>\tConnect Vim to this particular X-server" -msgstr "-display <display>\tvimを指定した X サーバーに接続する" +#, c-format +msgid "Error executing vim.on_key Lua callback: %.*s" +msgstr "vim.on_key Lua コールバックの実行中にエラーが発生しました: %.*s" -msgid "-X\t\t\tDo not connect to X server" -msgstr "-X\t\t\tXサーバーに接続しない" +#, c-format +msgid "Error executing Lua callback: %.*s" +msgstr "Lua コールバックの実行中にエラーが発生しました: %.*s" -msgid "--remote <files>\tEdit <files> in a Vim server if possible" -msgstr "--remote <files>\t可能ならばVimサーバーで <files> を編集する" +#, c-format +msgid "Error executing vim.secure.read: %.*s" +msgstr "vim.secure.read の実行中にエラーが発生しました: %.*s" -msgid "--remote-silent <files> Same, don't complain if there is no server" -msgstr "--remote-silent <files> 同上、サーバーが無くても警告文を出力しない" +#, c-format +msgid "Error executing vim.secure.trust: %.*s" +msgstr "vim.secure.trust の実行中にエラーが発生しました: %.*s" -msgid "" -"--remote-wait <files> As --remote but wait for files to have been edited" -msgstr "--remote-wait <files>\t--remote後 ファイルの編集が終わるのを待つ" +msgid "Argument missing after" +msgstr "引数がありません" -msgid "" -"--remote-wait-silent <files> Same, don't complain if there is no server" -msgstr "" -"--remote-wait-silent <files> 同上、サーバーが無くても警告文を出力しない" +msgid "Garbage after option argument" +msgstr "オプション引数の後にゴミがあります" -msgid "" -"--remote-tab[-wait][-silent] <files> As --remote but use tab page per file" -msgstr "" -"--remote-tab[-wait][-silent] <files> --remoteでファイル1つにつき1つのタブ" -"ページを開く" +msgid "Unknown option argument" +msgstr "未知のオプション引数です" -msgid "--remote-send <keys>\tSend <keys> to a Vim server and exit" -msgstr "--remote-send <keys>\tVimサーバーに <keys> を送信して終了する" +msgid "Too many edit arguments" +msgstr "編集引数が多過ぎます" -msgid "--remote-expr <expr>\tEvaluate <expr> in a Vim server and print result" -msgstr "--remote-expr <expr>\tサーバーで <expr> を実行して結果を表示する" +msgid "Too many \"+command\", \"-c command\" or \"--cmd command\" arguments" +msgstr "\"+command\", \"-c command\", \"--cmd command\" の引数が多過ぎます" -msgid "--serverlist\t\tList available Vim server names and exit" -msgstr "--serverlist\t\tVimサーバー名の一覧を表示して終了する" +#, c-format +msgid "Cannot open for script output: \"" +msgstr "スクリプト出力用として開けません: \"" -msgid "--servername <name>\tSend to/become the Vim server <name>" -msgstr "--servername <name>\tVimサーバー <name> に送信/名前設定する" +#, c-format +msgid "E5421: Failed to open stdin: %s" +msgstr "E5421: 標準入力を開けませんでした: %s" -msgid "--startuptime <file>\tWrite startup timing messages to <file>" -msgstr "--startuptime <file>\t起動にかかった時間の詳細を <file> へ出力する" +#, c-format +msgid "Attempt to open script file again: \"%s %s\"\n" +msgstr "スクリプトファイルを再び開こうとしました: \"%s %s\"\n" -msgid "-i <viminfo>\t\tUse <viminfo> instead of .viminfo" -msgstr "-i <viminfo>\t\t.viminfoの代わりに <viminfo> を使う" +msgid "--embed conflicts with -es/-Es/-l" +msgstr "--embed が -es/-Es/-l と競合しています" -msgid "--clean\t\t'nocompatible', Vim defaults, no plugins, no viminfo" -msgstr "--clean\t\t'nocompatible'、Vimの既定、プラグインなし、viminfoなし" +msgid "pre-vimrc command line" +msgstr "vimrc前のコマンドライン" -msgid "-h or --help\tPrint Help (this message) and exit" -msgstr "-h or --help\tヘルプ(このメッセージ)を表示し終了する" +#, c-format +msgid "E5422: Conflicting configs: \"%s\" \"%s\"" +msgstr "E5422: 設定が競合しています: \"%s\" \"%s\"" -msgid "--version\t\tPrint version information and exit" -msgstr "--version\t\tバージョン情報を表示し終了する" +#, c-format +msgid "E282: Cannot read from \"%s\"" +msgstr "E282: \"%s\" から読込むことができません" +#, c-format msgid "" "\n" -"Arguments recognised by gvim (Motif version):\n" +"More info with \"" msgstr "" "\n" -"gvimによって解釈される引数(Motifバージョン):\n" +"より詳細な情報は: \"" -msgid "" -"\n" -"Arguments recognised by gvim (neXtaw version):\n" -msgstr "" -"\n" -"gvimによって解釈される引数(neXtawバージョン):\n" +#, c-format +msgid "Usage:\n" +msgstr "使用法:\n" +#, c-format +msgid " nvim [options] [file ...]\n" +msgstr " nvim [オプション] [ファイル...]\n" + +#, c-format msgid "" "\n" -"Arguments recognised by gvim (Athena version):\n" +"Options:\n" msgstr "" "\n" -"gvimによって解釈される引数(Athenaバージョン):\n" - -msgid "-display <display>\tRun Vim on <display>" -msgstr "-display <display>\t<display> でvimを実行する" - -msgid "-iconic\t\tStart Vim iconified" -msgstr "-iconic\t\t最小化した状態でvimを起動する" +"オプション:\n" -msgid "-background <color>\tUse <color> for the background (also: -bg)" -msgstr "-background <color>\t背景色に <color> を使う(同義: -bg)" +#, c-format +msgid " --cmd <cmd> Execute <cmd> before any config\n" +msgstr " --cmd <cmd> 設定をロードする前に <cmd> を実行する\n" -msgid "-foreground <color>\tUse <color> for normal text (also: -fg)" -msgstr "-foreground <color>\t前景色に <color> を使う(同義: -fg)" +#, c-format +msgid " +<cmd>, -c <cmd> Execute <cmd> after config and first file\n" +msgstr "" +" +<cmd>, -c <cmd> 最初のファイルと設定をロード後 <cmd> を実行する\n" -msgid "-font <font>\t\tUse <font> for normal text (also: -fn)" -msgstr "-font <font>\t\tテキスト表示に <font> を使う(同義: -fn)" +#, c-format +msgid " -l <script> [args...] Execute Lua <script> (with optional args)\n" +msgstr " -l <script> [引数...] Lua <script> を実行する (任意で引数を指定)\n" -msgid "-boldfont <font>\tUse <font> for bold text" -msgstr "-boldfont <font>\t太字に <font> を使う" +#, c-format +msgid " -S <session> Source <session> after loading the first file\n" +msgstr " -S <session> 最初のファイルをロード後 <session> を取込む\n" -msgid "-italicfont <font>\tUse <font> for italic text" -msgstr "-italicfont <for>\t斜体字に <font> を使う" +#, c-format +msgid " -s <scriptin> Read Normal mode commands from <scriptin>\n" +msgstr " -s <scriptin> <scriptin> からノーマルコマンドを読込む\n" -msgid "-geometry <geom>\tUse <geom> for initial geometry (also: -geom)" -msgstr "-geometry <geom>\t初期配置に <geom> を使う(同義: -geom)" +#, c-format +msgid " -u <config> Use this config file\n" +msgstr " -u <config> この設定ファイルを使用する\n" -msgid "-borderwidth <width>\tUse a border width of <width> (also: -bw)" -msgstr "-borderwidth <width>\t境界の幅を <width> にする(同義: -bw)" +#, c-format +msgid " -d Diff mode\n" +msgstr " -d 差分モード\n" -msgid "-scrollbarwidth <width> Use a scrollbar width of <width> (also: -sw)" -msgstr "" -"-scrollbarwidth <width> スクロールバーの幅を <width> にする(同義: -sw)" +#, c-format +msgid " -es, -Es Silent (batch) mode\n" +msgstr " -es, -Es サイレント(バッチ)モード\n" -msgid "-menuheight <height>\tUse a menu bar height of <height> (also: -mh)" -msgstr "-menuheight <height>\tメニューバーの高さを <height> にする(同義: -mh)" +#, c-format +msgid " -h, --help Print this help message\n" +msgstr " -h, --help このヘルプメッセージを表示する\n" -msgid "-reverse\t\tUse reverse video (also: -rv)" -msgstr "-reverse\t\t反転映像を使用する(同義: -rv)" +#, c-format +msgid " -i <shada> Use this shada file\n" +msgstr " -i <shada> この ShaDa ファイルを使用する\n" -msgid "+reverse\t\tDon't use reverse video (also: +rv)" -msgstr "+reverse\t\t反転映像を使用しない(同義: +rv)" +#, c-format +msgid " -n No swap file, use memory only\n" +msgstr " -n スワップファイルを使用せずメモリだけ\n" -msgid "-xrm <resource>\tSet the specified resource" -msgstr "-xrm <resource>\t特定のリソースを使用する" +#, c-format +msgid " -o[N] Open N windows (default: one per file)\n" +msgstr "" +" -o[N] N 個ウィンドウを開く(既定値: ファイルにつき1個)\n" +#, c-format msgid "" -"\n" -"Arguments recognised by gvim (GTK+ version):\n" +" -O[N] Open N vertical windows (default: one per file)\n" msgstr "" -"\n" -"gvimによって解釈される引数(GTK+バージョン):\n" +" -O[N] N 個垂直ウィンドウを開く(既定値: ファイルにつき1個)\n" -msgid "-display <display>\tRun Vim on <display> (also: --display)" -msgstr "-display <display>\t<display> でVimを実行する(同義: --display)" +#, c-format +msgid " -p[N] Open N tab pages (default: one per file)\n" +msgstr "" +" -p[N] N 個タブページを開く(既定値: ファイルにつき1個)\n" -msgid "--role <role>\tSet a unique role to identify the main window" -msgstr "--role <role>\tメインウィンドウを識別する一意な役割(role)を設定する" +#, c-format +msgid " -R Read-only (view) mode\n" +msgstr " -R 読込専用 (view) モード\n" -msgid "--socketid <xid>\tOpen Vim inside another GTK widget" -msgstr "--socketid <xid>\t異なるGTK widgetでVimを開く" +#, c-format +msgid " -v, --version Print version information\n" +msgstr " -v, --version バージョン情報を表示する\n" -msgid "--echo-wid\t\tMake gvim echo the Window ID on stdout" -msgstr "--echo-wid\t\tウィンドウIDを標準出力に出力する" +#, c-format +msgid " -V[N][file] Verbose [level][file]\n" +msgstr " -V[N][ファイル] ログ出力設定 [レベル] [ファイル]\n" -msgid "-P <parent title>\tOpen Vim inside parent application" -msgstr "-P <親のタイトル>\tVimを親アプリケーションの中で起動する" +#, c-format +msgid " -- Only file names after this\n" +msgstr " -- このあとにはファイル名だけ\n" -msgid "--windowid <HWND>\tOpen Vim inside another win32 widget" -msgstr "--windowid <HWND>\t異なるWin32 widgetの内部にVimを開く" +#, c-format +msgid " --api-info Write msgpack-encoded API metadata to stdout\n" +msgstr "" +" --api-info 標準出力にmsgpackにエンコードされたAPIメタデータを出" +"力\n" -msgid "No display" -msgstr "ディスプレイが見つかりません" +#, c-format +msgid "" +" --clean \"Factory defaults\" (skip user config and plugins, " +"shada)\n" +msgstr "" +" --clean \"工場出荷状態\" (設定とプラグイン、shadaをスキッ" +"プ)\n" + +#, c-format +msgid " --embed Use stdin/stdout as a msgpack-rpc channel\n" +msgstr " --embed msgpack-rpc チャネルに標準入出力を使用する\n" + +#, c-format +msgid " --headless Don't start a user interface\n" +msgstr " --headless ユーザーインターフェースを起動しない\n" -msgid ": Send failed.\n" -msgstr ": 送信に失敗しました.\n" +#, c-format +msgid " --listen <address> Serve RPC API from this address\n" +msgstr " --listen <address> このアドレスから RPC API を受け取る\n" -msgid ": Send failed. Trying to execute locally\n" -msgstr ": 送信に失敗しました。ローカルでの実行を試みています\n" +#, c-format +msgid " --remote[-subcommand] Execute commands remotely on a server\n" +msgstr " --remote[-subcommand] サーバー上でコマンドをリモート実行する\n" #, c-format -msgid "%d of %d edited" -msgstr "%d 個 (%d 個中) のファイルを編集しました" +msgid " --server <address> Specify RPC server to send commands to\n" +msgstr " --server <address> コマンドを送信する RPC サーバーを指定する\n" -msgid "No display: Send expression failed.\n" -msgstr "ディスプレイがありません: 式の送信に失敗しました.\n" +#, c-format +msgid " --startuptime <file> Write startup timing messages to <file>\n" +msgstr " --startuptime <file> 起動にかかった時間の詳細を <file> へ出力する\n" -msgid ": Send expression failed.\n" -msgstr ": 式の送信に失敗しました.\n" +#, c-format +msgid "" +"\n" +"See \":help startup-options\" for all options.\n" +msgstr "" +"\n" +"すべてのオプションについては ':help startup-options' を参照してください。\n" #, c-format -msgid "E224: global abbreviation already exists for %s" +msgid "E224: Global abbreviation already exists for %s" msgstr "E224: %s というグローバル短縮入力は既に存在します" #, c-format -msgid "E225: global mapping already exists for %s" +msgid "E225: Global mapping already exists for %s" msgstr "E225: %s というグローバルマッピングは既に存在します" #, c-format -msgid "E226: abbreviation already exists for %s" +msgid "E226: Abbreviation already exists for %s" msgstr "E226: %s という短縮入力は既に存在します" #, c-format -msgid "E227: mapping already exists for %s" +msgid "E227: Mapping already exists for %s" msgstr "E227: %s というマッピングは既に存在します" +msgid "E460: Entries missing in mapset() dict argument" +msgstr "E460: mapset() の辞書引数の要素が足りません" + +#, c-format +msgid "E1276: Illegal map mode string: '%s'" +msgstr "E1276: 不正なマップモード文字列です: '%s'" + msgid "No abbreviation found" msgstr "短縮入力は見つかりませんでした" @@ -2985,7 +4630,7 @@ msgid "No mapping found" msgstr "マッピングは見つかりませんでした" msgid "E228: makemap: Illegal mode" -msgstr "E228: makemap: 不正なモード" +msgstr "E228: makemap: 無効なモード" #, c-format msgid "E357: 'langmap': Matching character missing for %s" @@ -3021,58 +4666,76 @@ msgid "" "change line col text" msgstr "" "\n" -"変更 行 列 テキスト" +"変更 行 列 テキスト" -msgid "" -"\n" -"# File marks:\n" -msgstr "" -"\n" -"# ファイルマーク:\n" +#, c-format +msgid "E799: Invalid ID: %<PRId64> (must be greater than or equal to 1)" +msgstr "E799: 無効な ID: %<PRId64> (1 以上でなければなりません)" -msgid "" -"\n" -"# Jumplist (newest first):\n" -msgstr "" -"\n" -"# ジャンプリスト (新しいものが先):\n" +#, c-format +msgid "E801: ID already taken: %<PRId64>" +msgstr "E801: ID は既に利用中です: %<PRId64>" -msgid "" -"\n" -"# History of marks within files (newest to oldest):\n" -msgstr "" -"\n" -"# ファイル内マークの履歴 (新しいものから古いもの):\n" +#, c-format +msgid "E5030: Empty list at position %d" +msgstr "E5030: 位置 %d に空のリストがあります" + +#, c-format +msgid "E5031: List or number required at position %d" +msgstr "E5031: 位置 %d にはリストまたは数値が必要です" + +#, c-format +msgid "E802: Invalid ID: %<PRId64> (must be greater than or equal to 1)" +msgstr "E802: 無効な ID: %<PRId64> (1 以上でなければなりません)" -msgid "Missing '>'" -msgstr "'>' が見つかりません" +#, c-format +msgid "E803: ID not found: %<PRId64>" +msgstr "E803: ID はありません: %<PRId64>" -msgid "E543: Not a valid codepage" -msgstr "E543: 無効なコードページです" +#, c-format +msgid "E474: List item %d is either not a dictionary or an empty one" +msgstr "E474: リスト要素 %d は辞書でないか、空です。" -msgid "E284: Cannot set IC values" -msgstr "E284: ICの値を設定できません" +#, c-format +msgid "E474: List item %d is missing one of the required keys" +msgstr "E474: リスト要素 %d に必要なキーの 1 つがありません" -msgid "E285: Failed to create input context" -msgstr "E285: インプットコンテキストの作成に失敗しました" +#, c-format +msgid "E798: ID is reserved for \":match\": %<PRId64>" +msgstr "E798: ID は \":match\" のために予約されています: %<PRId64>" -msgid "E286: Failed to open input method" -msgstr "E286: インプットメソッドのオープンに失敗しました" +#, c-format +msgid "E798: ID is reserved for \"match\": %<PRId64>" +msgstr "E798: ID は \":match\" のために予約されています: %<PRId64>" -msgid "E287: Warning: Could not set destroy callback to IM" -msgstr "E287: 警告: IMの破壊コールバックを設定できませんでした" +#, c-format +msgid "E1109: List item %d is not a List" +msgstr "E1109: リストの要素 %d はリストではありません" -msgid "E288: input method doesn't support any style" -msgstr "E288: インプットメソッドはどんなスタイルもサポートしません" +#, c-format +msgid "E1110: List item %d does not contain 3 numbers" +msgstr "E1110: リストの要素 %d は数値を 3 個含んでいません" -msgid "E289: input method doesn't support my preedit type" -msgstr "E289: インプットメソッドは my preedit type をサポートしません" +#, c-format +msgid "E1111: List item %d range invalid" +msgstr "E1111: リストの要素 %d の範囲が不正です" -msgid "E293: block was not locked" +#, c-format +msgid "E1112: List item %d cell width invalid" +msgstr "E1112: リストの要素 %d のセル幅が不正です" + +#, c-format +msgid "E1113: Overlapping ranges for 0x%lx" +msgstr "E1113: 0x%lx の範囲が重複しています" + +msgid "E1114: Only values of 0x80 and higher supported" +msgstr "E1114: 0x80 以上の値しかサポートされていません" + +msgid "E293: Block was not locked" msgstr "E293: ブロックがロックされていません" msgid "E294: Seek error in swap file read" -msgstr "E294: スワップファイル読込時にシークエラーです" +msgstr "E294: スワップファイル読込み時にシークエラーです" msgid "E295: Read error in swap file" msgstr "E295: スワップファイルの読込みエラーです" @@ -3086,17 +4749,45 @@ msgstr "E297: スワップファイルの書込みエラーです" msgid "E300: Swap file already exists (symlink attack?)" msgstr "E300: スワップファイルが既に存在します (symlinkによる攻撃?)" +#, c-format +msgid "E315: ml_get: Invalid lnum: %<PRId64>" +msgstr "E315: ml_get: 無効な lnum: %<PRId64>" + +#, c-format +msgid "E316: ml_get: Cannot find line %<PRId64>in buffer %d %s" +msgstr "E316: ml_get: 行 %<PRId64> がバッファ %d %s に見つかりません" + +msgid "E317: Pointer block id wrong" +msgstr "E317: ポインタブロック ID が間違っています" + +msgid "E317: Pointer block id wrong 2" +msgstr "E317: ポインタブロック ID が間違っています 2" + +msgid "E317: Pointer block id wrong 3" +msgstr "E317: ポインタブロック ID が間違っています 3" + +msgid "E317: Pointer block id wrong 4" +msgstr "E317: ポインタブロック ID が間違っています 4" + +#, c-format +msgid "E322: Line number out of range: %<PRId64> past the end" +msgstr "E322: 行番号が範囲外です: %<PRId64> が末尾を超えています" + +#, c-format +msgid "E323: Line count wrong in block %<PRId64>" +msgstr "E323: ブロック %<PRId64> の行数が間違っています" + +msgid "E1364: Warning: Pointer block corrupted" +msgstr "E1364: 警告: ポインタブロックが壊れています" + msgid "E298: Didn't get block nr 0?" -msgstr "E298: ブロック 0 を取得できません?" +msgstr "E298: ブロック 0 を取得できませんでしたか?" msgid "E298: Didn't get block nr 1?" -msgstr "E298: ブロック 1 を取得できません?" +msgstr "E298: ブロック 1 を取得できませんでしたか?" msgid "E298: Didn't get block nr 2?" -msgstr "E298: ブロック 2 を取得できません?" - -msgid "E843: Error while updating swap file crypt" -msgstr "E843: スワップファイルの暗号を更新中にエラーが発生しました" +msgstr "E298: ブロック 2 を取得できませんでしたか?" msgid "E301: Oops, lost the swap file!!!" msgstr "E301: おっと、スワップファイルが失われました!!!" @@ -3109,7 +4800,7 @@ msgid "E303: Unable to open swap file for \"%s\", recovery impossible" msgstr "E303: \"%s\" のスワップファイルを開けないのでリカバリは不可能です" msgid "E304: ml_upd_block0(): Didn't get block 0??" -msgstr "E304: ml_upd_block0(): ブロック 0 を取得できませんでした??" +msgstr "E304: ml_upd_block0(): ブロック 0 を取得できませんでしたか??" #, c-format msgid "E305: No swap file found for %s" @@ -3155,12 +4846,6 @@ msgstr "" ",\n" "もしくはファイルが損傷しています。" -#, c-format -msgid "" -"E833: %s is encrypted and this version of Vim does not support encryption" -msgstr "" -"E833: %s はこのバージョンのVimでサポートしていない形式で暗号化されています" - msgid " has been damaged (page size is smaller than minimum value).\n" msgstr " は損傷しています (ページサイズが最小値を下回っています).\n" @@ -3176,38 +4861,6 @@ msgid "E308: Warning: Original file may have been changed" msgstr "E308: 警告: 原本ファイルが変更されています" #, c-format -msgid "Swap file is encrypted: \"%s\"" -msgstr "スワップファイルは暗号化されています: \"%s\"" - -msgid "" -"\n" -"If you entered a new crypt key but did not write the text file," -msgstr "" -"\n" -"新しい暗号キーを入力したあとにテキストファイルを保存していない場合は、" - -msgid "" -"\n" -"enter the new crypt key." -msgstr "" -"\n" -"新しい暗号キーを入力してください。" - -msgid "" -"\n" -"If you wrote the text file after changing the crypt key press enter" -msgstr "" -"\n" -"暗号キーを変えたあとにテキストファイルを保存した場合は、テキストファイルと" - -msgid "" -"\n" -"to use the same key for text file and swap file" -msgstr "" -"\n" -"スワップファイルに同じ暗号キーを使うためにenterだけを押してください。" - -#, c-format msgid "E309: Unable to read block 1 from %s" msgstr "E309: %s からブロック 1 を読込めません" @@ -3236,6 +4889,9 @@ msgstr "??? ここから ???END までの行が破壊されているようです msgid "??? from here until ???END lines may have been inserted/deleted" msgstr "??? ここから ???END までの行が挿入か削除されたようです" +msgid "??? lines may be missing" +msgstr "???行がないようです" + msgid "???END" msgstr "???END" @@ -3268,15 +4924,17 @@ msgstr "復元完了。バッファの内容はファイルと同じになりま msgid "" "\n" -"You may want to delete the .swp file now.\n" -"\n" +"You may want to delete the .swp file now." msgstr "" "\n" -"元の.swpファイルは削除しても構いません\n" -"\n" +"元の.swpファイルは削除しても構いません。" -msgid "Using crypt key from swap file for the text file.\n" -msgstr "スワップファイルから取得した暗号キーをテキストファイルに使います.\n" +msgid "" +"\n" +"Note: process STILL RUNNING: " +msgstr "" +"\n" +"注意: プロセスはまだ実行中です: " msgid "Swap files found:" msgstr "スワップファイルが複数見つかりました:" @@ -3293,9 +4951,6 @@ msgstr " ディレクトリ " msgid " -- none --\n" msgstr " -- なし --\n" -msgid "%a %b %d %H:%M:%S %Y" -msgstr "%Y/%m/%d (%a) %H:%M:%S" - msgid " owned by: " msgstr " 所有者: " @@ -3311,6 +4966,10 @@ msgstr " [from Vim version 3.0]" msgid " [does not look like a Vim swap file]" msgstr " [Vimのスワップファイルではないようです]" +#, fuzzy +#~ msgid " [garbled strings (not nul terminated)]" +#~ msgstr " [文字化けした文字列 (nul で終了していない)]" + msgid " file name: " msgstr " ファイル名: " @@ -3351,18 +5010,11 @@ msgstr "" "\n" " プロセスID: " -msgid " (still running)" +msgid " (STILL RUNNING)" msgstr " (まだ実行中)" msgid "" "\n" -" [not usable with this version of Vim]" -msgstr "" -"\n" -" [このVimバージョンでは使用できません]" - -msgid "" -"\n" " [not usable on this computer]" msgstr "" "\n" @@ -3383,53 +5035,25 @@ msgstr "ファイルが維持されます" msgid "E314: Preserve failed" msgstr "E314: 維持に失敗しました" -#, c-format -msgid "E315: ml_get: invalid lnum: %ld" -msgstr "E315: ml_get: 無効なlnumです: %ld" - -#, c-format -msgid "E316: ml_get: cannot find line %ld in buffer %d %s" -msgstr "E316: ml_get: 行 %ld をバッファ %d %s 内に見つけられません" - -msgid "E317: pointer block id wrong 3" -msgstr "E317: ポインタブロックのIDが間違っています 3" - msgid "stack_idx should be 0" msgstr "stack_idx は 0 であるべきです" msgid "E318: Updated too many blocks?" -msgstr "E318: 更新されたブロックが多過ぎるかも?" - -msgid "E317: pointer block id wrong 4" -msgstr "E317: ポインタブロックのIDが間違っています 4" +msgstr "E318: 更新されたブロックが多すぎますか?" msgid "deleted block 1?" msgstr "ブロック 1 は消された?" #, c-format -msgid "E320: Cannot find line %ld" -msgstr "E320: 行 %ld が見つかりません" - -msgid "E317: pointer block id wrong" -msgstr "E317: ポインタブロックのIDが間違っています" +msgid "E320: Cannot find line %<PRId64>" +msgstr "E320: 行 %<PRId64> が見つかりません" msgid "pe_line_count is zero" msgstr "pe_line_count がゼロです" -#, c-format -msgid "E322: line number out of range: %ld past the end" -msgstr "E322: 行番号が範囲外です: %ld 超えています" - -#, c-format -msgid "E323: line count wrong in block %ld" -msgstr "E323: ブロック %ld の行カウントが間違っています" - msgid "Stack size increases" msgstr "スタックサイズが増えます" -msgid "E317: pointer block id wrong 2" -msgstr "E317: ポインタブロックのIDが間違っています 2" - #, c-format msgid "E773: Symlink loop for \"%s\"" msgstr "E773: \"%s\" のシンボリックリンクがループになっています" @@ -3447,6 +5071,9 @@ msgstr "" msgid "While opening file \"" msgstr "次のファイルを開いている最中 \"" +msgid " CANNOT BE FOUND" +msgstr " 見つかりません" + msgid " NEWER than swap file!\n" msgstr " スワップファイルよりも新しいです!\n" @@ -3485,6 +5112,9 @@ msgstr "" "\"\n" " を消せばこのメッセージを回避できます.\n" +msgid "Found a swap file that is not useful, deleting it" +msgstr "不要なスワップファイルが見つかりました。削除します" + msgid "Swap file \"" msgstr "スワップファイル \"" @@ -3494,9 +5124,6 @@ msgstr "\" が既にあります!" msgid "VIM - ATTENTION" msgstr "VIM - 注意" -msgid "Swap file already exists!" -msgstr "スワップファイルが既に存在します!" - msgid "" "&Open Read-Only\n" "&Edit anyway\n" @@ -3528,12 +5155,24 @@ msgstr "" msgid "E326: Too many swap files found" msgstr "E326: スワップファイルが多数見つかりました" +#, c-format +msgid "" +"E303: Unable to create directory \"%s\" for swap file, recovery impossible: " +"%s" +msgstr "" +"E303: スワップファイルの為のディレクトリ \"%s\" を作成できませんでした。リカ" +"バリは不可能です: %s" + +msgid "Vim: Data too large to fit into virtual memory space\n" +msgstr "Vim: データが大きすぎて仮想メモリ空間に収まりません\n" + +#, c-format +msgid "E342: Out of memory! (allocating %<PRIu64> bytes)" +msgstr "E342: メモリが足りません! (%<PRIu64> バイトを割当要求)" + msgid "E327: Part of menu-item path is not sub-menu" msgstr "E327: メニューアイテムのパスの部分がサブメニューではありません" -msgid "E328: Menu only exists in another mode" -msgstr "E328: メニューは他のモードにだけあります" - #, c-format msgid "E329: No menu \"%s\"" msgstr "E329: \"%s\" というメニューはありません" @@ -3557,9 +5196,6 @@ msgstr "" "\n" "--- メニュー ---" -msgid "Tear off this menu" -msgstr "このメニューを切り取る" - #, c-format msgid "E335: Menu not defined for %s mode" msgstr "E335: %s にはメニューが定義されていません" @@ -3581,17 +5217,13 @@ msgstr "E337: メニューが見つかりません - メニュー名を確認し msgid "Error detected while processing %s:" msgstr "%s の処理中にエラーが検出されました:" -#, c-format -msgid "line %4ld:" -msgstr "行 %4ld:" +#~ msgid "line %4" +#~ msgstr "" #, c-format msgid "E354: Invalid register name: '%s'" msgstr "E354: 無効なレジスタ名: '%s'" -msgid "Messages maintainer: Bram Moolenaar <Bram@vim.org>" -msgstr "日本語メッセージ翻訳/監修: 村岡 太郎 <koron.kaoriya@gmail.com>" - msgid "Interrupt: " msgstr "割込み: " @@ -3599,8 +5231,21 @@ msgid "Press ENTER or type command to continue" msgstr "続けるにはENTERを押すかコマンドを入力してください" #, c-format -msgid "%s line %ld" -msgstr "%s 行 %ld" +msgid "%d more line" +msgid_plural "%d more lines" +msgstr[0] "%d 行 追加しました" + +#, c-format +msgid "%d line less" +msgid_plural "%d fewer lines" +msgstr[0] "%d 行 削除しました" + +msgid " (Interrupted)" +msgstr " (割込まれました)" + +#, c-format +msgid "%s line %<PRId64>" +msgstr "%s 行 %<PRId64>" msgid "-- More --" msgstr "-- 継続 --" @@ -3621,6 +5266,15 @@ msgstr "" msgid "" "&Yes\n" "&No\n" +"&Cancel" +msgstr "" +"はい(&Y)\n" +"いいえ(&N)\n" +"キャンセル(&C)" + +msgid "" +"&Yes\n" +"&No\n" "Save &All\n" "&Discard All\n" "&Cancel" @@ -3631,299 +5285,152 @@ msgstr "" "全て放棄(&D)\n" "キャンセル(&C)" -msgid "E766: Insufficient arguments for printf()" -msgstr "E766: printf() の引数が不十分です" - -msgid "E807: Expected Float argument for printf()" -msgstr "E807: printf() の引数には浮動小数点数が期待されています" - -msgid "E767: Too many arguments to printf()" -msgstr "E767: printf() の引数が多過ぎます" - -msgid "Type number and <Enter> or click with mouse (empty cancels): " -msgstr "" -"番号と<Enter>を入力するかマウスでクリックしてください (空でキャンセル): " - -msgid "Type number and <Enter> (empty cancels): " -msgstr "番号と<Enter>を入力してください (空でキャンセル): " - -msgid "1 more line" -msgstr "1 行 追加しました" - -msgid "1 line less" -msgstr "1 行 削除しました" - -#, c-format -msgid "%ld more lines" -msgstr "%ld 行 追加しました" - -#, c-format -msgid "%ld fewer lines" -msgstr "%ld 行 削除しました" - -msgid " (Interrupted)" -msgstr " (割込まれました)" - -msgid "Beep!" -msgstr "ビーッ!" - -#, c-format -msgid "%ld second ago" -msgid_plural "%ld seconds ago" -msgstr[0] "%ld 秒経過しています" - -msgid "ERROR: " -msgstr "エラー: " - -#, c-format -msgid "" -"\n" -"[bytes] total alloc-freed %lu-%lu, in use %lu, peak use %lu\n" -msgstr "" -"\n" -"[メモリ(バイト)] 総割当-解放量 %lu-%lu, 使用量 %lu, ピーク時 %lu\n" - -#, c-format -msgid "" -"[calls] total re/malloc()'s %lu, total free()'s %lu\n" -"\n" -msgstr "" -"[呼出] 総 re/malloc() 回数 %lu, 総 free() 回数 %lu\n" -"\n" - -msgid "E341: Internal error: lalloc(0, )" -msgstr "E341: 内部エラー: lalloc(0, )" - -#, c-format -msgid "E342: Out of memory! (allocating %lu bytes)" -msgstr "E342: メモリが足りません! (%lu バイトを割当要求)" - -#, c-format -msgid "Calling shell to execute: \"%s\"" -msgstr "実行のためにシェルを呼出し中: \"%s\"" - -msgid "E545: Missing colon" -msgstr "E545: コロンがありません" - -msgid "E546: Illegal mode" -msgstr "E546: 不正なモードです" - -msgid "E547: Illegal mouseshape" -msgstr "E547: 不正な 'mouseshape' です" - -msgid "E548: digit expected" -msgstr "E548: 数値が必要です" - -msgid "E549: Illegal percentage" -msgstr "E549: 不正なパーセンテージです" - -msgid "E854: path too long for completion" -msgstr "E854: パスが長過ぎて補完できません" - -#, c-format -msgid "" -"E343: Invalid path: '**[number]' must be at the end of the path or be " -"followed by '%s'." -msgstr "" -"E343: 無効なパスです: '**[数値]' はpathの最後か '%s' が続いてないといけませ" -"ん." - -#, c-format -msgid "E344: Can't find directory \"%s\" in cdpath" -msgstr "E344: cdpathには \"%s\" というファイルがありません" - -#, c-format -msgid "E345: Can't find file \"%s\" in path" -msgstr "E345: pathには \"%s\" というファイルがありません" - -#, c-format -msgid "E346: No more directory \"%s\" found in cdpath" -msgstr "E346: cdpathにはこれ以上 \"%s\" というファイルがありません" - -#, c-format -msgid "E347: No more file \"%s\" found in path" -msgstr "E347: パスにはこれ以上 \"%s\" というファイルがありません" - -#, c-format -msgid "E668: Wrong access mode for NetBeans connection info file: \"%s\"" -msgstr "" -"E668: NetBeansの接続情報ファイルのアクセスモードに問題があります: \"%s\"" - -#, c-format -msgid "E658: NetBeans connection lost for buffer %ld" -msgstr "E658: バッファ %ld の NetBeans 接続が失われました" - -msgid "E838: netbeans is not supported with this GUI" -msgstr "E838: NetBeansはこのGUIには対応していません" - -msgid "E511: netbeans already connected" -msgstr "E511: NetBeansは既に接続しています" +msgid "E664: Changelist is empty" +msgstr "E664: 変更リストが空です" -#, c-format -msgid "E505: %s is read-only (add ! to override)" -msgstr "E505: %s は読込専用です (強制書込には ! を追加)" +msgid "E1292: Command-line window is already open" +msgstr "E1292: コマンドラインウィンドウは既に開かれています" msgid "E349: No identifier under cursor" msgstr "E349: カーソルの位置には識別子がありません" -msgid "Warning: terminal cannot highlight" -msgstr "警告: 使用している端末はハイライトできません" - msgid "E348: No string under cursor" msgstr "E348: カーソルの位置には文字列がありません" msgid "E352: Cannot erase folds with current 'foldmethod'" msgstr "E352: 現在の 'foldmethod' では折畳みを消去できません" -msgid "E664: changelist is empty" -msgstr "E664: 変更リストが空です" - msgid "E662: At start of changelist" msgstr "E662: 変更リストの先頭" msgid "E663: At end of changelist" msgstr "E663: 変更リストの末尾" -msgid "Type :qa! and press <Enter> to abandon all changes and exit Vim" +msgid "Type :qa! and press <Enter> to abandon all changes and exit Nvim" msgstr "" -"すべての変更を破棄し、Vimを終了するには :qa! と入力し <Enter> を押してくだ" +"すべての変更を破棄し、Nvimを終了するには :qa! と入力し <Enter> を押してくだ" "さい" -#, c-format -msgid "1 line %sed 1 time" -msgstr "1 行が %s で 1 回処理されました" +msgid "Type :qa and press <Enter> to exit Nvim" +msgstr "Nvimを終了するには :qa と入力し <Enter> を押してください" -#, c-format -msgid "1 line %sed %d times" -msgstr "1 行が %s で %d 回処理されました" +msgid "" +"E883: Search pattern and expression register may not contain two or more " +"lines" +msgstr "E883: 検索パターンと式レジスタには2行以上を含められません" #, c-format -msgid "%ld lines %sed 1 time" -msgstr "%ld 行が %s で 1 回処理されました" +msgid "%<PRId64> line %sed %d time" +msgid_plural "%<PRId64> line %sed %d times" +msgstr[0] "%<PRId64> 行が %s で %d 回処理されました" #, c-format -msgid "%ld lines %sed %d times" -msgstr "%ld 行が %s で %d 回処理されました" +msgid "%<PRId64> lines %sed %d time" +msgid_plural "%<PRId64> lines %sed %d times" +msgstr[0] "%<PRId64> 行が %s で %d 回処理されました" #, c-format -msgid "%ld lines to indent... " -msgstr "%ld 行がインデントされます... " - -msgid "1 line indented " -msgstr "1 行をインデントしました " +msgid "%<PRId64> lines to indent... " +msgstr "%<PRId64> 行がインデントされます... " #, c-format -msgid "%ld lines indented " -msgstr "%ld 行をインデントしました " - -msgid "cannot yank; delete anyway" -msgstr "ヤンクできません; とにかく消去" +msgid "%<PRId64> line indented " +msgid_plural "%<PRId64> lines indented " +msgstr[0] "%<PRId64> 行をインデントしました " -msgid "1 line changed" -msgstr "1 行が変更されました" +msgid "E748: No previously used register" +msgstr "E748: まだレジスタを使用していません" #, c-format -msgid "%ld lines changed" -msgstr "%ld 行が変更されました" +msgid "%<PRId64> line changed" +msgid_plural "%<PRId64> lines changed" +msgstr[0] "%<PRId64> 行が変更されました" #, c-format -msgid "block of 1 line yanked%s" -msgstr "1 行のブロックが%sヤンクされました" +msgid " into \"%c" +msgstr " \"%c に" #, c-format -msgid "1 line yanked%s" -msgstr "1 行が%sヤンクされました" +msgid "block of %<PRId64> line yanked%s" +msgid_plural "block of %<PRId64> lines yanked%s" +msgstr[0] "%<PRId64> 行のブロックが%sヤンクされました" #, c-format -msgid "block of %ld lines yanked%s" -msgstr "%ld 行のブロックが%sヤンクされました" +msgid "%<PRId64> line yanked%s" +msgid_plural "%<PRId64> lines yanked%s" +msgstr[0] "%<PRId64> 行が%sヤンクされました" #, c-format -msgid "%ld lines yanked%s" -msgstr "%ld 行が%sヤンクされました" - -msgid "" -"\n" -"--- Registers ---" -msgstr "" -"\n" -"--- レジスタ ---" - -msgid "Illegal register name" -msgstr "不正なレジスタ名" +msgid "E353: Nothing in register %s" +msgstr "E353: レジスタ %s には何もありません" msgid "" "\n" -"# Registers:\n" +"Type Name Content" msgstr "" "\n" -"# レジスタ:\n" +"型式 名前 内容" #, c-format -msgid "E574: Unknown register type %d" -msgstr "E574: 未知のレジスタ型 %d です" +msgid "%<PRId64> lines changed" +msgid_plural "%<PRId64> lines changed" +msgstr[0] "%<PRId64> 行が変更されました" #, c-format -msgid "%ld Cols; " -msgstr "%ld 列; " +msgid "%<PRId64> Cols; " +msgstr "%<PRId64> 列; " #, c-format -msgid "Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Bytes" -msgstr "選択 %s%ld / %ld 行; %lld / %lld 単語; %lld / %lld バイト" +msgid "" +"Selected %s%<PRId64> of %<PRId64> Lines; %<PRId64> of %<PRId64> Words; " +"%<PRId64> of %<PRId64> Bytes" +msgstr "" +"選択 %s%<PRId64> / %<PRId64> 行; %<PRId64> / %<PRId64> 単語; %<PRId64> / " +"%<PRId64> バイト" #, c-format msgid "" -"Selected %s%ld of %ld Lines; %lld of %lld Words; %lld of %lld Chars; %lld of " -"%lld Bytes" +"Selected %s%<PRId64> of %<PRId64> Lines; %<PRId64> of %<PRId64> Words; " +"%<PRId64> of %<PRId64> Chars; %<PRId64> of %<PRId64> Bytes" msgstr "" -"選択 %s%ld / %ld 行; %lld / %lld 単語; %lld / %lld 文字; %lld / %lld バイト" +"選択 %s%<PRId64> / %<PRId64> 行; %<PRId64> / %<PRId64> 単語; %<PRId64> / " +"%<PRId64> 文字; %<PRId64> / %<PRId64> バイト" #, c-format -msgid "Col %s of %s; Line %ld of %ld; Word %lld of %lld; Byte %lld of %lld" -msgstr "列 %s / %s; 行 %ld of %ld; 単語 %lld / %lld; バイト %lld / %lld" +msgid "" +"Col %s of %s; Line %<PRId64> of %<PRId64>; Word %<PRId64> of %<PRId64>; Byte " +"%<PRId64> of %<PRId64>" +msgstr "" +"列 %s / %s; 行 %<PRId64> of %<PRId64>; 単語 %<PRId64> / %<PRId64>; バイト " +"%<PRId64> / %<PRId64>" #, c-format msgid "" -"Col %s of %s; Line %ld of %ld; Word %lld of %lld; Char %lld of %lld; Byte " -"%lld of %lld" +"Col %s of %s; Line %<PRId64> of %<PRId64>; Word %<PRId64> of %<PRId64>; Char " +"%<PRId64> of %<PRId64>; Byte %<PRId64> of %<PRId64>" msgstr "" -"列 %s / %s; 行 %ld / %ld; 単語 %lld / %lld; 文字 %lld / %lld; バイト %lld of " -"%lld" +"列 %s / %s; 行 %<PRId64> / %<PRId64>; 単語 %<PRId64> / %<PRId64>; 文字 " +"%<PRId64> / %<PRId64>; バイト %<PRId64> of %<PRId64>" #, c-format -msgid "(+%lld for BOM)" -msgstr "(+%lld for BOM)" +msgid "(+%<PRId64> for BOM)" +msgstr "(+%<PRId64> for BOM)" msgid "E774: 'operatorfunc' is empty" msgstr "E774: 'operatorfunc' オプションが空です" -msgid "E775: Eval feature not available" -msgstr "E775: 式評価機能が無効になっています" - msgid "E518: Unknown option" msgstr "E518: 未知のオプションです" -msgid "E519: Option not supported" -msgstr "E519: オプションはサポートされていません" - msgid "E520: Not allowed in a modeline" msgstr "E520: modeline では許可されません" msgid "E992: Not allowed in a modeline when 'modelineexpr' is off" msgstr "E992: 'modelineexpr' がオフの時 modeline では許可されません" -msgid "E846: Key code not set" -msgstr "E846: キーコードが設定されていません" - msgid "E521: Number required after =" msgstr "E521: = の後には数字が必要です" -msgid "E522: Not found in termcap" -msgstr "E522: termcap 内に見つかりません" - -msgid "E946: Cannot make a terminal with running job modifiable" -msgstr "E946: 実行中のジョブがある端末は変更可能にできません" - msgid "E590: A preview window already exists" msgstr "E590: プレビューウィンドウが既に存在します" @@ -3931,9 +5438,6 @@ msgid "W17: Arabic requires UTF-8, do ':set encoding=utf-8'" msgstr "" "W17: アラビア文字にはUTF-8が必要なので、':set encoding=utf-8' してください" -msgid "E954: 24-bit colors are not supported on this environment" -msgstr "E954: 24bit色はこの環境ではサポートされていません" - #, c-format msgid "E593: Need at least %d lines" msgstr "E593: 最低 %d の行数が必要です" @@ -3942,20 +5446,12 @@ msgstr "E593: 最低 %d の行数が必要です" msgid "E594: Need at least %d columns" msgstr "E594: 最低 %d のカラム幅が必要です" -#, c-format -msgid "E355: Unknown option: %s" -msgstr "E355: 未知のオプションです: %s" +msgid "Cannot unset global option value" +msgstr "グローバルオプションの設定解除はできません" #, c-format -msgid "E521: Number required: &%s = '%s'" -msgstr "E521: 数字が必要です: &%s = '%s'" - -msgid "" -"\n" -"--- Terminal codes ---" -msgstr "" -"\n" -"--- 端末コード ---" +msgid "Invalid value for option '%s': expected %s, got %s %s" +msgstr "'%s' は無効なオプション値です: %s が必要でしたが %s %s でした" msgid "" "\n" @@ -3981,45 +5477,32 @@ msgstr "" msgid "E356: get_varp ERROR" msgstr "E356: get_varp エラー" -#, c-format -msgid "E539: Illegal character <%s>" -msgstr "E539: 不正な文字です <%s>" - -#, c-format -msgid "For option %s" -msgstr "オプション: %s" - msgid "E540: Unclosed expression sequence" msgstr "E540: 式が終了していません" +msgid "E536: Comma required" +msgstr "E536: コンマが必要です" -msgid "E542: unbalanced groups" +msgid "E542: Unbalanced groups" msgstr "E542: グループが釣合いません" -msgid "E529: Cannot set 'term' to empty string" -msgstr "E529: 'term' には空文字列を設定できません" - -msgid "E530: Cannot change term in GUI" -msgstr "E530: GUIでは 'term' を変更できません" - -msgid "E531: Use \":gui\" to start the GUI" -msgstr "E531: GUIをスタートするには \":gui\" を使用してください" - msgid "E589: 'backupext' and 'patchmode' are equal" msgstr "E589: 'backupext' と 'patchmode' が同じです" -msgid "E834: Conflicts with value of 'listchars'" -msgstr "E834: 'listchars'の値に矛盾があります" +msgid "E595: 'showbreak' contains unprintable or wide character" +msgstr "E595: 'showbreak' は表示できない文字かワイド文字を含んでいます" -msgid "E835: Conflicts with value of 'fillchars'" -msgstr "E835: 'fillchars'の値に矛盾があります" +#, c-format +msgid "E1511: Wrong number of characters for field \"%s\"" +msgstr "E1511: フィールド \"%s\" の文字数が間違っています" -msgid "E617: Cannot be changed in the GTK+ 2 GUI" -msgstr "E617: GTK+2 GUIでは変更できません" +#, c-format +msgid "E1512: Wrong character width for field \"%s\"" +msgstr "E1512: フィールド \"%s\" の文字幅が間違っています" #, c-format -msgid "E950: Cannot convert between %s and %s" -msgstr "E950: %s と %s の間で変換できません" +msgid "E539: Illegal character <%s>" +msgstr "E539: 不正な文字です <%s>" msgid "E524: Missing colon" msgstr "E524: コロンがありません" @@ -4028,174 +5511,61 @@ msgid "E525: Zero length string" msgstr "E525: 文字列の長さがゼロです" #, c-format -msgid "E526: Missing number after <%s>" -msgstr "E526: <%s> の後に数字がありません" - -msgid "E527: Missing comma" -msgstr "E527: カンマがありません" - -msgid "E528: Must specify a ' value" -msgstr "E528: ' の値を指定しなければなりません" - -msgid "E595: contains unprintable or wide character" -msgstr "E595: 表示できない文字かワイド文字を含んでいます" - -msgid "E596: Invalid font(s)" -msgstr "E596: 無効なフォントです" - -msgid "E597: can't select fontset" -msgstr "E597: フォントセットを選択できません" - -msgid "E598: Invalid fontset" -msgstr "E598: 無効なフォントセットです" - -msgid "E533: can't select wide font" -msgstr "E533: ワイドフォントを選択できません" - -msgid "E534: Invalid wide font" -msgstr "E534: 無効なワイドフォントです" - -#, c-format -msgid "E535: Illegal character after <%c>" -msgstr "E535: <%c> の後に不正な文字があります" - -msgid "E536: comma required" -msgstr "E536: カンマが必要です" - -#, c-format msgid "E537: 'commentstring' must be empty or contain %s" msgstr "E537: 'commentstring' は空であるか %s を含む必要があります" -msgid "cannot open " -msgstr "開けません " - -msgid "VIM: Can't open window!\n" -msgstr "VIM: ウィンドウを開けません!\n" - -msgid "Need Amigados version 2.04 or later\n" -msgstr "Amigadosのバージョン 2.04かそれ以降が必要です\n" - #, c-format -msgid "Need %s version %ld\n" -msgstr "%s のバージョン %ld が必要です\n" - -msgid "Cannot open NIL:\n" -msgstr "NILを開けません:\n" - -msgid "Cannot create " -msgstr "作成できません " - -#, c-format -msgid "Vim exiting with %d\n" -msgstr "Vimは %d で終了します\n" - -msgid "cannot change console mode ?!\n" -msgstr "コンソールモードを変更できません?!\n" - -msgid "mch_get_shellsize: not a console??\n" -msgstr "mch_get_shellsize: コンソールではない??\n" - -msgid "E360: Cannot execute shell with -f option" -msgstr "E360: -f オプションでシェルを実行できません" - -msgid "Cannot execute " -msgstr "実行できません " - -msgid "shell " -msgstr "シェル " - -msgid " returned\n" -msgstr " 戻りました\n" - -msgid "ANCHOR_BUF_SIZE too small." -msgstr "ANCHOR_BUF_SIZE が小さ過ぎます。" - -msgid "I/O ERROR" -msgstr "入出力エラー" - -msgid "Message" -msgstr "メッセージ" +msgid "E535: Illegal character after <%c>" +msgstr "E535: <%c> の後に不正な文字があります" -msgid "E237: Printer selection failed" -msgstr "E237: プリンタの選択に失敗しました" +msgid "E5080: Digit expected" +msgstr "E5080: 数値が必要です" #, c-format -msgid "to %s on %s" -msgstr "%s へ (%s 上の)" +msgid "E526: Missing number after <%s>" +msgstr "E526: <%s> の後に数字がありません" -#, c-format -msgid "E613: Unknown printer font: %s" -msgstr "E613: 未知のプリンタオプションです: %s" +msgid "E527: Missing comma" +msgstr "E527: コンマがありません" -#, c-format -msgid "E238: Print error: %s" -msgstr "E238: 印刷エラー: %s" +msgid "E528: Must specify a ' value" +msgstr "E528: ' の値を指定しなければなりません" -#, c-format -msgid "Printing '%s'" -msgstr "印刷しています: '%s'" +msgid "E834: Conflicts with value of 'listchars'" +msgstr "E834: 'listchars'の値に矛盾があります" -#, c-format -msgid "E244: Illegal charset name \"%s\" in font name \"%s\"" -msgstr "E244: 文字セット名 \"%s\" は不正です (フォント名 \"%s\")" +msgid "E835: Conflicts with value of 'fillchars'" +msgstr "E835: 'fillchars'の値に矛盾があります" #, c-format -msgid "E244: Illegal quality name \"%s\" in font name \"%s\"" -msgstr "E244: 品質名 \"%s\" は不正です (フォント名 \"%s\")" +msgid "dlerror = \"%s\"" +msgstr "dlerror = \"%s\"" #, c-format -msgid "E245: Illegal char '%c' in font name \"%s\"" -msgstr "E245: '%c' は不正な文字です (フォント名 \"%s\")" +msgid "E5420: Failed to write to file: %s" +msgstr "E5420: ファイルへの書き込みに失敗しました: %s" -#, c-format -msgid "Opening the X display took %ld msec" -msgstr "Xサーバーへの接続に %ld ミリ秒かかりました" +msgid "E1506: Buffer too small to copy xattr value or key" +msgstr "E1506: xattr値またはキーをコピーするのにバッファが小さすぎます" msgid "" -"\n" -"Vim: Got X error\n" -msgstr "" -"\n" -"Vim: X のエラーを検出しましたr\n" - -#, c-format -msgid "restoring display %s" -msgstr "ディスプレイ %s を復元しています" - -msgid "Testing the X display failed" -msgstr "X display のチェックに失敗しました" +"E1508: Size of the extended attribute value is larger than the maximum size " +"allowed" +msgstr "E1508: 拡張属性値のサイズが許可されている最大サイズを超えています" -msgid "Opening the X display timed out" -msgstr "X display の open がタイムアウトしました" - -msgid "" -"\n" -"Could not get security context for " -msgstr "" -"\n" -"セキュリティコンテキストを取得できません " +msgid "E1509: Error occurred when reading or writing extended attribute" +msgstr "E1509: 拡張属性の読込みまたは書込みでエラーが起きました" -msgid "" -"\n" -"Could not set security context for " -msgstr "" -"\n" -"セキュリティコンテキストを設定できません " +msgid "Vim: Error reading input, exiting...\n" +msgstr "Vim: 入力を読込み中のエラーにより終了します...\n" #, c-format -msgid "Could not set security context %s for %s" -msgstr "セキュリティコンテキスト %s を %s に設定できません" +msgid "Current %slanguage: \"%s\"" +msgstr "現在の %s言語: \"%s\"" #, c-format -msgid "Could not get security context %s for %s. Removing it!" -msgstr "セキュリティコンテキスト %s を %s から取得できません。削除します!" - -msgid "" -"\n" -"Cannot execute shell sh\n" -msgstr "" -"\n" -"sh シェルを実行できません\n" +msgid "E197: Cannot set language to \"%s\"" +msgstr "E197: 言語を \"%s\" に設定できません" msgid "" "\n" @@ -4206,98 +5576,31 @@ msgstr "" msgid "" "\n" -"Cannot create pipes\n" -msgstr "" -"\n" -"パイプを作成できません\n" - -msgid "" -"\n" -"Cannot fork\n" -msgstr "" -"\n" -"fork できません\n" - -msgid "" -"\n" -"Cannot execute shell " -msgstr "" -"\n" -"シェルを実行できません " - -msgid "" -"\n" -"Command terminated\n" +"shell failed to start: " msgstr "" "\n" -"コマンドを中断しました\n" - -msgid "XSMP lost ICE connection" -msgstr "XSMP がICE接続を失いました" - -#, c-format -msgid "dlerror = \"%s\"" -msgstr "dlerror = \"%s\"" - -msgid "Opening the X display failed" -msgstr "X display の open に失敗しました" - -msgid "XSMP handling save-yourself request" -msgstr "XSMP がsave-yourself要求を処理しています" - -msgid "XSMP opening connection" -msgstr "XSMP が接続を開始しています" - -msgid "XSMP ICE connection watch failed" -msgstr "XSMP ICE接続が失敗したようです" +"シェルの起動に失敗しました: " #, c-format -msgid "XSMP SmcOpenConnection failed: %s" -msgstr "XSMP SmcOpenConnectionが失敗しました: %s" - -msgid "At line" -msgstr "行" - -msgid "Could not load vim32.dll!" -msgstr "vim32.dll をロードできませんでした" - -msgid "VIM Error" -msgstr "VIMエラー" +msgid "E5677: Error writing input to shell-command: %s" +msgstr "E5677: シェルコマンドへの入力の書き込みエラー: %s" -msgid "Could not fix up function pointers to the DLL!" -msgstr "DLLから関数ポインタを取得できませんでした" +#, no-c-format +msgid "%a %b %d %H:%M:%S %Y" +msgstr "%Y/%m/%d (%a) %H:%M:%S" #, c-format -msgid "Vim: Caught %s event\n" -msgstr "Vim: イベント %s を検知\n" - -msgid "close" -msgstr "閉じる" - -msgid "logoff" -msgstr "ログオフ" - -msgid "shutdown" -msgstr "シャットダウン" - -msgid "E371: Command not found" -msgstr "E371: コマンドがありません" +msgid "E447: Can't find file \"%s\" in path" +msgstr "E447: pathには \"%s\" というファイルがありません" -msgid "" -"VIMRUN.EXE not found in your $PATH.\n" -"External commands will not pause after completion.\n" -"See :help win32-vimrun for more information." -msgstr "" -"VIMRUN.EXEが $PATH の中に見つかりません.\n" -"外部コマンドの終了後に一時停止をしません.\n" -"詳細は :help win32-vimrun を参照してください." +msgid "E750: First use \":profile start {fname}\"" +msgstr "E750: 初めに \":profile start {fname}\" を実行してください" -msgid "Vim Warning" -msgstr "Vimの警告" +msgid "E553: No more items" +msgstr "E553: 要素がもうありません" -#, c-format -msgid "shell returned %d" -msgstr "シェルがコード %d で終了しました" +msgid "E925: Current quickfix list was changed" +msgstr "E925: 現在の quickfix リストが変更されました" msgid "E926: Current location list was changed" msgstr "E926: 現在のロケーションリストが変更されました" @@ -4331,15 +5634,9 @@ msgstr "E378: 'errorformat' にパターンが指定されていません" msgid "E379: Missing or empty directory name" msgstr "E379: ディレクトリ名が無いか空です" -msgid "E553: No more items" -msgstr "E553: 要素がもうありません" - msgid "E924: Current window was closed" msgstr "E924: 現在のウィンドウが閉じられました" -msgid "E925: Current quickfix was changed" -msgstr "E925: 現在の quickfix が変更されました" - #, c-format msgid "(%d of %d)%s%s: " msgstr "(%d of %d)%s%s: " @@ -4349,7 +5646,7 @@ msgstr " (行が削除されました)" #, c-format msgid "%serror list %d of %d; %d errors " -msgstr "%s エラー一覧 %d of %d; %d 個エラー" +msgstr "%s エラー一覧 %d of %d; %d 個エラー " msgid "E380: At bottom of quickfix stack" msgstr "E380: quickfix スタックの末尾です" @@ -4360,9 +5657,6 @@ msgstr "E381: quickfix スタックの先頭です" msgid "No entries" msgstr "エントリがありません" -msgid "Error file" -msgstr "エラーファイル" - msgid "E683: File name missing or invalid pattern" msgstr "E683: ファイル名が無いか無効なパターンです" @@ -4370,17 +5664,35 @@ msgstr "E683: ファイル名が無いか無効なパターンです" msgid "Cannot open file \"%s\"" msgstr "ファイル \"%s\" を開けません" -msgid "E681: Buffer is not loaded" -msgstr "E681: バッファは読み込まれませんでした" +msgid "cannot have both a list and a \"what\" argument" +msgstr "リストと \"what\" 引数の両方を指定することはできません" msgid "E777: String or List expected" msgstr "E777: 文字列かリストが必要です" #, c-format -msgid "E369: invalid item in %s%%[]" +msgid "E927: Invalid action: '%s'" +msgstr "E927: 無効な操作です: '%s'" + +#, c-format +msgid "E59: Invalid character after %s@" +msgstr "E59: %s@ の後に不正な文字がありました" + +msgid "E63: Invalid use of \\_" +msgstr "E63: \\_ の無効な使用方法です" + +msgid "E363: Pattern uses more memory than 'maxmempattern'" +msgstr "E363: パターンが 'maxmempattern' 以上のメモリを使用します" + +#, c-format +msgid "E369: Invalid item in %s%%[]" msgstr "E369: 無効な項目です: %s%%[]" #, c-format +msgid "E654: Missing delimiter after search pattern: %s" +msgstr "E654: 検索パターンのあとに区切りがありません: %s" + +#, c-format msgid "E769: Missing ] after %s[" msgstr "E769: %s[ の後に ] がありません" @@ -4420,6 +5732,21 @@ msgid "E956: Cannot use pattern recursively" msgstr "E956: パターンを再帰的に使うことはできません" #, c-format +msgid "E1204: No Number allowed after .: '\\%%%c'" +msgstr "E1204: . の後に数字は許されません: '\\%%%c'" + +#, c-format +msgid "E1273: (NFA regexp) missing value in '\\%%%c'" +msgstr "E1273: (NFA 正規表現) '\\%%%c' に値がありません" + +#, c-format +msgid "E1281: Atom '\\%%#=%c' must be at the start of the pattern" +msgstr "E1281: アトム '\\%%#=%c' はパターンの先頭になければなりません" + +msgid "E1290: substitute nesting too deep" +msgstr "E1290: 置換の入れ子が深過ぎます" + +#, c-format msgid "E554: Syntax error in %s{...}" msgstr "E554: %s{...} 内に文法エラーがあります" @@ -4427,22 +5754,9 @@ msgstr "E554: %s{...} 内に文法エラーがあります" msgid "E888: (NFA regexp) cannot repeat %s" msgstr "E888: (NFA 正規表現) 繰り返せません %s" -msgid "" -"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be " -"used " -msgstr "" -"E864: \\%#= には 0, 1 もしくは 2 のみが続けられます。正規表現エンジンは自動選" -"択されます。" - -msgid "Switching to backtracking RE engine for pattern: " -msgstr "次のパターンにバックトラッキング RE エンジンを適用します: " - msgid "E65: Illegal back reference" msgstr "E65: 不正な後方参照です" -msgid "E63: invalid use of \\_" -msgstr "E63: \\_ の無効な使用方法です" - #, c-format msgid "E64: %s%c follows nothing" msgstr "E64:%s%c の後になにもありません" @@ -4459,10 +5773,6 @@ msgid "E71: Invalid character after %s%%" msgstr "E71: %s%% の後に不正な文字がありました" #, c-format -msgid "E59: invalid character after %s@" -msgstr "E59: %s@ の後に不正な文字がありました" - -#, c-format msgid "E60: Too many complex %s{...}s" msgstr "E60: 複雑な %s{...} が多過ぎます" @@ -4487,6 +5797,7 @@ msgstr "E52: \\z( が釣り合っていません" msgid "E339: Pattern too long" msgstr "E339: パターンが長過ぎます" +#, c-format msgid "External submatches:\n" msgstr "外部の部分該当:\n" @@ -4498,29 +5809,26 @@ msgid "E866: (NFA regexp) Misplaced %c" msgstr "E866: (NFA 正規表現) 位置が誤っています: %c" #, c-format -msgid "E877: (NFA regexp) Invalid character class: %ld" -msgstr "E877: (NFA 正規表現) 無効な文字クラス: %ld" +msgid "E877: (NFA regexp) Invalid character class: %<PRId64>" +msgstr "E877: (NFA 正規表現) 無効な文字クラス: %<PRId64>" + +msgid "E951: \\% value too large" +msgstr "E951: \\% 値が大き過ぎます" #, c-format msgid "E867: (NFA) Unknown operator '\\z%c'" msgstr "E867: (NFA) 未知のオペレータです: '\\z%c'" -msgid "E951: \\% value too large" -msgstr "E951: \\% 値が長過ぎます" - #, c-format msgid "E867: (NFA) Unknown operator '\\%%%c'" msgstr "E867: (NFA) 未知のオペレータです: '\\%%%c'" -msgid "E868: Error building NFA with equivalence class!" -msgstr "E868: 等価クラスを含むNFA構築に失敗しました!" - #, c-format msgid "E869: (NFA) Unknown operator '\\@%c'" msgstr "E869: (NFA) 未知のオペレータです: '\\@%c'" msgid "E870: (NFA regexp) Error reading repetition limits" -msgstr "E870: (NFA 正規表現) 繰り返しの制限回数を読込中にエラー" +msgstr "E870: (NFA 正規表現) 繰り返しの制限回数を読込み中にエラー" msgid "E871: (NFA regexp) Can't have a multi follow a multi" msgstr "E871: (NFA 正規表現) 繰り返し の後に 繰り返し はできません" @@ -4536,112 +5844,134 @@ msgstr "E873: (NFA 正規表現) 終端記号がありません" msgid "Could not open temporary log file for writing, displaying on stderr... " msgstr "" -"NFA正規表現エンジン用のログファイルを書込用として開けません。ログは標準エラー" -"出力に出力します。" +"NFA正規表現エンジン用のログファイルを書込み用として開けません。ログは標準エ" +"ラー出力に出力します。" msgid "E874: (NFA) Could not pop the stack!" msgstr "E874: (NFA) スタックをポップできません!" msgid "" -"E875: (NFA regexp) (While converting from postfix to NFA), too many states " +"E875: (NFA regexp) (While converting from postfix to NFA),too many states " "left on stack" msgstr "" -"E875: (NFA 正規表現) (後置文字列をNFAに変換中に) スタックに残されたステートが" -"多過ぎます" +"E875: (NFA) (後置文字列をNFAに変換中に) スタックに残されたステートが多過ぎま" +"す" msgid "E876: (NFA regexp) Not enough space to store the whole NFA " -msgstr "E876: (NFA 正規表現) NFA全体を保存するには空きスペースが足りません" +msgstr "E876: (NFA) NFA全体を保存するには空きスペースが足りません" -msgid "E878: (NFA) Could not allocate memory for branch traversal!" -msgstr "E878: (NFA) 現在横断中のブランチに十分なメモリを割り当てられません!" +msgid "" +"E864: \\%#= can only be followed by 0, 1, or 2. The automatic engine will be " +"used " +msgstr "" +"E864: \\%#= には 0, 1 もしくは 2 のみが続けられます。正規表現エンジンは自動選" +"択されます" + +msgid "Switching to backtracking RE engine for pattern: " +msgstr "次のパターンにバックトラッキング RE エンジンを適用します: " #, c-format -msgid "block of %ld line yanked%s" -msgid_plural "block of %ld lines yanked%s" -msgstr[0] "%ld 行のブロックが%sヤンクされました" +msgid "Searching for \"%s\" under \"%s\" in \"%s\"" +msgstr "\"%s\" を \"%s\" 以下の \"%s\" から検索中" #, c-format -msgid "%ld line yanked%s" -msgid_plural "%ld lines yanked%s" -msgstr[0] "%ld 行が%sヤンクされました" +msgid "Searching for \"%s\" in \"%s\"" +msgstr "\"%s\" を \"%s\" から検索中" -msgid "" -"\n" -"Type Name Content" -msgstr "" -"\n" -"型式 名前 内容" +#, c-format +msgid "Searching for \"%s\"" +msgstr "\"%s\" を検索中" -msgid " VREPLACE" -msgstr " 仮想置換" +#, c-format +msgid "not found in '%s': \"%s\"" +msgstr "'%s' の中にはありません: \"%s\"" -msgid " REPLACE" -msgstr " 置換" +#, c-format +msgid "Searching for \"%s\" in runtime path" +msgstr "ランタイムパスで '%s' を検索しています" -msgid " REVERSE" -msgstr " 反転" +#, c-format +msgid "not found in runtime path: \"%s\"" +msgstr "ランタイムパスに見つかりませんでした: \"%s\"" -msgid " INSERT" -msgstr " 挿入" +#, c-format +msgid "Cannot source a directory: \"%s\"" +msgstr "ディレクトリは取込めません: \"%s\"" -msgid " (insert)" -msgstr " (挿入)" +#, c-format +msgid "could not source \"%s\"" +msgstr "\"%s\" を取込めません" -msgid " (replace)" -msgstr " (置換)" +#, c-format +msgid "line %<PRId64>: could not source \"%s\"" +msgstr "行 %<PRId64>: \"%s\" を取込めません" -msgid " (vreplace)" -msgstr " (仮想置換)" +#, c-format +msgid "sourcing \"%s\"" +msgstr "\"%s\" を取込み中" -msgid " Hebrew" -msgstr " ヘブライ" +#, c-format +msgid "line %<PRId64>: sourcing \"%s\"" +msgstr "行 %<PRId64>: %s を取込み中" -msgid " Arabic" -msgstr " アラビア" +#, c-format +msgid "finished sourcing %s" +msgstr "%s の取込みを完了" -msgid " (paste)" -msgstr " (貼り付け)" +msgid "modeline" +msgstr "モード行" -msgid " VISUAL" -msgstr " ビジュアル" +msgid "--cmd argument" +msgstr "--cmd 引数" -msgid " VISUAL LINE" -msgstr " ビジュアル 行" +msgid "-c argument" +msgstr "-c 引数" -msgid " VISUAL BLOCK" -msgstr " ビジュアル 矩形" +msgid "environment variable" +msgstr "環境変数" -msgid " SELECT" -msgstr " セレクト" +msgid "error handler" +msgstr "エラーハンドラ" -msgid " SELECT LINE" -msgstr " 行指向選択" +msgid "changed window size" +msgstr "ウィンドウサイズが変更されました" -msgid " SELECT BLOCK" -msgstr " 矩形選択" +msgid "Lua" +msgstr "Lua" -msgid "recording" -msgstr "記録中" +#, c-format +msgid "API client (channel id %<PRIu64>)" +msgstr "API クライアント (チャネル ID %<PRIu64>)" -msgid "E984: :scriptversion used outside of a sourced file" -msgstr "E984: :scriptversion が取込スクリプト以外で使用されました" +#, fuzzy +#~ msgid "anonymous :source" +#~ msgstr "匿名の :source" -#, c-format -msgid "E999: scriptversion not supported: %d" -msgstr "E999: scriptversion はサポートされていません: %d" +#, fuzzy, c-format +#~ msgid "anonymous :source (script id %d)" +#~ msgstr "匿名の :source (スクリプト ID %d)" -#, c-format -msgid "E383: Invalid search string: %s" -msgstr "E383: 無効な検索文字列です: %s" +msgid "W15: Warning: Wrong line separator, ^M may be missing" +msgstr "W15: 警告: 行区切が不正です。^M がないのでしょう" + +msgid "E167: :scriptencoding used outside of a sourced file" +msgstr "E167: :scriptencoding が取込みスクリプト以外で使用されました" + +msgid "E168: :finish used outside of a sourced file" +msgstr "E168: :finish が取込みスクリプト以外で使用されました" #, c-format -msgid "E384: search hit TOP without match for: %s" +msgid "E384: Search hit TOP without match for: %s" msgstr "E384: 上まで検索しましたが該当箇所はありません: %s" #, c-format -msgid "E385: search hit BOTTOM without match for: %s" +msgid "E385: Search hit BOTTOM without match for: %s" msgstr "E385: 下まで検索しましたが該当箇所はありません: %s" +#, c-format +msgid "E383: Invalid search string: %s" +msgstr "E383: 無効な検索文字列です: %s" + msgid "E386: Expected '?' or '/' after ';'" msgstr "E386: ';' のあとには '?' か '/' が期待されている" @@ -4655,7 +5985,7 @@ msgid "not found " msgstr "見つかりません " msgid "in path ---\n" -msgstr "パスに ----\n" +msgstr "パスに ---\n" msgid " (Already listed)" msgstr " (既に列挙)" @@ -4686,26 +6016,271 @@ msgstr "E388: 定義を見つけられません" msgid "E389: Couldn't find pattern" msgstr "E389: パターンを見つけられません" -msgid "Substitute " -msgstr "Substitute " +msgid "too few bytes read" +msgstr "読み込まれたバイト数が少なすぎます" + +#, fuzzy, c-format +#~ msgid "System error while skipping in ShaDa file: %s" +#~ msgstr "ShaDa ファイルのスキップ中にシステム エラーが発生しました: %s" + +#, c-format +msgid "" +"Error while reading ShaDa file: last entry specified that it occupies " +"%<PRIu64> bytes, but file ended earlier" +msgstr "" +"ShaDa ファイルの読み取り中にエラーが発生しました: 最後のエントリで %<PRIu64> " +"バイトを占めるように指定されましたが、ファイルはその前に終了しました" + +#, c-format +msgid "System error while closing ShaDa file: %s" +msgstr "ShaDa ファイルを閉じる時にシステムエラーが発生しました: %s" + +#, c-format +msgid "System error while writing ShaDa file: %s" +msgstr "ShaDa ファイルの書き込み中にシステムエラーが発生しました: %s" + +#, c-format +msgid "Reading ShaDa file \"%s\"%s%s%s%s" +msgstr "ShaDaファイル \"%s\"%s%s%s%s を読込み中" + +msgid " info" +msgstr " 情報" + +msgid " marks" +msgstr " マーク" + +msgid " oldfiles" +msgstr " 旧ファイル群" + +msgid " FAILED" +msgstr " 失敗" + +#, c-format +msgid "System error while opening ShaDa file %s for reading: %s" +msgstr "ShaDa ファイル %s を開く時にシステム エラーが発生しました: %s" + +#, fuzzy +#~ msgid "additional elements of ShaDa " +#~ msgstr "ShaDa の追加要素 " + +#, fuzzy +#~ msgid "additional data of ShaDa " +#~ msgstr "ShaDa の追加データ " + +#, c-format +msgid "Failed to write variable %s" +msgstr "変数 %s の書き込みに失敗しました" + +#, c-format +msgid "" +"Failed to parse ShaDa file due to a msgpack parser error at position " +"%<PRIu64>" +msgstr "" +"位置 %<PRIu64> での msgpack 構文解析エラーのため、ShaDa ファイルの解析に失敗" +"しました" + +#, c-format +msgid "" +"Failed to parse ShaDa file: incomplete msgpack string at position %<PRIu64>" +msgstr "" +"ShaDa ファイルの解析に失敗しました: 位置 %<PRIu64> に不完全な msgpack 文字列" +"があります" + +#, c-format +msgid "" +"Failed to parse ShaDa file: extra bytes in msgpack string at position " +"%<PRIu64>" +msgstr "" +"ShaDa ファイルの解析に失敗しました: 位置 %<PRIu64> の msgpack 文字列に余分な" +"バイトがあります" + +#, c-format +msgid "" +"System error while opening ShaDa file %s for reading to merge before writing " +"it: %s" +msgstr "" +"書き込み前にマージを実行するため、読み取り用に ShaDa ファイル %s を開いている" +"ときにシステムエラーが発生しました: %s" + +#, fuzzy, c-format +#~ msgid "E138: All %s.tmp.X files exist, cannot write ShaDa file!" +#~ msgstr "" +#~ "E138: 全ての %s.tmp.X ファイルが存在します。ShaDa ファイルを書き込むことがで" +#~ "きません!" + +#, c-format +msgid "System error while opening temporary ShaDa file %s for writing: %s" +msgstr "" +"書き込みの為一時的に ShaDa ファイル %s を開いているときにシステムエラーが発生" +"しました: %s" + +#, c-format +msgid "Failed to create directory %s for writing ShaDa file: %s" +msgstr "ShaDa ファイルを書き込むためのディレクトリ %s の作成に失敗しました: %s" + +#, c-format +msgid "System error while opening ShaDa file %s for writing: %s" +msgstr "" +"書き込みの為に ShaDa ファイル %s を開いているときにシステムエラーが発生しまし" +"た: %s" + +#, c-format +msgid "Writing ShaDa file \"%s\"" +msgstr "ShaDaファイル \"%s\" を書込み中" + +#, c-format +msgid "E137: ShaDa file is not writable: %s" +msgstr "E137: ShaDaファイルが書込みできません: %s" + +#, c-format +msgid "Failed setting uid and gid for file %s: %s" +msgstr "ファイル %s の uid と gid の設定に失敗しました: %s" + +#, c-format +msgid "Can't rename ShaDa file from %s to %s!" +msgstr "ShaDaファイルの名前を %s から %s へ変更できません!" + +#, c-format +msgid "Did not rename %s because %s does not look like a ShaDa file" +msgstr "" +"%s の名前を変更しませんでした。%s は ShaDa ファイルのように見えないためです" + +#, c-format +msgid "Did not rename %s to %s because there were errors during writing it" +msgstr "書き込み中にエラーが発生した為、%s の名前を %s に変更しませんでした" + +#, c-format +msgid "Do not forget to remove %s or rename it manually to %s." +msgstr "%s を削除するか、手動で名前を %s に変更することを忘れないでください。" + +#, c-format +msgid "System error while reading ShaDa file: %s" +msgstr "ShaDaファイルの読込み中にシステムエラーが発生しました: %s" + +#, c-format +msgid "System error while reading integer from ShaDa file: %s" +msgstr "ShaDa ファイルから整数を読み込む時にシステムエラーが発生しました: %s" + +#, c-format +msgid "" +"Error while reading ShaDa file: expected positive integer at position " +"%<PRIu64>, but got nothing" +msgstr "" +"ShaDa ファイルの読み込み中にエラーが発生しました: 位置 %<PRIu64> に正の整数が" +"必要ですが、何も取得されませんでした" + +#, c-format +msgid "" +"Error while reading ShaDa file: expected positive integer at position " +"%<PRIu64>" +msgstr "" +"ShaDa ファイルの読み込み中にエラーが発生しました: 位置 %<PRIu64> に正の整数が" +"必要です" + +#, c-format +msgid "" +"Error while reading ShaDa file: there is an item at position %<PRIu64> that " +"is stated to be too long" +msgstr "" +"ShaDa ファイルの読み込み中にエラーが発生しました: 位置 %<PRIu64> にある要素が" +"長すぎます" + +#, c-format +msgid "" +"Error while reading ShaDa file: there is an item at position %<PRIu64> that " +"must not be there: Missing items are for internal uses only" +msgstr "" +"ShaDa ファイルの読み込み中にエラーが発生しました: 位置 %<PRIu64> に存在しては" +"いけない要素があります: 欠落している要素は内部使用のみです" + +#, c-format +msgid "" +"Error while reading ShaDa file: buffer list at position %<PRIu64> contains " +"entry that is not a dictionary" +msgstr "" +"ShaDa ファイルの読み込み中にエラーが発生しました: 位置 %<PRIu64> のバッファリ" +"ストに辞書型ではないエントリが含まれています" + +#, c-format +msgid "" +"Error while reading ShaDa file: buffer list at position %<PRIu64> contains " +"entry with invalid line number" +msgstr "" +"ShaDa ファイルの読み込み中にエラーが発生しました: 位置 %<PRIu64> のバッファリ" +"ストに無効な行番号を持つエントリが含まれています" + +#, c-format +msgid "" +"Error while reading ShaDa file: buffer list at position %<PRIu64> contains " +"entry with invalid column number" +msgstr "" +"ShaDa ファイルの読み込み中にエラーが発生しました: 位置 %<PRIu64> のバッファリ" +"ストに無効な列番号を持つエントリが含まれています" #, c-format msgid "" +"Error while reading ShaDa file: buffer list at position %<PRIu64> contains " +"entry that does not have a file name" +msgstr "" +"ShaDa ファイルの読み込み中にエラーが発生しました: 位置 %<PRIu64> のバッファリ" +"ストにファイル名を持たないエントリが含まれています" + +msgid "" "\n" -"# Last %sSearch Pattern:\n" -"~" +"--- Signs ---" msgstr "" "\n" -"# 最後の %s検索パターン:\n" -"~" +"--- サイン ---" -msgid "E756: Spell checking is not enabled" -msgstr "E756: スペルチェックは無効化されています" +#, c-format +msgid "Signs for %s:" +msgstr "%s のサイン:" #, c-format -msgid "Warning: Cannot find word list \"%s_%s.spl\" or \"%s_ascii.spl\"" -msgstr "" -"警告: 単語リスト \"%s_%s.spl\" および \"%s_ascii.spl\" は見つかりません" +msgid " name=%s" +msgstr " 名前=%s" + +#, c-format +msgid " group=%s" +msgstr " グループ=%s" + +#~ msgid " line=%" +#~ msgstr "" + +#, c-format +msgid "E239: Invalid sign text: %s" +msgstr "E239: 無効なsignのテキストです: %s" + +#, c-format +msgid "E155: Unknown sign: %s" +msgstr "E155: 未知のsignです: %s" + +msgid " (not supported)" +msgstr " (非サポート)" + +#, c-format +msgid "E885: Not possible to change sign %s" +msgstr "E885: 変更できない sign です: %s" + +#, c-format +msgid "E157: Invalid sign ID: %<PRId32>" +msgstr "E157: 無効なsign識別子です: %<PRId32>" + +msgid "E934: Cannot jump to a buffer that does not have a name" +msgstr "E934: 名前の無いバッファへはジャンプできません" + +msgid "E159: Missing sign number" +msgstr "E159: signの番号がありません" + +#, c-format +msgid "E160: Unknown sign command: %s" +msgstr "E160: 未知のsignコマンドです: %s" + +msgid "E156: Missing sign name" +msgstr "E156: sign名がありません" + +msgid "E759: Format error in spell file" +msgstr "E759: スペルファイルのフォーマットエラーです" #, c-format msgid "Warning: Cannot find word list \"%s.%s.spl\" or \"%s.ascii.spl\"" @@ -4713,7 +6288,7 @@ msgstr "" "警告: 単語リスト \"%s.%s.spl\" および \"%s.ascii.spl\" は見つかりません" msgid "E797: SpellFileMissing autocommand deleted buffer" -msgstr "E797: autocommand の SpellFileMissing がバッファを削除しました" +msgstr "E797: SpellFileMissing 自動コマンドがバッファを削除しました" #, c-format msgid "Warning: region %s not supported" @@ -4730,6 +6305,16 @@ msgid "E758: Truncated spell file" msgstr "E758: スペルファイルが切取られているようです" #, c-format +msgid "E782: Error while reading .sug file: %s" +msgstr "E782: .sug ファイルの読込み中にエラーが発生しました: %s" + +msgid "E783: Duplicate char in MAP entry" +msgstr "E783: MAP エントリに重複文字が存在します" + +msgid "E1280: Illegal character in word" +msgstr "E1280: 単語内に不正な文字があります" + +#, c-format msgid "Trailing text in %s line %d: %s" msgstr "%s (%d 行目) に続くテキスト: %s" @@ -4737,23 +6322,20 @@ msgstr "%s (%d 行目) に続くテキスト: %s" msgid "Affix name too long in %s line %d: %s" msgstr "%s (%d 行目) の affix 名が長過ぎます: %s" -msgid "E761: Format error in affix file FOL, LOW or UPP" -msgstr "" -"E761: affixファイルの FOL, LOW もしくは UPP のフォーマットにエラーがあります" - -msgid "E762: Character in FOL, LOW or UPP is out of range" -msgstr "E762: FOL, LOW もしくは UPP の文字が範囲外です" - msgid "Compressing word tree..." msgstr "単語ツリーを圧縮しています..." #, c-format msgid "Reading spell file \"%s\"" -msgstr "スペルファイル \"%s\" を読込中" +msgstr "スペルファイル \"%s\" を読込み中" msgid "E757: This does not look like a spell file" msgstr "E757: スペルファイルではないようです" +#, c-format +msgid "E5042: Failed to read spell file %s: %s" +msgstr "E5042: スペルファイル %s の読み込みに失敗しました: %s" + msgid "E771: Old spell file, needs to be updated" msgstr "E771: 古いスペルファイルなので、アップデートしてください" @@ -4780,12 +6362,8 @@ msgid "E781: .sug file doesn't match .spl file: %s" msgstr "E781: .sug ファイルが .spl ファイルと一致しません: %s" #, c-format -msgid "E782: error while reading .sug file: %s" -msgstr "E782: .sug ファイルの読込中にエラーが発生しました: %s" - -#, c-format msgid "Reading affix file %s..." -msgstr "affix ファイル %s を読込中..." +msgstr "affix ファイル %s を読込み中..." #, c-format msgid "Conversion failure for word in %s line %d: %s" @@ -4796,10 +6374,6 @@ msgid "Conversion in %s not supported: from %s to %s" msgstr "%s 内の次の変換はサポートされていません: %s から %s へ" #, c-format -msgid "Conversion in %s not supported" -msgstr "%s 内の変換はサポートされていません" - -#, c-format msgid "Invalid value for FLAG in %s line %d: %s" msgstr "%s 内の %d 行目の FLAG に無効な値があります: %s" @@ -4884,10 +6458,6 @@ msgstr "%s の %d 行目の MAP に重複した文字があります" msgid "Unrecognized or duplicate item in %s line %d: %s" msgstr "%s の %d 行目に 認識できないか重複した項目があります: %s" -#, c-format -msgid "Missing FOL/LOW/UPP line in %s" -msgstr "%s 行目に FOL/LOW/UPP がありません" - msgid "COMPOUNDSYLMAX used without SYLLABLE" msgstr "SYLLABLE が指定されない COMPOUNDSYLMAX" @@ -4929,8 +6499,8 @@ msgid "E760: No word count in %s" msgstr "E760: %s には単語数がありません" #, c-format -msgid "line %6d, word %6ld - %s" -msgstr "行 %6d, 単語 %6ld - %s" +msgid "line %6d, word %6d - %s" +msgstr "行 %6d, 単語 %6d - %s" #, c-format msgid "Duplicate word in %s line %d: %s" @@ -4952,54 +6522,47 @@ msgstr "非ASCII文字を含む %d 個の単語を無視しました (%s 内)" msgid "Reading word file %s..." msgstr "単語ファイル %s を読込み中..." -#, c-format -msgid "Duplicate /encoding= line ignored in %s line %d: %s" -msgstr "%s の %d 行目の 重複した /encoding= 行を無視しました: %s" +#~ msgid "Conversion failure for word in %s line %" +#~ msgstr "" -#, c-format -msgid "/encoding= line after word ignored in %s line %d: %s" -msgstr "%s の %d 行目の 単語の後の /encoding= 行を無視しました: %s" +#~ msgid "Duplicate /encoding= line ignored in %s line %" +#~ msgstr "" -#, c-format -msgid "Duplicate /regions= line ignored in %s line %d: %s" -msgstr "%s の %d 行目の 重複した /regions= 行を無視しました: %s" +#~ msgid "/encoding= line after word ignored in %s line %" +#~ msgstr "" -#, c-format -msgid "Too many regions in %s line %d: %s" -msgstr "%s の %d 行目、範囲指定が多過ぎます: %s" +#~ msgid "Duplicate /regions= line ignored in %s line %" +#~ msgstr "" -#, c-format -msgid "/ line ignored in %s line %d: %s" -msgstr "%s の %d 行目の 重複した / 行を無視しました: %s" +#~ msgid "Too many regions in %s line %" +#~ msgstr "" -#, c-format -msgid "Invalid region nr in %s line %d: %s" -msgstr "%s の %d 行目 無効な nr 領域です: %s" +#~ msgid "/ line ignored in %s line %" +#~ msgstr "" -#, c-format -msgid "Unrecognized flags in %s line %d: %s" -msgstr "%s の %d 行目 認識不能なフラグです: %s" +#~ msgid "Invalid region nr in %s line %" +#~ msgstr "" + +#~ msgid "Unrecognized flags in %s line %" +#~ msgstr "" #, c-format msgid "Ignored %d words with non-ASCII characters" msgstr "非ASCII文字を含む %d 個の単語を無視しました" -msgid "E845: Insufficient memory, word list will be incomplete" -msgstr "E845: メモリが足りないので、単語リストは不完全です" - #, c-format -msgid "Compressed %d of %d nodes; %d (%d%%) remaining" -msgstr "ノード %d 個(全 %d 個中) を圧縮しました; 残り %d (%d%%)" +msgid "Compressed %s of %d nodes; %d (%ld%%) remaining" +msgstr "ノード %s を圧縮 (全 %d 個中); 残り %d (%ld%%)" msgid "Reading back spell file..." -msgstr "スペルファイルを逆読込中" +msgstr "スペルファイルを逆読込み中..." msgid "Performing soundfolding..." msgstr "音声畳込みを実行中..." #, c-format -msgid "Number of words after soundfolding: %ld" -msgstr "音声畳込み後の総単語数: %ld" +msgid "Number of words after soundfolding: %<PRId64>" +msgstr "音声畳込み後の総単語数: %<PRId64>" #, c-format msgid "Total number of words: %d" @@ -5017,8 +6580,8 @@ msgid "E751: Output file name must not have region name" msgstr "E751: 出力ファイル名には範囲名を含められません" #, c-format -msgid "E754: Only up to %ld regions supported" -msgstr "E754: 範囲は %ld 個までしかサポートされていません" +msgid "E754: Only up to %d regions supported" +msgstr "E754: 範囲は %d 個までしかサポートされていません" #, c-format msgid "E755: Invalid region in %s" @@ -5035,13 +6598,16 @@ msgid "Done!" msgstr "実行しました!" #, c-format -msgid "E765: 'spellfile' does not have %ld entries" -msgstr "E765: 'spellfile' には %ld 個のエントリはありません" +msgid "E765: 'spellfile' does not have %<PRId64> entries" +msgstr "E765: 'spellfile' には %<PRId64> 個のエントリはありません" #, c-format msgid "Word '%.*s' removed from %s" msgstr "単語 '%.*s' が %s から削除されました" +msgid "Seek error in spellfile" +msgstr "スワップファイルでシークエラーです" + #, c-format msgid "Word '%.*s' added to %s" msgstr "単語 '%.*s' が %s へ追加されました" @@ -5049,39 +6615,129 @@ msgstr "単語 '%.*s' が %s へ追加されました" msgid "E763: Word characters differ between spell files" msgstr "E763: 単語の文字がスペルファイルと異なります" -msgid "E783: duplicate char in MAP entry" -msgstr "E783: MAP エントリに重複文字が存在します" +msgid "Sorry, no suggestions" +msgstr "残念ですが、修正候補はありません" -msgid "No Syntax items defined for this buffer" -msgstr "このバッファに定義された構文要素はありません" +#, c-format +msgid "Sorry, only %<PRId64> suggestions" +msgstr "残念ですが、修正候補は %<PRId64> 個しかありません" + +#, c-format +msgid "Change \"%.*s\" to:" +msgstr "\"%.*s\" を次へ変換:" + +#, c-format +msgid " < \"%.*s\"" +msgstr " < \"%.*s\"" + +msgid "[Help]" +msgstr "[ヘルプ]" + +msgid "[Preview]" +msgstr "[プレビュー]" + +#, c-format +msgid "E1500: Cannot mix positional and non-positional arguments: %s" +msgstr "E1500: 位置引数と非位置引数を混ぜることはできません: %s" + +#, c-format +msgid "E1501: format argument %d unused in $-style format: %s" +msgstr "" +"E1501: フォーマット引数 %d は $ スタイルフォーマットで使われていません: %s" + +#, c-format +msgid "" +"E1502: Positional argument %d used as field width reused as different type: " +"%s/%s" +msgstr "" +"E1502: フィールド幅として使われている位置引数 %d が異なる型に再利用されていま" +"す: %s/%s" -msgid "syntax conceal on" -msgstr "構文の conceal は現在 on です" +#, c-format +msgid "E1503: Positional argument %d out of bounds: %s" +msgstr "E1503: 位置引数 %d が範囲外です: %s" -msgid "syntax conceal off" -msgstr "構文の conceal は現在 off です" +#, c-format +msgid "E1504: Positional argument %d type used inconsistently: %s/%s" +msgstr "E1504: 位置引数 %d の型が一貫していません: %s/%s" + +#, c-format +msgid "E1505: Invalid format specifier: %s" +msgstr "E1505: 無効なフォーマット指示子です: %s" + +msgid "unknown" +msgstr "不明" + +msgid "int" +msgstr "int" + +msgid "long int" +msgstr "long int" + +msgid "long long int" +msgstr "long long int" + +msgid "signed size_t" +msgstr "signed size_t" + +msgid "unsigned int" +msgstr "unsigned int" + +msgid "unsigned long int" +msgstr "unsigned long int" + +msgid "unsigned long long int" +msgstr "unsigned long long int" + +msgid "size_t" +msgstr "size_t" + +msgid "pointer" +msgstr "pointer" + +msgid "percent" +msgstr "percent" + +msgid "char" +msgstr "char" + +msgid "string" +msgstr "string" + +msgid "float" +msgstr "float" + +msgid "E766: Insufficient arguments for printf()" +msgstr "E766: printf() の引数が不十分です" + +msgid "E807: Expected Float argument for printf()" +msgstr "E807: printf() の引数には浮動小数点数が期待されています" + +msgid "E767: Too many arguments to printf()" +msgstr "E767: printf() の引数が多過ぎます" #, c-format msgid "E390: Illegal argument: %s" msgstr "E390: 不正な引数です: %s" -msgid "syntax case ignore" -msgstr "構文の大文字小文字は現在 ignore です" +msgid "E395: Contains argument not accepted here" +msgstr "E395: この場所では引数containsは許可されていません" -msgid "syntax case match" -msgstr "構文の大文字小文字は現在 match です" +msgid "E844: Invalid cchar value" +msgstr "E844: 無効なccharの値です" -msgid "syntax spell toplevel" -msgstr "構文の spell は現在 toplevel です" +#, c-format +msgid "E890: Trailing char after ']': %s]%s" +msgstr "E890: ']' の後ろに余分な文字があります: %s]%s" -msgid "syntax spell notoplevel" -msgstr "構文の spell は現在 notoplevel です" +msgid "No Syntax items defined for this buffer" +msgstr "このバッファに定義された構文要素はありません" -msgid "syntax spell default" -msgstr "構文の spell は現在 default です" +msgid "'redrawtime' exceeded, syntax highlighting disabled" +msgstr "'redrawtime' を超過したため、構文ハイライトは無効化されます" -msgid "syntax iskeyword " -msgstr "構文用 iskeyword " +msgid "syntax iskeyword not set" +msgstr "構文用 iskeyword はセットされていません" #, c-format msgid "E391: No such syntax cluster: %s" @@ -5093,6 +6749,9 @@ msgstr "C言語風コメントから同期中" msgid "no syncing" msgstr "非同期" +msgid "syncing starts at the first line" +msgstr "最初の行で同期開始" + msgid "syncing starts " msgstr "同期開始 " @@ -5124,11 +6783,14 @@ msgstr "" msgid "E392: No such syntax cluster: %s" msgstr "E392: そのような構文クラスタはありません: %s" +msgid "from the first line" +msgstr "(最初の行から)" + msgid "minimal " -msgstr "minimal " +msgstr "最小 " msgid "maximal " -msgstr "maximal " +msgstr "最大 " msgid "; match " msgstr "; 該当 " @@ -5136,12 +6798,6 @@ msgstr "; 該当 " msgid " line breaks" msgstr " 個の改行" -msgid "E395: contains argument not accepted here" -msgstr "E395: この場所では引数containsは許可されていません" - -msgid "E844: invalid cchar value" -msgstr "E844: 無効なccharの値です" - msgid "E393: group[t]here not accepted here" msgstr "E393: ここではグループは許可されません" @@ -5153,17 +6809,13 @@ msgid "E397: Filename required" msgstr "E397: ファイル名が必要です" msgid "E847: Too many syntax includes" -msgstr "E847: 構文の取り込み(include)が多過ぎます" +msgstr "E847: 構文の取込み(include)が多過ぎます" #, c-format msgid "E789: Missing ']': %s" msgstr "E789: ']' がありません: %s" #, c-format -msgid "E890: trailing char after ']': %s]%s" -msgstr "E890: ']' の後ろに余分な文字があります: %s]%s" - -#, c-format msgid "E398: Missing '=': %s" msgstr "E398: '=' がありません: %s" @@ -5214,31 +6866,37 @@ msgstr "E409: 未知のグループ名: %s" #, c-format msgid "E410: Invalid :syntax subcommand: %s" -msgstr "E410: 無効な :syntax のサブコマンド: %s" +msgstr "E410: 無効な :syntax のサブコマンドです: %s" msgid "" " TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN" msgstr "" " TOTAL COUNT MATCH SLOWEST AVERAGE NAME PATTERN" -msgid "E555: at bottom of tag stack" +msgid "E73: Tag stack empty" +msgstr "E73: タグスタックが空です" + +#, c-format +msgid "E426: Tag not found: %s" +msgstr "E426: タグが見つかりません: %s" + +msgid "E555: At bottom of tag stack" msgstr "E555: タグスタックの末尾です" -msgid "E556: at top of tag stack" +msgid "E556: At top of tag stack" msgstr "E556: タグスタックの先頭です" -msgid "E425: Cannot go before first matching tag" -msgstr "E425: 最初の該当タグを越えて戻ることはできません" +msgid "E986: Cannot modify the tag stack within tagfunc" +msgstr "E986: tagfunc内のタグスタックを変更できません" -#, c-format -msgid "E426: tag not found: %s" -msgstr "E426: タグが見つかりません: %s" +msgid "E987: Invalid return value from tagfunc" +msgstr "E987: tagfuncからの戻り値が無効です" -msgid " # pri kind tag" -msgstr " # pri kind tag" +msgid "E1299: Window unexpectedly closed while searching for tags" +msgstr "E1299: タグを検索中に予期せずウィンドウが閉じられました" -msgid "file\n" -msgstr "ファイル\n" +msgid "E425: Cannot go before first matching tag" +msgstr "E425: 最初の該当タグを越えて戻ることはできません" msgid "E427: There is only one matching tag" msgstr "E427: 該当タグが1つだけしかありません" @@ -5264,6 +6922,12 @@ msgstr " タグを異なるcaseで使用します!" msgid "E429: File \"%s\" does not exist" msgstr "E429: ファイル \"%s\" がありません" +msgid " # pri kind tag" +msgstr " # pri kind tag" + +msgid "file\n" +msgstr "ファイル\n" + msgid "" "\n" " # TO tag FROM line in file/text" @@ -5272,23 +6936,16 @@ msgstr "" " # TO タグ FROM 行 in file/text" #, c-format -msgid "Searching tags file %s" -msgstr "タグファイル %s を検索中" - -#, c-format -msgid "E430: Tag file path truncated for %s\n" -msgstr "E430: タグファイルのパスが %s に切り捨てられました\n" - -msgid "Ignoring long line in tags file" -msgstr "タグファイル内の長い行を無視します" - -#, c-format msgid "E431: Format error in tags file \"%s\"" msgstr "E431: タグファイル \"%s\" のフォーマットにエラーがあります" #, c-format -msgid "Before byte %ld" -msgstr "直前の %ld バイト" +msgid "Before byte %<PRId64>" +msgstr "直前の %<PRId64> バイト" + +#, c-format +msgid "Searching tags file %s" +msgstr "タグファイル %s を検索中" #, c-format msgid "E432: Tags file not sorted: %s" @@ -5307,138 +6964,87 @@ msgstr "E435: タグを見つけられないので単に推測します!" msgid "Duplicate field name: %s" msgstr "重複したフィールド名: %s" -msgid "' not known. Available builtin terminals are:" -msgstr "' は未知です。現行の組み込み端末は次のとおりです:" - -msgid "defaulting to '" -msgstr "省略値を次のように設定します '" - -msgid "E557: Cannot open termcap file" -msgstr "E557: termcapファイルを開けません" - -msgid "E558: Terminal entry not found in terminfo" -msgstr "E558: terminfoに端末エントリを見つけられません" - -msgid "E559: Terminal entry not found in termcap" -msgstr "E559: termcapに端末エントリを見つけられません" - -#, c-format -msgid "E436: No \"%s\" entry in termcap" -msgstr "E436: termcapに \"%s\" のエントリがありません" - -msgid "E437: terminal capability \"cm\" required" -msgstr "E437: 端末に \"cm\" 機能が必要です" - msgid "" -"\n" -"--- Terminal keys ---" +"E856: \"assert_fails()\" second argument must be a string or a list with one " +"or two strings" msgstr "" -"\n" -"--- 端末キー ---" - -msgid "Cannot open $VIMRUNTIME/rgb.txt" -msgstr "$VIMRUNTIME/rgb.txtを開けません" +"E856: \"assert_fails()\" の第2引数は文字列または1個か2個の文字列のリストでな" +"ければなりません" -#, c-format -msgid "Kill job in \"%s\"?" -msgstr "\"%s\" 内のジョブを終了しますか?" +msgid "E1115: \"assert_fails()\" fourth argument must be a number" +msgstr "E1115: \"assert_fails()\" の第4引数は数字でなければなりません" -msgid "Terminal" -msgstr "端末" +msgid "E1116: \"assert_fails()\" fifth argument must be a string" +msgstr "E1116: \"assert_fails()\" の第5引数は文字列でなければなりません" -msgid "Terminal-finished" -msgstr "端末 (終了)" +msgid "E1142: Calling test_garbagecollect_now() while v:testing is not set" +msgstr "" +"E1142: v:testing が設定されていない状態で test_garbagecollect_now() を呼んで" +"います" -msgid "active" -msgstr "アクティブ" +msgid "Beep!" +msgstr "ビーッ!" -msgid "running" -msgstr "実行中" +msgid "E439: Undo list corrupt" +msgstr "E439: Undo リストが壊れています" -msgid "finished" -msgstr "終了" +msgid "E440: Undo line missing" +msgstr "E440: Undo する行がありません" #, c-format -msgid "E953: File exists: %s" -msgstr "E953: ファイルは既に存在します: %s" - -msgid "E955: Not a terminal buffer" -msgstr "E955: 端末バッファではありません" - -msgid "new shell started\n" -msgstr "新しいシェルを起動します\n" - -msgid "Vim: Error reading input, exiting...\n" -msgstr "Vim: 入力を読込み中のエラーにより終了します...\n" - -msgid "Used CUT_BUFFER0 instead of empty selection" -msgstr "空の選択領域のかわりにCUT_BUFFER0が使用されました" +msgid "E829: Write error in undo file: %s" +msgstr "E829: アンドゥファイルの書込みエラーです: %s" msgid "E881: Line count changed unexpectedly" msgstr "E881: 予期せず行カウントが変わりました" -msgid "No undo possible; continue anyway" -msgstr "可能なアンドゥはありません: とりあえず続けます" - #, c-format msgid "E828: Cannot open undo file for writing: %s" msgstr "E828: 書込み用にアンドゥファイルを開けません: %s" #, c-format +msgid "E5003: Unable to create directory \"%s\" for undo file: %s" +msgstr "E5003: アンドゥファイル用のディレクトリ \"%s\" を作成できません: %s" + +#, c-format msgid "E825: Corrupted undo file (%s): %s" msgstr "E825: アンドゥファイルが壊れています (%s): %s" msgid "Cannot write undo file in any directory in 'undodir'" -msgstr "'undodir'のディレクトリにアンドゥファイルを書き込めません" +msgstr "'undodir'のディレクトリにアンドゥファイルを書込めません" #, c-format msgid "Will not overwrite with undo file, cannot read: %s" -msgstr "アンドゥファイルとして読み込めないので上書きしません: %s" +msgstr "アンドゥファイルとして読込めないので上書きしません: %s" #, c-format msgid "Will not overwrite, this is not an undo file: %s" msgstr "アンドゥファイルではないので上書きしません: %s" msgid "Skipping undo file write, nothing to undo" -msgstr "対象がないのでアンドゥファイルの書き込みをスキップします" +msgstr "対象がないのでアンドゥファイルの書込みをスキップします" #, c-format msgid "Writing undo file: %s" -msgstr "アンドゥファイル書き込み中: %s" - -#, c-format -msgid "E829: write error in undo file: %s" -msgstr "E829: アンドゥファイルの書き込みエラーです: %s" +msgstr "アンドゥファイル書込み中: %s" #, c-format msgid "Not reading undo file, owner differs: %s" -msgstr "オーナーが異なるのでアンドゥファイルを読み込みません: %s" +msgstr "オーナーが異なるのでアンドゥファイルを読込みません: %s" #, c-format msgid "Reading undo file: %s" -msgstr "アンドゥファイル読込中: %s" +msgstr "アンドゥファイル読込み中: %s" #, c-format msgid "E822: Cannot open undo file for reading: %s" -msgstr "E822: アンドゥファイルを読込用として開けません: %s" +msgstr "E822: アンドゥファイルを読込み用として開けません: %s" #, c-format msgid "E823: Not an undo file: %s" msgstr "E823: アンドゥファイルではありません: %s" #, c-format -msgid "E832: Non-encrypted file has encrypted undo file: %s" -msgstr "E832: 非暗号化ファイルが暗号化されたアンドゥファイルを使ってます: %s" - -#, c-format -msgid "E826: Undo file decryption failed: %s" -msgstr "E826: 暗号化されたアンドゥファイルの解読に失敗しました: %s" - -#, c-format -msgid "E827: Undo file is encrypted: %s" -msgstr "E827: アンドゥファイルが暗号化されています: %s" - -#, c-format msgid "E824: Incompatible undo file: %s" msgstr "E824: 互換性の無いアンドゥファイルです: %s" @@ -5447,7 +7053,7 @@ msgstr "ファイルの内容が変わっているため、アンドゥ情報を #, c-format msgid "Finished reading undo file %s" -msgstr "アンドゥファイル %s の取込を完了" +msgstr "アンドゥファイル %s の取込みを完了" msgid "Already at oldest change" msgstr "既に一番古い変更です" @@ -5456,8 +7062,8 @@ msgid "Already at newest change" msgstr "既に一番新しい変更です" #, c-format -msgid "E830: Undo number %ld not found" -msgstr "E830: アンドゥ番号 %ld は見つかりません" +msgid "E830: Undo number %<PRId64> not found" +msgstr "E830: アンドゥ番号 %<PRId64> は見つかりません" msgid "E438: u_undo: line numbers wrong" msgstr "E438: u_undo: 行番号が間違っています" @@ -5481,14 +7087,19 @@ msgid "changes" msgstr "箇所変更しました" #, c-format -msgid "%ld %s; %s #%ld %s" -msgstr "%ld %s; %s #%ld %s" +msgid "%<PRId64> %s; %s #%<PRId64> %s" +msgstr "%<PRId64> %s; %s #%<PRId64> %s" + +msgid "after" +msgstr "後方" msgid "before" msgstr "前方" -msgid "after" -msgstr "後方" +#, c-format +msgid "%<PRId64> second ago" +msgid_plural "%<PRId64> seconds ago" +msgstr[0] "%<PRId64> 秒経過しています" msgid "Nothing to undo" msgstr "アンドゥ対象がありません" @@ -5496,411 +7107,110 @@ msgstr "アンドゥ対象がありません" msgid "number changes when saved" msgstr "通番 変更数 変更時期 保存済" -#, c-format -msgid "%ld seconds ago" -msgstr "%ld 秒経過しています" - msgid "E790: undojoin is not allowed after undo" msgstr "E790: undo の直後に undojoin はできません" -msgid "E439: undo list corrupt" -msgstr "E439: アンドゥリストが壊れています" - -msgid "E440: undo line missing" -msgstr "E440: アンドゥ行がありません" - -#, c-format -msgid "E122: Function %s already exists, add ! to replace it" -msgstr "E122: 関数 %s は定義済です、再定義するには ! を追加してください" - -msgid "E717: Dictionary entry already exists" -msgstr "E717: 辞書型内にエントリが既に存在します" - -msgid "E718: Funcref required" -msgstr "E718: 関数参照型が要求されます" - -#, c-format -msgid "E130: Unknown function: %s" -msgstr "E130: 未知の関数です: %s" - -#, c-format -msgid "E125: Illegal argument: %s" -msgstr "E125: 不正な引数です: %s" - -#, c-format -msgid "E853: Duplicate argument name: %s" -msgstr "E853: 引数名が重複しています: %s" - -msgid "E989: Non-default argument follows default argument" -msgstr "E989: 非デフォルト引数がデフォルト引数の後にあります" - -#, c-format -msgid "E740: Too many arguments for function %s" -msgstr "E740: 関数の引数が多過ぎます: %s" - -#, c-format -msgid "E116: Invalid arguments for function %s" -msgstr "E116: 関数の無効な引数です: %s" - -msgid "E132: Function call depth is higher than 'maxfuncdepth'" -msgstr "E132: 関数呼出の入れ子数が 'maxfuncdepth' を超えました" - -#, c-format -msgid "calling %s" -msgstr "%s を実行中です" - -#, c-format -msgid "%s aborted" -msgstr "%s が中断されました" - -#, c-format -msgid "%s returning #%ld" -msgstr "%s が #%ld を返しました" - -#, c-format -msgid "%s returning %s" -msgstr "%s が %s を返しました" - -msgid "E699: Too many arguments" -msgstr "E699: 引数が多過ぎます" - -#, c-format -msgid "E117: Unknown function: %s" -msgstr "E117: 未知の関数です: %s" - -#, c-format -msgid "E276: Cannot use function as a method: %s" -msgstr "E276: 関数をメソッドとして使用できません: %s" - -#, c-format -msgid "E933: Function was deleted: %s" -msgstr "E933: 関数は削除されました: %s" - -#, c-format -msgid "E119: Not enough arguments for function: %s" -msgstr "E119: 関数の引数が足りません: %s" - -#, c-format -msgid "E120: Using <SID> not in a script context: %s" -msgstr "E120: スクリプト以外で<SID>が使われました: %s" - -#, c-format -msgid "E725: Calling dict function without Dictionary: %s" -msgstr "E725: 辞書用関数が呼ばれましたが辞書がありません: %s" - -msgid "E129: Function name required" -msgstr "E129: 関数名が要求されます" - #, c-format -msgid "E128: Function name must start with a capital or \"s:\": %s" -msgstr "E128: 関数名は大文字か \"s:\" で始まらなければなりません: %s" +msgid "E179: Argument required for %s" +msgstr "E179: %s には引数が必要です" #, c-format -msgid "E884: Function name cannot contain a colon: %s" -msgstr "E884: 関数名にはコロンは含められません: %s" - -#, c-format -msgid "E123: Undefined function: %s" -msgstr "E123: 未定義の関数です: %s" - -#, c-format -msgid "E124: Missing '(': %s" -msgstr "E124: '(' がありません: %s" - -msgid "E862: Cannot use g: here" -msgstr "E862: ここでは g: は使えません" - -#, c-format -msgid "E932: Closure function should not be at top level: %s" -msgstr "E932: クロージャー関数はトップレベルに記述できません: %s" - -msgid "E126: Missing :endfunction" -msgstr "E126: :endfunction がありません" - -#, c-format -msgid "W22: Text found after :endfunction: %s" -msgstr "W22: :endfunction の後に文字があります: %s" - -#, c-format -msgid "E707: Function name conflicts with variable: %s" -msgstr "E707: 関数名が変数名と衝突します: %s" - -#, c-format -msgid "E127: Cannot redefine function %s: It is in use" -msgstr "E127: 関数 %s を再定義できません: 使用中です" - -#, c-format -msgid "E746: Function name does not match script file name: %s" -msgstr "E746: 関数名がスクリプトのファイル名と一致しません: %s" - -#, c-format -msgid "E131: Cannot delete function %s: It is in use" -msgstr "E131: 関数 %s を削除できません: 使用中です" +msgid "E184: No such user-defined command: %s" +msgstr "E184: そのユーザー定義コマンドはありません: %s" -msgid "E133: :return not inside a function" -msgstr "E133: 関数外に :return がありました" +msgid "E1208: -complete used without allowing arguments" +msgstr "E1208: -complete が引数を許可されずに使われています" #, c-format -msgid "%s (%s, compiled %s)" -msgstr "%s (%s, compiled %s)" - -msgid "" -"\n" -"MS-Windows 64-bit GUI version" -msgstr "" -"\n" -"MS-Windows 64 ビット GUI 版" - -msgid "" -"\n" -"MS-Windows 32-bit GUI version" -msgstr "" -"\n" -"MS-Windows 32 ビット GUI 版" - -msgid " with OLE support" -msgstr " with OLE サポート" - -msgid "" -"\n" -"MS-Windows 64-bit console version" -msgstr "" -"\n" -"MS-Windows 64 ビット コンソール 版" +msgid "E1237: No such user-defined command in current buffer: %s" +msgstr "E1237: 現在のバッファにそのユーザー定義コマンドはありません: %s" msgid "" "\n" -"MS-Windows 32-bit console version" +" Name Args Address Complete Definition" msgstr "" "\n" -"MS-Windows 32 ビット コンソール 版" +" 名前 引数 アドレス 補完 定義" -msgid "" -"\n" -"macOS version" -msgstr "" -"\n" -"macOS 版" - -msgid "" -"\n" -"macOS version w/o darwin feat." -msgstr "" -"\n" -"macOS 版 (darwin 無し)" - -msgid "" -"\n" -"OpenVMS version" -msgstr "" -"\n" -"OpenVMS 版" - -msgid "" -"\n" -"Included patches: " -msgstr "" -"\n" -"適用済パッチ: " - -msgid "" -"\n" -"Extra patches: " -msgstr "" -"\n" -"追加拡張パッチ: " - -msgid "Modified by " -msgstr "Modified by " - -msgid "" -"\n" -"Compiled " -msgstr "" -"\n" -"Compiled " - -msgid "by " -msgstr "by " - -msgid "" -"\n" -"Huge version " -msgstr "" -"\n" -"Huge 版 " - -msgid "" -"\n" -"Big version " -msgstr "" -"\n" -"Big 版 " - -msgid "" -"\n" -"Normal version " -msgstr "" -"\n" -"通常 版 " - -msgid "" -"\n" -"Small version " -msgstr "" -"\n" -"Small 版 " +msgid "No user-defined commands found" +msgstr "ユーザー定義コマンドが見つかりませんでした" -msgid "" -"\n" -"Tiny version " -msgstr "" -"\n" -"Tiny 版 " +#, c-format +msgid "E180: Invalid address type value: %s" +msgstr "E180: 無効なアドレスタイプ値です: %s" -msgid "without GUI." -msgstr "without GUI." +#, c-format +msgid "E180: Invalid complete value: %s" +msgstr "E180: 無効な補完指定です: %s" -msgid "with GTK3 GUI." -msgstr "with GTK3 GUI." +msgid "E468: Completion argument only allowed for custom completion" +msgstr "E468: 補完引数はカスタム補完でしか使用できません" -msgid "with GTK2-GNOME GUI." -msgstr "with GTK2-GNOME GUI." +msgid "E467: Custom completion requires a function argument" +msgstr "E467: カスタム補完には引数として関数が必要です" -msgid "with GTK2 GUI." -msgstr "with GTK2 GUI." +msgid "E175: No attribute specified" +msgstr "E175: 属性は定義されていません" -msgid "with X11-Motif GUI." -msgstr "with X11-Motif GUI." +msgid "E176: Invalid number of arguments" +msgstr "E176: 引数の数が無効です" -msgid "with X11-neXtaw GUI." -msgstr "with X11-neXtaw GUI." +msgid "E177: Count cannot be specified twice" +msgstr "E177: カウントを2重指定することはできません" -msgid "with X11-Athena GUI." -msgstr "with X11-Athena GUI." +msgid "E178: Invalid default value for count" +msgstr "E178: カウントの省略値が無効です" -msgid "with Photon GUI." -msgstr "with Photon GUI." +#, c-format +msgid "E181: Invalid attribute: %s" +msgstr "E181: 無効な属性です: %s" -msgid "with GUI." -msgstr "with GUI." +#, c-format +msgid "E174: Command already exists: add ! to replace it: %s" +msgstr "E174: コマンドが既にあります: 再定義するには ! を追加してください: %s" -msgid "with Carbon GUI." -msgstr "with Carbon GUI." +msgid "E182: Invalid command name" +msgstr "E182: 無効なコマンド名です" -msgid "with Cocoa GUI." -msgstr "with Cocoa GUI." +msgid "E183: User defined commands must start with an uppercase letter" +msgstr "E183: ユーザー定義コマンドは英大文字で始まらなければなりません" -msgid " Features included (+) or not (-):\n" -msgstr " 機能の一覧 有効(+)/無効(-)\n" +msgid "E841: Reserved name, cannot be used for user defined command" +msgstr "E841: 予約名なので、ユーザー定義コマンドに利用できません" msgid " system vimrc file: \"" msgstr " システム vimrc: \"" -msgid " user vimrc file: \"" -msgstr " ユーザー vimrc: \"" - -msgid " 2nd user vimrc file: \"" -msgstr " 第2ユーザー vimrc: \"" - -msgid " 3rd user vimrc file: \"" -msgstr " 第3ユーザー vimrc: \"" - -msgid " user exrc file: \"" -msgstr " ユーザー exrc: \"" - -msgid " 2nd user exrc file: \"" -msgstr " 第2ユーザー exrc: \"" - -msgid " system gvimrc file: \"" -msgstr " システム gvimrc: \"" - -msgid " user gvimrc file: \"" -msgstr " ユーザー gvimrc: \"" - -msgid "2nd user gvimrc file: \"" -msgstr " 第2ユーザー gvimrc: \"" - -msgid "3rd user gvimrc file: \"" -msgstr " 第3ユーザー gvimrc: \"" - -msgid " defaults file: \"" -msgstr " デフォルトファイル: \"" - -msgid " system menu file: \"" -msgstr " システムメニュー: \"" - msgid " fall-back for $VIM: \"" msgstr " 省略時の $VIM: \"" msgid " f-b for $VIMRUNTIME: \"" msgstr "省略時の $VIMRUNTIME: \"" -msgid "Compilation: " -msgstr "コンパイル: " +msgid "Nvim is open source and freely distributable" +msgstr "Nvim はオープンソースであり自由に配布可能です" -msgid "Compiler: " -msgstr "コンパイラ: " +msgid "type :help nvim<Enter> if you are new! " +msgstr "初めての人は :help nvim<Enter> " -msgid "Linking: " -msgstr "リンク: " +msgid "type :checkhealth<Enter> to optimize Nvim" +msgstr "Nvimを最適化するには :checkhealth<Enter> " -msgid " DEBUG BUILD" -msgstr "デバッグビルド" - -msgid "VIM - Vi IMproved" -msgstr "VIM - Vi IMproved" - -msgid "version " -msgstr "version " +msgid "type :q<Enter> to exit " +msgstr "終了するには :q<Enter> " -msgid "by Bram Moolenaar et al." -msgstr "by Bram Moolenaar 他." +msgid "type :help<Enter> for help " +msgstr "ヘルプを見るには :help<Enter> " -msgid "Vim is open source and freely distributable" -msgstr "Vim はオープンソースであり自由に配布可能です" +#, c-format +msgid "type :help news<Enter> to see changes in v%s.%s" +msgstr "v%s.%sの変更点は :help news<Enter> " msgid "Help poor children in Uganda!" msgstr "ウガンダの恵まれない子供たちに援助を!" msgid "type :help iccf<Enter> for information " -msgstr "詳細な情報は :help iccf<Enter> " - -msgid "type :q<Enter> to exit " -msgstr "終了するには :q<Enter> " - -msgid "type :help<Enter> or <F1> for on-line help" -msgstr "オンラインヘルプは :help<Enter> か <F1> " - -msgid "type :help version8<Enter> for version info" -msgstr "バージョン情報は :help version8<Enter> " - -msgid "Running in Vi compatible mode" -msgstr "Vi互換モードで動作中" - -msgid "type :set nocp<Enter> for Vim defaults" -msgstr "Vim推奨値にするには :set nocp<Enter> " - -msgid "type :help cp-default<Enter> for info on this" -msgstr "詳細な情報は :help cp-default<Enter>" - -msgid "menu Help->Orphans for information " -msgstr "詳細はメニューの ヘルプ->孤児 を参照して下さい " - -msgid "Running modeless, typed text is inserted" -msgstr "モード無で実行中。タイプした文字が挿入されます" - -msgid "menu Edit->Global Settings->Toggle Insert Mode " -msgstr "メニューの 編集->全体設定->挿入(初心者)モード切替 " - -msgid " for two modes " -msgstr " でモード有に " - -msgid "menu Edit->Global Settings->Toggle Vi Compatible" -msgstr "メニューの 編集->全体設定->Vi互換モード切替 " - -msgid " for Vim defaults " -msgstr " でVimとして動作 " +msgstr "詳細な情報は :help iccf<Enter> " msgid "Sponsor Vim development!" msgstr "Vimの開発を応援してください!" @@ -5909,772 +7219,201 @@ msgid "Become a registered Vim user!" msgstr "Vimの登録ユーザーになってください!" msgid "type :help sponsor<Enter> for information " -msgstr "詳細な情報は :help sponsor<Enter> " +msgstr "詳細な情報は :help sponsor<Enter> " msgid "type :help register<Enter> for information " -msgstr "詳細な情報は :help register<Enter> " - -msgid "menu Help->Sponsor/Register for information " -msgstr "詳細はメニューの ヘルプ->スポンサー/登録 を参照して下さい" - -msgid "Already only one window" -msgstr "既にウィンドウは1つしかありません" - -msgid "E441: There is no preview window" -msgstr "E441: プレビューウィンドウがありません" - -msgid "E442: Can't split topleft and botright at the same time" -msgstr "E442: 左上と右下を同時に分割することはできません" - -msgid "E443: Cannot rotate when another window is split" -msgstr "E443: 他のウィンドウが分割されている時には順回できません" - -msgid "E444: Cannot close last window" -msgstr "E444: 最後のウィンドウを閉じることはできません" - -msgid "E813: Cannot close autocmd window" -msgstr "E813: autocmdウィンドウは閉じられません" - -msgid "E814: Cannot close window, only autocmd window would remain" -msgstr "E814: autocmdウィンドウしか残らないため、ウィンドウは閉じられません" - -msgid "E445: Other window contains changes" -msgstr "E445: 他のウィンドウには変更があります" - -msgid "E446: No file name under cursor" -msgstr "E446: カーソルの下にファイル名がありません" - -#, c-format -msgid "E447: Can't find file \"%s\" in path" -msgstr "E447: pathには \"%s\" というファイルがありません" - -#, c-format -msgid "E799: Invalid ID: %ld (must be greater than or equal to 1)" -msgstr "E799: 無効な ID: %ld (1 以上でなければなりません)" - -#, c-format -msgid "E801: ID already taken: %ld" -msgstr "E801: ID はすでに利用中です: %ld" - -#, c-format -msgid "E802: Invalid ID: %ld (must be greater than or equal to 1)" -msgstr "E802: 無効な ID: %ld (1 以上でなければなりません)" - -#, c-format -msgid "E803: ID not found: %ld" -msgstr "E803: ID はありません: %ld" - -msgid "Edit with &multiple Vims" -msgstr "複数のVimで編集する (&M)" - -msgid "Edit with single &Vim" -msgstr "1つのVimで編集する (&V)" - -msgid "Diff with Vim" -msgstr "Vimで差分を表示する" - -msgid "Edit with &Vim" -msgstr "Vimで編集する (&V)" - -msgid "Edit with existing Vim - " -msgstr "起動済のVimで編集する - " - -msgid "Edits the selected file(s) with Vim" -msgstr "選択したファイルをVimで編集する" - -msgid "Error creating process: Check if gvim is in your path!" -msgstr "プロセスの作成に失敗: gvimが環境変数PATH上にあるか確認してください!" - -msgid "gvimext.dll error" -msgstr "gvimext.dll エラー" - -msgid "Path length too long!" -msgstr "パスが長過ぎます!" - -msgid "--No lines in buffer--" -msgstr "--バッファに行がありません--" - -msgid "E470: Command aborted" -msgstr "E470: コマンドが中断されました" - -msgid "E471: Argument required" -msgstr "E471: 引数が必要です" - -msgid "E10: \\ should be followed by /, ? or &" -msgstr "E10: \\ の後は / か ? か & でなければなりません" - -msgid "E11: Invalid in command-line window; <CR> executes, CTRL-C quits" -msgstr "E11: コマンドラインでは無効です; <CR>で実行, CTRL-Cでやめる" - -msgid "E12: Command not allowed from exrc/vimrc in current dir or tag search" -msgstr "" -"E12: 現在のディレクトリやタグ検索ではexrc/vimrcのコマンドは許可されません" - -msgid "E171: Missing :endif" -msgstr "E171: :endif がありません" - -msgid "E600: Missing :endtry" -msgstr "E600: :endtry がありません" - -msgid "E170: Missing :endwhile" -msgstr "E170: :endwhile がありません" - -msgid "E170: Missing :endfor" -msgstr "E170: :endfor がありません" - -msgid "E588: :endwhile without :while" -msgstr "E588: :while のない :endwhile があります" - -msgid "E588: :endfor without :for" -msgstr "E588: :endfor のない :for があります" - -msgid "E13: File exists (add ! to override)" -msgstr "E13: ファイルが存在します (! を追加で上書)" - -msgid "E472: Command failed" -msgstr "E472: コマンドが失敗しました" - -#, c-format -msgid "E234: Unknown fontset: %s" -msgstr "E234: 未知のフォントセット: %s" - -#, c-format -msgid "E235: Unknown font: %s" -msgstr "E235: 未知のフォント: %s" - -#, c-format -msgid "E236: Font \"%s\" is not fixed-width" -msgstr "E236: フォント \"%s\" は固定幅ではありません" - -msgid "E473: Internal error" -msgstr "E473: 内部エラーです" - -#, c-format -msgid "E685: Internal error: %s" -msgstr "E685: 内部エラーです: %s" - -msgid "Interrupted" -msgstr "割込まれました" - -msgid "E474: Invalid argument" -msgstr "E474: 無効な引数です" - -#, c-format -msgid "E475: Invalid argument: %s" -msgstr "E475: 無効な引数です: %s" - -#, c-format -msgid "E475: Invalid value for argument %s" -msgstr "E475: 引数 %s に対して無効な値です" - -#, c-format -msgid "E475: Invalid value for argument %s: %s" -msgstr "E475: 引数 %s に対して無効な値です: %s" - -#, c-format -msgid "E15: Invalid expression: %s" -msgstr "E15: 無効な式です: %s" - -msgid "E16: Invalid range" -msgstr "E16: 無効な範囲です" - -msgid "E476: Invalid command" -msgstr "E476: 無効なコマンドです" - -#, c-format -msgid "E17: \"%s\" is a directory" -msgstr "E17: \"%s\" はディレクトリです" - -#, c-format -msgid "E364: Library call failed for \"%s()\"" -msgstr "E364: \"%s\"() のライブラリ呼出に失敗しました" - -msgid "E667: Fsync failed" -msgstr "E667: fsync に失敗しました" - -#, c-format -msgid "E448: Could not load library function %s" -msgstr "E448: ライブラリの関数 %s をロードできませんでした" - -msgid "E19: Mark has invalid line number" -msgstr "E19: マークに無効な行番号が指定されていました" - -msgid "E20: Mark not set" -msgstr "E20: マークは設定されていません" - -msgid "E21: Cannot make changes, 'modifiable' is off" -msgstr "E21: 'modifiable' がオフなので、変更できません" - -msgid "E22: Scripts nested too deep" -msgstr "E22: スクリプトの入れ子が深過ぎます" - -msgid "E23: No alternate file" -msgstr "E23: 副ファイルはありません" - -msgid "E24: No such abbreviation" -msgstr "E24: そのような短縮入力はありません" - -msgid "E477: No ! allowed" -msgstr "E477: ! は許可されていません" - -msgid "E25: GUI cannot be used: Not enabled at compile time" -msgstr "E25: GUIは使用不可能です: コンパイル時に無効にされています" - -msgid "E26: Hebrew cannot be used: Not enabled at compile time\n" -msgstr "E26: ヘブライ語は使用不可能です: コンパイル時に無効にされています\n" - -msgid "E27: Farsi cannot be used: Not enabled at compile time\n" -msgstr "E27: ペルシア語は使用不可能です: コンパイル時に無効にされています\n" - -msgid "E800: Arabic cannot be used: Not enabled at compile time\n" -msgstr "E800: アラビア語は使用不可能です: コンパイル時に無効にされています\n" - -#, c-format -msgid "E28: No such highlight group name: %s" -msgstr "E28: そのような名のハイライトグループはありません: %s" - -msgid "E29: No inserted text yet" -msgstr "E29: まだテキストが挿入されていません" - -msgid "E30: No previous command line" -msgstr "E30: 以前にコマンド行がありません" - -msgid "E31: No such mapping" -msgstr "E31: そのようなマッピングはありません" - -msgid "E479: No match" -msgstr "E479: 該当はありません" - -#, c-format -msgid "E480: No match: %s" -msgstr "E480: 該当はありません: %s" - -msgid "E32: No file name" -msgstr "E32: ファイル名がありません" - -msgid "E33: No previous substitute regular expression" -msgstr "E33: 正規表現置換がまだ実行されていません" - -msgid "E34: No previous command" -msgstr "E34: コマンドがまだ実行されていません" - -msgid "E35: No previous regular expression" -msgstr "E35: 正規表現がまだ実行されていません" - -msgid "E481: No range allowed" -msgstr "E481: 範囲指定は許可されていません" - -msgid "E36: Not enough room" -msgstr "E36: ウィンドウに十分な高さもしくは幅がありません" +msgstr "詳細な情報は :help register<Enter>" #, c-format -msgid "E247: no registered server named \"%s\"" -msgstr "E247: %s という名前の登録されたサーバーはありません" +msgid "E15: Invalid control character present in input: %.*s" +msgstr "E15: 無効な制御文字が入力されました: %.*s" #, c-format -msgid "E482: Can't create file %s" -msgstr "E482: ファイル %s を作成できません" - -msgid "E483: Can't get temp file name" -msgstr "E483: 一時ファイルの名前を取得できません" +msgid "E112: Option name missing: %.*s" +msgstr "E112: オプション名がありません: %.*s" #, c-format -msgid "E484: Can't open file %s" -msgstr "E484: ファイル \"%s\" を開けません" +msgid "E15: Unexpected EOC character: %.*s" +msgstr "E15: 予期しない EOC 文字: %.*s" #, c-format -msgid "E485: Can't read file %s" -msgstr "E485: ファイル %s を読込めません" - -msgid "E38: Null argument" -msgstr "E38: 引数が空です" +msgid "E15: Unidentified character: %.*s" +msgstr "E15: 識別できない文字: %.*s" -msgid "E39: Number expected" -msgstr "E39: 数値が要求されています" +#, fuzzy, c-format +#~ msgid "E15: Operator is not associative: %.*s" +#~ msgstr "E15: 演算子は結合的ではありません: %.*s" #, c-format -msgid "E40: Can't open errorfile %s" -msgstr "E40: エラーファイル %s を開けません" +msgid "E15: Missing operator: %.*s" +msgstr "E15: 演算子がありません: %.*s" -msgid "E233: cannot open display" -msgstr "E233: ディスプレイを開けません" +#, fuzzy, c-format +#~ msgid "E15: Expected lambda arguments list or arrow: %.*s" +#~ msgstr "E15: ラムダ引数リストかアローが必要です: %.*s" -msgid "E41: Out of memory!" -msgstr "E41: メモリが尽き果てました!" - -msgid "Pattern not found" -msgstr "パターンは見つかりませんでした" +#, fuzzy, c-format +#~ msgid "E15: Expected value part of assignment lvalue: %.*s" +#~ msgstr "E15: 代入左辺値の値部分が必要です: %.*s" #, c-format -msgid "E486: Pattern not found: %s" -msgstr "E486: パターンは見つかりませんでした: %s" +msgid "E15: Expected assignment operator or subscript: %.*s" +msgstr "E15: 代入演算子または添え字が必要です: %.*s" -msgid "E487: Argument must be positive" -msgstr "E487: 引数は正の値でなければなりません" - -msgid "E459: Cannot go back to previous directory" -msgstr "E459: 前のディレクトリに戻れません" - -msgid "E42: No Errors" -msgstr "E42: エラーはありません" - -msgid "E776: No location list" -msgstr "E776: ロケーションリストはありません" - -msgid "E43: Damaged match string" -msgstr "E43: 該当文字列が破損しています" - -msgid "E44: Corrupted regexp program" -msgstr "E44: 不正な正規表現プログラムです" +#, fuzzy +#~ msgid "E15: Unexpected " +#~ msgstr "E15: 予期しない " -msgid "E45: 'readonly' option is set (add ! to override)" -msgstr "E45: 'readonly' オプションが設定されています (! を追加で上書き)" +#, fuzzy, c-format +#~ msgid "E15: Unexpected multiplication-like operator: %.*s" +#~ msgstr "E15: 予期しない乗算のような演算子: %.*s" -msgid "E995: Cannot modify existing variable" -msgstr "E995: 既存の変数を変更できません" +msgid "E15: Environment variable name missing" +msgstr "E15: 環境変数名がありません" #, c-format -msgid "E46: Cannot change read-only variable \"%s\"" -msgstr "E46: 読取専用変数 \"%s\" には値を設定できません" +msgid "E15: Expected value, got comparison operator: %.*s" +msgstr "E15: 値が必要ですが比較演算子を受け取りました: %.*s" #, c-format -msgid "E794: Cannot set variable in the sandbox: \"%s\"" -msgstr "E794: サンドボックスでは変数 \"%s\" に値を設定できません" - -msgid "E713: Cannot use empty key for Dictionary" -msgstr "E713: 辞書型に空のキーを使うことはできません" - -msgid "E715: Dictionary required" -msgstr "E715: 辞書型が必要です" +msgid "E15: Expected value, got comma: %.*s" +msgstr "E15: 値が必要ですがカンマを受け取りました: %.*s" #, c-format -msgid "E684: list index out of range: %ld" -msgstr "E684: リストのインデックスが範囲外です: %ld" +msgid "E15: Comma outside of call, lambda or literal: %.*s" +msgstr "E15: カンマが呼び出し、ラムダ、またはリテラルの外です: %.*s" #, c-format -msgid "E118: Too many arguments for function: %s" -msgstr "E118: 関数の引数が多過ぎます: %s" +msgid "E15: Colon outside of dictionary or ternary operator: %.*s" +msgstr "E15: 辞書外のコロンまたは三項演算子: %.*s" #, c-format -msgid "E716: Key not present in Dictionary: %s" -msgstr "E716: 辞書型にキーが存在しません: %s" - -msgid "E714: List required" -msgstr "E714: リスト型が必要です" +msgid "E15: Expected value, got closing bracket: %.*s" +msgstr "E15: 値が必要ですが閉じ括弧を受け取りました: %.*s" #, c-format -msgid "E712: Argument of %s must be a List or Dictionary" -msgstr "E712: %s の引数はリスト型または辞書型でなければなりません" - -msgid "E47: Error while reading errorfile" -msgstr "E47: エラーファイルの読込中にエラーが発生しました" - -msgid "E48: Not allowed in sandbox" -msgstr "E48: サンドボックスでは許されません" - -msgid "E523: Not allowed here" -msgstr "E523: ここでは許可されません" - -msgid "E359: Screen mode setting not supported" -msgstr "E359: スクリーンモードの設定には対応していません" - -msgid "E49: Invalid scroll size" -msgstr "E49: 無効なスクロール量です" - -msgid "E91: 'shell' option is empty" -msgstr "E91: 'shell' オプションが空です" - -msgid "E255: Couldn't read in sign data!" -msgstr "E255: sign のデータを読込めませんでした" - -msgid "E72: Close error on swap file" -msgstr "E72: スワップファイルのクローズ時エラーです" - -msgid "E73: tag stack empty" -msgstr "E73: タグスタックが空です" - -msgid "E74: Command too complex" -msgstr "E74: コマンドが複雑過ぎます" - -msgid "E75: Name too long" -msgstr "E75: 名前が長過ぎます" - -msgid "E76: Too many [" -msgstr "E76: [ が多過ぎます" - -msgid "E77: Too many file names" -msgstr "E77: ファイル名が多過ぎます" - -msgid "E488: Trailing characters" -msgstr "E488: 余分な文字が後ろにあります" - -msgid "E78: Unknown mark" -msgstr "E78: 未知のマーク" - -msgid "E79: Cannot expand wildcards" -msgstr "E79: ワイルドカードを展開できません" - -msgid "E591: 'winheight' cannot be smaller than 'winminheight'" -msgstr "E591: 'winheight' は 'winminheight' より小さくできません" - -msgid "E592: 'winwidth' cannot be smaller than 'winminwidth'" -msgstr "E592: 'winwidth' は 'winminwidth' より小さくできません" - -msgid "E80: Error while writing" -msgstr "E80: 書込み中のエラー" - -msgid "E939: Positive count required" -msgstr "E939: 正のカウントが必要です" - -msgid "E81: Using <SID> not in a script context" -msgstr "E81: スクリプト以外で<SID>が使われました" +msgid "E475: Unable to assign to empty list: %.*s" +msgstr "E475: 空のリストに割り当てることができません: %.*s" #, c-format -msgid "E107: Missing parentheses: %s" -msgstr "E107: カッコ '(' がありません: %s" - -msgid "E449: Invalid expression received" -msgstr "E449: 無効な式を受け取りました" - -msgid "E463: Region is guarded, cannot modify" -msgstr "E463: 領域が保護されているので、変更できません" - -msgid "E744: NetBeans does not allow changes in read-only files" -msgstr "E744: NetBeans は読込専用ファイルを変更することを許しません" - -msgid "E363: pattern uses more memory than 'maxmempattern'" -msgstr "E363: パターンが 'maxmempattern' 以上のメモリを使用します" - -msgid "E749: empty buffer" -msgstr "E749: バッファが空です" - -#, c-format -msgid "E86: Buffer %ld does not exist" -msgstr "E86: バッファ %ld はありません" - -msgid "E682: Invalid search pattern or delimiter" -msgstr "E682: 検索パターンか区切り記号が不正です" - -msgid "E139: File is loaded in another buffer" -msgstr "E139: 同じ名前のファイルが他のバッファで読込まれています" +msgid "E15: Unexpected closing figure brace: %.*s" +msgstr "E15: 予期しない閉じ波括弧: %.*s" #, c-format -msgid "E764: Option '%s' is not set" -msgstr "E764: オプション '%s' は設定されていません" - -msgid "E850: Invalid register name" -msgstr "E850: 無効なレジスタ名です" +msgid "E475: Nested lists not allowed when assigning: %.*s" +msgstr "E475: 割り当て時に入れ子のリストは許可されていません: %.*s" #, c-format -msgid "E919: Directory not found in '%s': \"%s\"" -msgstr "E919: ディレクトリが '%s' の中にありません: \"%s\"" - -msgid "E952: Autocommand caused recursive behavior" -msgstr "E952: Autocommandが再帰を引き起こしました" - -msgid "search hit TOP, continuing at BOTTOM" -msgstr "上まで検索したので下に戻ります" - -msgid "search hit BOTTOM, continuing at TOP" -msgstr "下まで検索したので上に戻ります" +msgid "E15: Expected value, got closing figure brace: %.*s" +msgstr "E15: 値が必要ですが '}' を受け取りました: %.*s" #, c-format -msgid "Need encryption key for \"%s\"" -msgstr "暗号キーが必要です: \"%s\"" - -msgid "empty keys are not allowed" -msgstr "空のキーは許可されていません" +msgid "E15: Don't know what figure brace means: %.*s" +msgstr "E15: 波括弧の意味がわかりません: %.*s" -msgid "dictionary is locked" -msgstr "辞書はロックされています" +#, fuzzy, c-format +#~ msgid "E15: Unexpected arrow: %.*s" +#~ msgstr "E15: 予期しないアロー: %.*s" -msgid "list is locked" -msgstr "リストはロックされています" +#, fuzzy, c-format +#~ msgid "E15: Arrow outside of lambda: %.*s" +#~ msgstr "E15: アローがラムダの外にあります: %.*s" #, c-format -msgid "failed to add key '%s' to dictionary" -msgstr "辞書にキー '%s' を追加するのに失敗しました" +msgid "E15: Unexpected dot: %.*s" +msgstr "E15: 予期しないドット: %.*s" -#, c-format -msgid "index must be int or slice, not %s" -msgstr "インデックスは %s ではなく整数かスライスにしてください" +#, fuzzy, c-format +#~ msgid "E15: Cannot concatenate in assignments: %.*s" +#~ msgstr "E15: 割り当て内で連結できません: %.*s" #, c-format -msgid "expected str() or unicode() instance, but got %s" -msgstr "str() もしくは unicode() のインスタンスが期待されているのに %s でした" +msgid "E15: Expected value, got parenthesis: %.*s" +msgstr "E15: 値が必要ですが丸括弧を受け取りました: %.*s" #, c-format -msgid "expected bytes() or str() instance, but got %s" -msgstr "bytes() もしくは str() のインスタンスが期待されているのに %s でした" +msgid "E15: Unexpected closing parenthesis: %.*s" +msgstr "E15: 予期しない閉じ丸括弧: %.*s" #, c-format -msgid "" -"expected int(), long() or something supporting coercing to long(), but got %s" -msgstr "long() かそれへ変換可能なものが期待されているのに %s でした" +msgid "E15: Expected value, got question mark: %.*s" +msgstr "E15: 値が必要ですが疑問符を受け取りました: %.*s" #, c-format -msgid "expected int() or something supporting coercing to int(), but got %s" -msgstr "int() かそれへ変換可能なものが期待されているのに %s でした" - -msgid "value is too large to fit into C int type" -msgstr "C言語の int 型としては値が大き過ぎます" - -msgid "value is too small to fit into C int type" -msgstr "C言語の int 型としては値が小さ過ぎます" - -msgid "number must be greater than zero" -msgstr "数値は 0 より大きくなければなりません" - -msgid "number must be greater or equal to zero" -msgstr "数値は 0 かそれ以上でなければなりません" - -msgid "can't delete OutputObject attributes" -msgstr "OutputObject属性を消せません" +msgid "E114: Missing double quote: %.*s" +msgstr "E114: ダブルクォートがありません: %.*s" #, c-format -msgid "invalid attribute: %s" -msgstr "無効な属性です: %s" - -msgid "E264: Python: Error initialising I/O objects" -msgstr "E264: Python: I/Oオブジェクトの初期化エラー" +msgid "E115: Missing single quote: %.*s" +msgstr "E115: シングルクォートがありません: %.*s" -msgid "failed to change directory" -msgstr "辞書の変更に失敗しました" +#, fuzzy, c-format +#~ msgid "E475: Expected closing bracket to end list assignment lvalue: %.*s" +#~ msgstr "E475: リスト割り当ての左辺値を終了するための閉じ括弧が必要です: %.*s" #, c-format -msgid "expected 3-tuple as imp.find_module() result, but got %s" -msgstr "imp.find_module() が %s を返しました (期待値: 3 要素のタプル)" - -#, c-format -msgid "expected 3-tuple as imp.find_module() result, but got tuple of size %d" -msgstr "imp.find_module() が %d 要素のタプルを返しました (期待値: 3)" - -msgid "internal error: imp.find_module returned tuple with NULL" -msgstr "内部エラー: imp.find_module が NULL を含むタプルを返しました" - -msgid "cannot delete vim.Dictionary attributes" -msgstr "vim.Dictionary属性は消せません" - -msgid "cannot modify fixed dictionary" -msgstr "固定された辞書は変更できません" +msgid "E15: Misplaced assignment: %.*s" +msgstr "E15: 割り当てが間違っています: %.*s" #, c-format -msgid "cannot set attribute %s" -msgstr "属性 %s は設定できません" - -msgid "hashtab changed during iteration" -msgstr "イテレーション中に hashtab が変更されました" +msgid "E15: Unexpected assignment: %.*s" +msgstr "E15: 予期しない割り当て: %.*s" #, c-format -msgid "expected sequence element of size 2, but got sequence of size %d" -msgstr "シーケンスの要素数には 2 が期待されていましたが %d でした" - -msgid "list constructor does not accept keyword arguments" -msgstr "リストのコンストラクタはキーワード引数を受け付けません" - -msgid "list index out of range" -msgstr "リスト範囲外のインデックスです" +msgid "E15: Expected value, got EOC: %.*s" +msgstr "E15: 値が必要ですが EOC を受け取りました: %.*s" #, c-format -msgid "internal error: failed to get Vim list item %d" -msgstr "内部エラー: vimのリスト要素 %d の取得に失敗しました" - -msgid "slice step cannot be zero" -msgstr "スライスのステップに 0 は指定できません" +msgid "E116: Missing closing parenthesis for function call: %.*s" +msgstr "E116: 関数の呼び出しに ')' がありません: %.*s" #, c-format -msgid "attempt to assign sequence of size greater than %d to extended slice" -msgstr "長さ %d の拡張スライスに、より長いスライスを割り当てようとしました" +msgid "E110: Missing closing parenthesis for nested expression: %.*s" +msgstr "E110: 入れ子の式に ')' がありません: %.*s" #, c-format -msgid "internal error: no Vim list item %d" -msgstr "内部エラー: vimのリスト要素 %d はありません" - -msgid "internal error: not enough list items" -msgstr "内部エラー: リストに十分な要素がありません" - -msgid "internal error: failed to add item to list" -msgstr "内部エラー: リストへの要素追加に失敗しました" +msgid "E697: Missing end of List ']': %.*s" +msgstr "E697: リスト型の最後に ']' がありません: %.*s" #, c-format -msgid "attempt to assign sequence of size %d to extended slice of size %d" -msgstr "長さ %d のスライスを %d の拡張スライスに割り当てようとしました" - -msgid "failed to add item to list" -msgstr "リストへの要素追加に失敗しました" - -msgid "cannot delete vim.List attributes" -msgstr "vim.List 属性は消せません" - -msgid "cannot modify fixed list" -msgstr "固定されたリストは変更できません" +msgid "E723: Missing end of Dictionary '}': %.*s" +msgstr "E723: 辞書型の最後に '}' がありません: %.*s" #, c-format -msgid "unnamed function %s does not exist" -msgstr "無名関数 %s は存在しません" +msgid "E15: Missing closing figure brace: %.*s" +msgstr "E15: '}' がありません: %.*s" #, c-format -msgid "function %s does not exist" -msgstr "関数 %s がありません" +msgid "E15: Missing closing figure brace for lambda: %.*s" +msgstr "E15: ラムダに '}' がありません: %.*s" #, c-format -msgid "failed to run function %s" -msgstr "関数 %s の実行に失敗しました" - -msgid "unable to get option value" -msgstr "オプションの値は取得できません" +msgid "E109: Missing ':' after '?': %.*s" +msgstr "E109: '?' の後に ':' がありません: %.*s" -msgid "internal error: unknown option type" -msgstr "内部エラー: 未知のオプション型です" - -msgid "problem while switching windows" -msgstr "ウィンドウを切換中に問題が発生しました" - -#, c-format -msgid "unable to unset global option %s" -msgstr "グローバルオプション %s の設定解除はできません" +msgid "E1159: Cannot split a window when closing the buffer" +msgstr "E1159: バッファを閉じている間にウィンドウを分割することはできません" -#, c-format -msgid "unable to unset option %s which does not have global value" -msgstr "グローバルな値の無いオプション %s の設定解除はできません" - -msgid "attempt to refer to deleted tab page" -msgstr "削除されたタブを参照しようとしました" - -msgid "no such tab page" -msgstr "そのようなタブページはありません" - -msgid "attempt to refer to deleted window" -msgstr "削除されたウィンドウを参照しようとしました" - -msgid "readonly attribute: buffer" -msgstr "読込専用属性: バッファー" - -msgid "cursor position outside buffer" -msgstr "カーソル位置がバッファの外側です" - -msgid "no such window" -msgstr "そのようなウィンドウはありません" - -msgid "attempt to refer to deleted buffer" -msgstr "削除されたバッファを参照しようとしました" - -msgid "failed to rename buffer" -msgstr "バッファ名の変更に失敗しました" - -msgid "mark name must be a single character" -msgstr "マーク名は1文字のアルファベットでなければなりません" - -#, c-format -msgid "expected vim.Buffer object, but got %s" -msgstr "vim.Bufferオブジェクトが期待されているのに %s でした" - -#, c-format -msgid "failed to switch to buffer %d" -msgstr "指定されたバッファ %d への切り替えに失敗しました" - -#, c-format -msgid "expected vim.Window object, but got %s" -msgstr "vim.Windowオブジェクトが期待されているのに %s でした" - -msgid "failed to find window in the current tab page" -msgstr "現在のタブには指定されたウィンドウがありませんでした" - -msgid "did not switch to the specified window" -msgstr "指定されたウィンドウに切り替えませんでした" - -#, c-format -msgid "expected vim.TabPage object, but got %s" -msgstr "vim.TabPageオブジェクトが期待されているのに %s でした" - -msgid "did not switch to the specified tab page" -msgstr "指定されたタブページに切り替えませんでした" - -msgid "failed to run the code" -msgstr "コードの実行に失敗しました" - -msgid "E858: Eval did not return a valid python object" -msgstr "E858: 式評価は有効なpythonオブジェクトを返しませんでした" - -msgid "E859: Failed to convert returned python object to a Vim value" -msgstr "E859: 返されたpythonオブジェクトをvimの値に変換できませんでした" - -#, c-format -msgid "unable to convert %s to a Vim dictionary" -msgstr "%s vimの辞書型に変換できません" - -#, c-format -msgid "unable to convert %s to a Vim list" -msgstr "%s をvimのリストに変換できません" - -#, c-format -msgid "unable to convert %s to a Vim structure" -msgstr "%s をvimの構造体に変換できません" - -msgid "internal error: NULL reference passed" -msgstr "内部エラー: NULL参照が渡されました" - -msgid "internal error: invalid value type" -msgstr "内部エラー: 無効な値型です" - -msgid "" -"Failed to set path hook: sys.path_hooks is not a list\n" -"You should now do the following:\n" -"- append vim.path_hook to sys.path_hooks\n" -"- append vim.VIM_SPECIAL_PATH to sys.path\n" -msgstr "" -"パスフックの設定に失敗しました: sys.path_hooks がリストではありません\n" -"すぐに下記を実施してください:\n" -"- vim.path_hooks を sys.path_hooks へ追加\n" -"- vim.VIM_SPECIAL_PATH を sys.path へ追加\n" +msgid "Already only one window" +msgstr "既にウィンドウは1つしかありません" -msgid "" -"Failed to set path: sys.path is not a list\n" -"You should now append vim.VIM_SPECIAL_PATH to sys.path" -msgstr "" -"パスの設定に失敗しました: sys.path がリストではありません\n" -"すぐに vim.VIM_SPECIAL_PATH を sys.path に追加してください" +msgid "E441: There is no preview window" +msgstr "E441: プレビューウィンドウがありません" -msgid "" -"Vim macro files (*.vim)\t*.vim\n" -"All Files (*.*)\t*.*\n" -msgstr "" -"Vimマクロファイル (*.vim)\t*.vim\n" -"すべてのファイル (*.*)\t*.*\n" +msgid "E442: Can't split topleft and botright at the same time" +msgstr "E442: 左上と右下を同時に分割することはできません" -msgid "All Files (*.*)\t*.*\n" -msgstr "すべてのファイル (*.*)\t*.*\n" +msgid "E443: Cannot rotate when another window is split" +msgstr "E443: 他のウィンドウが分割されている時には順回できません" -msgid "" -"All Files (*.*)\t*.*\n" -"C source (*.c, *.h)\t*.c;*.h\n" -"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n" -"VB code (*.bas, *.frm)\t*.bas;*.frm\n" -"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n" -msgstr "" -"すべてのファイル (*.*)\t*.*\n" -"Cソース (*.c, *.h)\t*.c;*.h\n" -"C++ソース (*.cpp, *.hpp)\t*.cpp;*.hpp\n" -"VBコード (*.bas, *.frm)\t*.bas;*.frm\n" -"Vimファイル (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n" +msgid "E444: Cannot close last window" +msgstr "E444: 最後のウィンドウを閉じることはできません" -msgid "" -"Vim macro files (*.vim)\t*.vim\n" -"All Files (*)\t*\n" -msgstr "" -"Vim マクロファイル (*.vim)\t*.vim\n" -"すべてのファイル (*)\t*\n" +msgid "E814: Cannot close window, only autocmd window would remain" +msgstr "E814: autocmdウィンドウしか残らないため、ウィンドウは閉じられません" -msgid "All Files (*)\t*\n" -msgstr "すべてのファイル (*)\t*\n" +msgid "E445: Other window contains changes" +msgstr "E445: 他のウィンドウには変更があります" -msgid "" -"All Files (*)\t*\n" -"C source (*.c, *.h)\t*.c;*.h\n" -"C++ source (*.cpp, *.hpp)\t*.cpp;*.hpp\n" -"Vim files (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n" -msgstr "" -"すべてのファイル (*)\t*\n" -"Cソース (*.c, *.h)\t*.c;*.h\n" -"C++ソース (*.cpp, *.hpp)\t*.cpp;*.hpp\n" -"Vimファイル (*.vim, _vimrc, _gvimrc)\t*.vim;_vimrc;_gvimrc\n" +msgid "E446: No file name under cursor" +msgstr "E446: カーソルの下にファイル名がありません" diff --git a/src/nvim/po/ru.po b/src/nvim/po/ru.po index 1235111c58..160de6c67e 100644 --- a/src/nvim/po/ru.po +++ b/src/nvim/po/ru.po @@ -4187,9 +4187,9 @@ msgid "" "&No\n" "&Cancel" msgstr "" -"&Да\n" -"&Нет\n" -"О&тмена" +"&Y Да\n" +"&N Нет\n" +"&C Отмена" #: ../message.c:3045 msgid "" diff --git a/src/nvim/popupmenu.c b/src/nvim/popupmenu.c index e34d6fd97f..86f3611ec5 100644 --- a/src/nvim/popupmenu.c +++ b/src/nvim/popupmenu.c @@ -6,6 +6,7 @@ #include <stdbool.h> #include <string.h> +#include "nvim/api/buffer.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" #include "nvim/api/vim.h" @@ -13,11 +14,16 @@ #include "nvim/autocmd.h" #include "nvim/buffer.h" #include "nvim/buffer_defs.h" +#include "nvim/buffer_updates.h" +#include "nvim/change.h" #include "nvim/charset.h" #include "nvim/drawscreen.h" +#include "nvim/edit.h" #include "nvim/eval/typval.h" #include "nvim/ex_cmds.h" #include "nvim/ex_cmds_defs.h" +#include "nvim/extmark.h" +#include "nvim/extmark_defs.h" #include "nvim/getchar.h" #include "nvim/gettext_defs.h" #include "nvim/globals.h" @@ -33,6 +39,7 @@ #include "nvim/menu.h" #include "nvim/message.h" #include "nvim/move.h" +#include "nvim/ops.h" #include "nvim/option.h" #include "nvim/option_defs.h" #include "nvim/option_vars.h" @@ -140,7 +147,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i // to avoid that must_redraw is set when 'cursorcolumn' is on. pum_is_visible = true; pum_is_drawn = true; - validate_cursor_col(); + validate_cursor_col(curwin); int above_row = 0; int below_row = cmdline_row; @@ -273,7 +280,7 @@ void pum_display(pumitem_T *array, int size, int selected, bool array_changed, i context_lines = 0; } else { // Leave two lines of context if possible - validate_cheight(); + validate_cheight(curwin); if (curwin->w_cline_row + curwin->w_cline_height - curwin->w_wrow >= 3) { context_lines = 3; } else { @@ -665,56 +672,10 @@ void pum_redraw(void) } } -/// create a floating preview window for info -/// @return NULL when no enough room to show -static win_T *pum_create_float_preview(bool enter) -{ - WinConfig config = WIN_CONFIG_INIT; - config.relative = kFloatRelativeEditor; - // when pum_above is SW otherwise is NW - config.anchor = pum_above ? kFloatAnchorSouth : 0; - int col = pum_col + pum_width + pum_scrollbar + 1; - // TODO(glepnir): support config align border by using completepopup - // align menu - config.row = pum_row; - int right_extra = Columns - col; - if (right_extra > 0) { - config.width = right_extra; - config.col = col - 1; - } else if (pum_col - 2 > 0) { - config.width = pum_col - 2; - config.col = pum_col - config.width - 1; - } else { - return NULL; - } - config.height = pum_height; - config.style = kWinStyleMinimal; - config.hide = true; - Error err = ERROR_INIT; - win_T *wp = win_new_float(NULL, true, config, &err); - // TODO(glepnir): remove win_enter usage - if (enter) { - win_enter(wp, false); - } - - // create a new buffer - Buffer b = nvim_create_buf(false, true, &err); - if (!b) { - win_free(wp, NULL); - return NULL; - } - buf_T *buf = find_buffer_by_handle(b, &err); - set_string_option_direct_in_buf(buf, kOptBufhidden, "wipe", OPT_LOCAL, 0); - wp->w_float_is_info = true; - wp->w_p_diff = false; - buf->b_p_bl = false; - win_set_buf(wp, buf, true, &err); - return wp; -} - /// set info text to preview buffer. static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *max_width) { + bcount_t inserted_bytes = 0; for (char *p = info; *p != NUL;) { int text_width = 0; char *e = vim_strchr(p, '\n'); @@ -728,6 +689,7 @@ static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *ma } *e = NUL; ml_append_buf(buf, (*lnum)++, p, (int)(e - p + 1), false); + inserted_bytes += (bcount_t)strlen(p) + 1; text_width = (int)mb_string2cells(p); if (text_width > *max_width) { *max_width = text_width; @@ -737,66 +699,78 @@ static void pum_preview_set_text(buf_T *buf, char *info, linenr_T *lnum, int *ma } // delete the empty last line ml_delete_buf(buf, buf->b_ml.ml_line_count, false); + if (strstr(p_cot, "popup") != NULL) { + extmark_splice(buf, 1, 0, 1, 0, 0, buf->b_ml.ml_line_count, 0, inserted_bytes, kExtmarkNoUndo); + } } -/// adjust floating preview window width and height -static void pum_adjust_float_position(win_T *wp, int height, int width) +/// adjust floating info preview window position +static void pum_adjust_info_position(win_T *wp, int height, int width) { - // when floating window in right and right no enough room to show - // but left has enough room, adjust floating window to left. - if (wp->w_config.width < width && wp->w_config.col > pum_col) { - if ((pum_col - 2) > width) { - wp->w_config.width = width; - wp->w_config.col = pum_col - width - 1; - } + int col = pum_col + pum_width + pum_scrollbar + 1; + // TODO(glepnir): support config align border by using completepopup + // align menu + int right_extra = Columns - col; + int left_extra = pum_col - 2; + + if (right_extra > width) { // place in right + wp->w_config.width = width; + wp->w_config.col = col - 1; + } else if (left_extra > width) { // place in left + wp->w_config.width = width; + wp->w_config.col = pum_col - wp->w_config.width - 1; + } else { // either width is enough just use the biggest one. + const bool place_in_right = right_extra > left_extra; + wp->w_config.width = place_in_right ? right_extra : left_extra; + wp->w_config.col = place_in_right ? col - 1 : pum_col - wp->w_config.width - 1; } - wp->w_config.width = MIN(wp->w_config.width, width); + // when pum_above is SW otherwise is NW + wp->w_config.anchor = pum_above ? kFloatAnchorSouth : 0; + wp->w_config.row = pum_above ? pum_row + height : pum_row; wp->w_config.height = MIN(Rows, height); wp->w_config.hide = false; win_config_float(wp, wp->w_config); } -/// used in nvim_complete_set -win_T *pum_set_info(int pum_idx, char *info) +/// Used for nvim__complete_set +/// +/// @param selected the selected compl item. +/// @parma info Info string. +/// @return a win_T pointer. +win_T *pum_set_info(int selected, char *info) { - if (!pum_is_visible || pum_idx < 0 || pum_idx > pum_size) { - return NULL; - } - pum_array[pum_idx].pum_info = xstrdup(info); - compl_set_info(pum_idx); - bool use_float = strstr(p_cot, "popup") != NULL ? true : false; - if (pum_idx != pum_selected || !use_float) { + if (!pum_is_visible || !compl_match_curr_select(selected)) { return NULL; } - block_autocmds(); RedrawingDisabled++; no_u_sync++; win_T *wp = win_float_find_preview(); if (wp == NULL) { - wp = pum_create_float_preview(false); - // no enough room to show + wp = win_float_create(false, true); if (!wp) { return NULL; } } else { // clean exist buffer + linenr_T count = wp->w_buffer->b_ml.ml_line_count; while (!buf_is_empty(wp->w_buffer)) { ml_delete_buf(wp->w_buffer, 1, false); } + bcount_t deleted_bytes = get_region_bytecount(wp->w_buffer, 1, count, 0, 0); + extmark_splice(wp->w_buffer, 1, 0, count, 0, deleted_bytes, 1, 0, 0, kExtmarkNoUndo); } - no_u_sync--; - RedrawingDisabled--; - linenr_T lnum = 0; int max_info_width = 0; pum_preview_set_text(wp->w_buffer, info, &lnum, &max_info_width); - redraw_later(wp, UPD_SOME_VALID); + no_u_sync--; + RedrawingDisabled--; + redraw_later(wp, UPD_NOT_VALID); if (wp->w_p_wrap) { lnum += plines_win(wp, lnum, true); } - pum_adjust_float_position(wp, lnum, max_info_width); + pum_adjust_info_position(wp, lnum, max_info_width); unblock_autocmds(); return wp; } @@ -820,6 +794,13 @@ static bool pum_set_selected(int n, int repeat) int prev_selected = pum_selected; pum_selected = n; + bool use_float = strstr(p_cot, "popup") != NULL; + // when new leader add and info window is shown and no selected we still + // need use the first index item to update the info float window position. + bool force_select = use_float && pum_selected < 0 && win_float_find_preview(); + if (force_select) { + pum_selected = 0; + } if ((pum_selected >= 0) && (pum_selected < pum_size)) { if (pum_first > pum_selected - 4) { @@ -882,7 +863,6 @@ static bool pum_set_selected(int n, int repeat) && (vim_strchr(p_cot, 'p') != NULL)) { win_T *curwin_save = curwin; tabpage_T *curtab_save = curtab; - bool use_float = strstr(p_cot, "popup") != NULL ? true : false; if (use_float) { block_autocmds(); @@ -907,7 +887,7 @@ static bool pum_set_selected(int n, int repeat) if (wp) { win_enter(wp, false); } else { - wp = pum_create_float_preview(true); + wp = win_float_create(true, true); if (wp) { resized = true; } @@ -978,7 +958,7 @@ static bool pum_set_selected(int n, int repeat) lnum += plines_win(curwin, lnum, true); } // adjust floating window by actually height and max info text width - pum_adjust_float_position(curwin, lnum, max_info_width); + pum_adjust_info_position(curwin, lnum, max_info_width); } if ((curwin != curwin_save && win_valid(curwin_save)) @@ -995,7 +975,7 @@ static bool pum_set_selected(int n, int repeat) } // Return cursor to where we were - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_SOME_VALID); // When the preview window was resized we need to @@ -1038,6 +1018,11 @@ static bool pum_set_selected(int n, int repeat) } } + // restore before selected value + if (force_select) { + pum_selected = n; + } + return resized; } @@ -1296,7 +1281,7 @@ void pum_show_popupmenu(vimmenu_T *menu) pum_is_drawn = true; pum_grid.zindex = kZIndexCmdlinePopupMenu; // show above cmdline area #23275 pum_redraw(); - setcursor_mayforce(true); + setcursor_mayforce(curwin, true); int c = vgetc(); diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 651ebc9f93..e022184f2f 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -773,9 +773,9 @@ static int qf_get_next_buf_line(qfstate_T *state) return QF_END_OF_INPUT; } char *p_buf = ml_get_buf(state->buf, state->buflnum); + size_t len = (size_t)ml_get_buf_len(state->buf, state->buflnum); state->buflnum += 1; - size_t len = strlen(p_buf); if (len > IOSIZE - 2) { state->linebuf = qf_grow_linebuf(state, len); } else { @@ -2699,7 +2699,8 @@ static void qf_goto_win_with_qfl_file(int qf_fnum) // Didn't find it, go to the window before the quickfix // window, unless 'switchbuf' contains 'uselast': in this case we // try to jump to the previously used window first. - if ((swb_flags & SWB_USELAST) && win_valid(prevwin)) { + if ((swb_flags & SWB_USELAST) && win_valid(prevwin) + && !prevwin->w_p_wfb) { win = prevwin; } else if (altwin != NULL) { win = altwin; @@ -2714,6 +2715,7 @@ static void qf_goto_win_with_qfl_file(int qf_fnum) // Remember a usable window. if (altwin == NULL && !win->w_p_pvw + && !win->w_p_wfb && bt_normal(win->w_buffer)) { altwin = win; } @@ -2802,8 +2804,43 @@ static int qf_jump_edit_buffer(qf_info_T *qi, qfline_T *qf_ptr, int forceit, int ECMD_HIDE + ECMD_SET_HELP, prev_winid == curwin->handle ? curwin : NULL); } else { - retval = buflist_getfile(qf_ptr->qf_fnum, 1, - GETF_SETMARK | GETF_SWITCH, forceit); + int fnum = qf_ptr->qf_fnum; + + if (!forceit && curwin->w_p_wfb && curbuf->b_fnum != fnum) { + if (qi->qfl_type == QFLT_LOCATION) { + // Location lists cannot split or reassign their window + // so 'winfixbuf' windows must fail + emsg(_(e_winfixbuf_cannot_go_to_buffer)); + return FAIL; + } + + if (win_valid(prevwin) && !prevwin->w_p_wfb + && !bt_quickfix(prevwin->w_buffer)) { + // 'winfixbuf' is set; attempt to change to a window without it + // that isn't a quickfix/location list window. + win_goto(prevwin); + } + if (curwin->w_p_wfb) { + // Split the window, which will be 'nowinfixbuf', and set curwin + // to that + if (win_split(0, 0) == OK) { + *opened_window = true; + } + if (curwin->w_p_wfb) { + // Autocommands set 'winfixbuf' or sent us to another window + // with it set, or we failed to split the window. Give up, + // but don't return immediately, as they may have messed + // with the list. + emsg(_(e_winfixbuf_cannot_go_to_buffer)); + retval = FAIL; + } + } + } + + if (retval == OK) { + retval = buflist_getfile(fnum, 1, + GETF_SETMARK | GETF_SWITCH, forceit); + } } // If a location list, check whether the associated window is still // present. @@ -2852,12 +2889,12 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char if (qf_col > 0) { curwin->w_cursor.coladd = 0; if (qf_viscol == true) { - coladvance(qf_col - 1); + coladvance(curwin, qf_col - 1); } else { curwin->w_cursor.col = qf_col - 1; } curwin->w_set_curswant = true; - check_cursor(); + check_cursor(curwin); } else { beginline(BL_WHITE | BL_FIX); } @@ -2865,7 +2902,7 @@ static void qf_jump_goto_line(linenr_T qf_lnum, int qf_col, char qf_viscol, char // Move the cursor to the first line in the buffer pos_T save_cursor = curwin->w_cursor; curwin->w_cursor.lnum = 0; - if (!do_search(NULL, '/', '/', qf_pattern, 1, SEARCH_KEEP, NULL)) { + if (!do_search(NULL, '/', '/', qf_pattern, strlen(qf_pattern), 1, SEARCH_KEEP, NULL)) { curwin->w_cursor = save_cursor; } } @@ -3794,7 +3831,7 @@ void ex_copen(exarg_T *eap) curwin->w_cursor.lnum = lnum; curwin->w_cursor.col = 0; - check_cursor(); + check_cursor(curwin); update_topline(curwin); // scroll to show the line } @@ -4158,6 +4195,12 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q } } + FOR_ALL_TAB_WINDOWS(tp, wp) { + if (wp->w_buffer == curbuf) { + wp->w_skipcol = 0; + } + } + // Remove all undo information u_clearallandblockfree(curbuf); } @@ -4237,10 +4280,10 @@ static void qf_fill_buffer(qf_list_T *qfl, buf_T *buf, qfline_T *old_last, int q set_option_value_give_err(kOptFiletype, STATIC_CSTR_AS_OPTVAL("qf"), OPT_LOCAL); curbuf->b_p_ma = false; - keep_filetype = true; // don't detect 'filetype' + curbuf->b_keep_filetype = true; // don't detect 'filetype' apply_autocmds(EVENT_BUFREADPOST, "quickfix", NULL, false, curbuf); apply_autocmds(EVENT_BUFWINENTER, "quickfix", NULL, false, curbuf); - keep_filetype = false; + curbuf->b_keep_filetype = false; curbuf->b_ro_locked--; // make sure it will be redrawn @@ -4297,6 +4340,11 @@ static void qf_jump_first(qf_info_T *qi, unsigned save_qfid, int forceit) if (qf_restore_list(qi, save_qfid) == FAIL) { return; } + + if (!check_can_set_curbuf_forceit(forceit)) { + return; + } + // Autocommands might have cleared the list, check for that if (!qf_list_empty(qf_get_curlist(qi))) { qf_jump(qi, 0, 0, forceit); @@ -5112,7 +5160,7 @@ void ex_cfile(exarg_T *eap) } } if (*eap->arg != NUL) { - set_string_option_direct(kOptErrorfile, eap->arg, 0, 0); + set_option_direct(kOptErrorfile, CSTR_AS_OPTVAL(eap->arg), 0, 0); } char *enc = (*curbuf->b_p_menc != NUL) ? curbuf->b_p_menc : p_menc; @@ -5125,7 +5173,7 @@ void ex_cfile(exarg_T *eap) // This function is used by the :cfile, :cgetfile and :caddfile // commands. - // :cfile always creates a new quickfix list and jumps to the + // :cfile always creates a new quickfix list and may jump to the // first error. // :cgetfile creates a new quickfix list but doesn't jump to the // first error. @@ -5314,12 +5362,13 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp break; } col = regmatch->endpos[0].col + (col == regmatch->endpos[0].col); - if (col > (colnr_T)strlen(ml_get_buf(buf, lnum))) { + if (col > ml_get_buf_len(buf, lnum)) { break; } } } else { char *const str = ml_get_buf(buf, lnum); + const colnr_T linelen = ml_get_buf_len(buf, lnum); int score; uint32_t matches[MAX_FUZZY_MATCHES]; const size_t sz = sizeof(matches) / sizeof(matches[0]); @@ -5358,7 +5407,7 @@ static bool vgr_match_buflines(qf_list_T *qfl, char *fname, buf_T *buf, char *sp break; } col = (colnr_T)matches[pat_len - 1] + col + 1; - if (col > (colnr_T)strlen(str)) { + if (col > linelen) { break; } } @@ -5587,6 +5636,10 @@ theend: /// ":lvimgrepadd {pattern} file(s)" void ex_vimgrep(exarg_T *eap) { + if (!check_can_set_curbuf_forceit(eap->forceit)) { + return; + } + char *au_name = vgr_get_auname(eap->cmdidx); if (au_name != NULL && apply_autocmds(EVENT_QUICKFIXCMDPRE, au_name, curbuf->b_fname, true, curbuf)) { diff --git a/src/nvim/rbuffer.c b/src/nvim/rbuffer.c index ef286b3e22..493c079d4c 100644 --- a/src/nvim/rbuffer.c +++ b/src/nvim/rbuffer.c @@ -123,7 +123,10 @@ char *rbuffer_read_ptr(RBuffer *buf, size_t *read_count) FUNC_ATTR_NONNULL_ALL void rbuffer_consumed(RBuffer *buf, size_t count) FUNC_ATTR_NONNULL_ALL { - assert(count && count <= buf->size); + if (count == 0) { + return; + } + assert(count <= buf->size); buf->read_ptr += count; if (buf->read_ptr >= buf->end_ptr) { diff --git a/src/nvim/regexp.c b/src/nvim/regexp.c index 86082adbb6..5600d6a2f8 100644 --- a/src/nvim/regexp.c +++ b/src/nvim/regexp.c @@ -45,6 +45,12 @@ #include "nvim/types_defs.h" #include "nvim/vim_defs.h" +typedef enum { + RGLF_LINE = 0x01, + RGLF_LENGTH = 0x02, + RGLF_SUBMATCH = 0x04, +} reg_getline_flags_T; + enum { /// In the NFA engine: how many braces are allowed. /// TODO(RE): Use dynamic memory allocation instead of static, like here @@ -386,6 +392,7 @@ static int re_multi_type(int c) } static char *reg_prev_sub = NULL; +static size_t reg_prev_sublen = 0; // REGEXP_INRANGE contains all characters which are always special in a [] // range after '\'. @@ -420,60 +427,82 @@ static int backslash_trans(int c) return c; } +enum { + CLASS_ALNUM = 0, + CLASS_ALPHA, + CLASS_BLANK, + CLASS_CNTRL, + CLASS_DIGIT, + CLASS_GRAPH, + CLASS_LOWER, + CLASS_PRINT, + CLASS_PUNCT, + CLASS_SPACE, + CLASS_UPPER, + CLASS_XDIGIT, + CLASS_TAB, + CLASS_RETURN, + CLASS_BACKSPACE, + CLASS_ESCAPE, + CLASS_IDENT, + CLASS_KEYWORD, + CLASS_FNAME, + CLASS_NONE = 99, +}; + /// Check for a character class name "[:name:]". "pp" points to the '['. /// Returns one of the CLASS_ items. CLASS_NONE means that no item was /// recognized. Otherwise "pp" is advanced to after the item. static int get_char_class(char **pp) { - static const char *(class_names[]) = { - "alnum:]", -#define CLASS_ALNUM 0 - "alpha:]", -#define CLASS_ALPHA 1 - "blank:]", -#define CLASS_BLANK 2 - "cntrl:]", -#define CLASS_CNTRL 3 - "digit:]", -#define CLASS_DIGIT 4 - "graph:]", -#define CLASS_GRAPH 5 - "lower:]", -#define CLASS_LOWER 6 - "print:]", -#define CLASS_PRINT 7 - "punct:]", -#define CLASS_PUNCT 8 - "space:]", -#define CLASS_SPACE 9 - "upper:]", -#define CLASS_UPPER 10 - "xdigit:]", -#define CLASS_XDIGIT 11 - "tab:]", -#define CLASS_TAB 12 - "return:]", -#define CLASS_RETURN 13 - "backspace:]", -#define CLASS_BACKSPACE 14 - "escape:]", -#define CLASS_ESCAPE 15 - "ident:]", -#define CLASS_IDENT 16 - "keyword:]", -#define CLASS_KEYWORD 17 - "fname:]", -#define CLASS_FNAME 18 + // must be sorted by the 'value' field because it is used by bsearch()! + static keyvalue_T char_class_tab[] = { + KEYVALUE_ENTRY(CLASS_ALNUM, "alnum:]"), + KEYVALUE_ENTRY(CLASS_ALPHA, "alpha:]"), + KEYVALUE_ENTRY(CLASS_BACKSPACE, "backspace:]"), + KEYVALUE_ENTRY(CLASS_BLANK, "blank:]"), + KEYVALUE_ENTRY(CLASS_CNTRL, "cntrl:]"), + KEYVALUE_ENTRY(CLASS_DIGIT, "digit:]"), + KEYVALUE_ENTRY(CLASS_ESCAPE, "escape:]"), + KEYVALUE_ENTRY(CLASS_FNAME, "fname:]"), + KEYVALUE_ENTRY(CLASS_GRAPH, "graph:]"), + KEYVALUE_ENTRY(CLASS_IDENT, "ident:]"), + KEYVALUE_ENTRY(CLASS_KEYWORD, "keyword:]"), + KEYVALUE_ENTRY(CLASS_LOWER, "lower:]"), + KEYVALUE_ENTRY(CLASS_PRINT, "print:]"), + KEYVALUE_ENTRY(CLASS_PUNCT, "punct:]"), + KEYVALUE_ENTRY(CLASS_RETURN, "return:]"), + KEYVALUE_ENTRY(CLASS_SPACE, "space:]"), + KEYVALUE_ENTRY(CLASS_TAB, "tab:]"), + KEYVALUE_ENTRY(CLASS_UPPER, "upper:]"), + KEYVALUE_ENTRY(CLASS_XDIGIT, "xdigit:]") }; -#define CLASS_NONE 99 - int i; - if ((*pp)[1] == ':') { - for (i = 0; i < (int)ARRAY_SIZE(class_names); i++) { - if (strncmp(*pp + 2, class_names[i], strlen(class_names[i])) == 0) { - *pp += strlen(class_names[i]) + 2; - return i; - } + // check that the value of "pp" has a chance of matching + if ((*pp)[1] == ':' && ASCII_ISLOWER((*pp)[2]) + && ASCII_ISLOWER((*pp)[3]) && ASCII_ISLOWER((*pp)[4])) { + // this function can be called repeatedly with the same value for "pp" + // so we cache the last found entry. + static keyvalue_T *last_entry = NULL; + + keyvalue_T target = { + .key = 0, + .value = *pp + 2, + .length = 0, // not used, see cmp_keyvalue_value_n() + }; + + keyvalue_T *entry; + if (last_entry != NULL && cmp_keyvalue_value_n(&target, last_entry) == 0) { + entry = last_entry; + } else { + entry = (keyvalue_T *)bsearch(&target, &char_class_tab, + ARRAY_SIZE(char_class_tab), + sizeof(char_class_tab[0]), cmp_keyvalue_value_n); + } + if (entry != NULL) { + last_entry = entry; + *pp += entry->length + 2; + return entry->key; } } return CLASS_NONE; @@ -745,6 +774,7 @@ char *skip_regexp_ex(char *startp, int dirc, int magic, char **newp, int *droppe { magic_T mymagic; char *p = startp; + size_t startplen = 0; if (magic) { mymagic = MAGIC_ON; @@ -766,14 +796,18 @@ char *skip_regexp_ex(char *startp, int dirc, int magic, char **newp, int *droppe } else if (p[0] == '\\' && p[1] != NUL) { if (dirc == '?' && newp != NULL && p[1] == '?') { // change "\?" to "?", make a copy first. + if (startplen == 0) { + startplen = strlen(startp); + } if (*newp == NULL) { - *newp = xstrdup(startp); + *newp = xstrnsave(startp, startplen); p = *newp + (p - startp); + startp = *newp; } if (dropped != NULL) { (*dropped)++; } - STRMOVE(p, p + 1); + memmove(p, p + 1, startplen - (size_t)((p + 1) - startp) + 1); } else { p++; // skip next character } @@ -1264,19 +1298,89 @@ static bool reg_iswordc(int c) return vim_iswordc_buf(c, rex.reg_buf); } -// Get pointer to the line "lnum", which is relative to "reg_firstlnum". -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 - if (rex.reg_firstlnum + lnum < 1) { - return NULL; +static bool can_f_submatch = false; ///< true when submatch() can be used + +/// These pointers are used for reg_submatch(). Needed for when the +/// substitution string is an expression that contains a call to substitute() +/// and submatch(). +typedef struct { + regmatch_T *sm_match; + regmmatch_T *sm_mmatch; + linenr_T sm_firstlnum; + linenr_T sm_maxline; + int sm_line_lbr; +} regsubmatch_T; + +static regsubmatch_T rsm; ///< can only be used when can_f_submatch is true + +/// Common code for reg_getline(), reg_getline_len(), reg_getline_submatch() and +/// reg_getline_submatch_len(). +/// +/// @param flags a bitmask that controls what info is to be returned +/// and whether or not submatch is in effect. +static void reg_getline_common(linenr_T lnum, reg_getline_flags_T flags, char **line, + colnr_T *length) +{ + bool get_line = flags & RGLF_LINE; + bool get_length = flags & RGLF_LENGTH; + linenr_T firstlnum; + linenr_T maxline; + + if (flags & RGLF_SUBMATCH) { + firstlnum = rsm.sm_firstlnum + lnum; + maxline = rsm.sm_maxline; + } else { + firstlnum = rex.reg_firstlnum + lnum; + maxline = rex.reg_maxline; + } + + // when looking behind for a match/no-match lnum is negative. but we + // can't go before line 1. + if (firstlnum < 1) { + if (get_line) { + *line = NULL; + } + if (get_length) { + *length = 0; + } + + return; } - if (lnum > rex.reg_maxline) { - // Must have matched the "\n" in the last line. - return ""; + + if (lnum > maxline) { + // must have matched the "\n" in the last line. + if (get_line) { + *line = ""; + } + if (get_length) { + *length = 0; + } + + return; + } + + if (get_line) { + *line = ml_get_buf(rex.reg_buf, firstlnum); + } + if (get_length) { + *length = ml_get_buf_len(rex.reg_buf, firstlnum); } - return ml_get_buf(rex.reg_buf, rex.reg_firstlnum + lnum); +} + +/// Get pointer to the line "lnum", which is relative to "reg_firstlnum". +static char *reg_getline(linenr_T lnum) +{ + char *line; + reg_getline_common(lnum, RGLF_LINE, &line, NULL); + return line; +} + +/// Get length of line "lnum", which is relative to "reg_firstlnum". +static colnr_T reg_getline_len(linenr_T lnum) +{ + colnr_T length; + reg_getline_common(lnum, RGLF_LENGTH, NULL, &length); + return length; } static uint8_t *reg_startzp[NSUBEXP]; // Workspace to mark beginning @@ -1510,7 +1614,7 @@ static int match_with_backref(linenr_T start_lnum, colnr_T start_col, linenr_T e if (clnum == end_lnum) { len = end_col - ccol; } else { - len = (int)strlen(p + ccol); + len = reg_getline_len(clnum) - ccol; } if (cstrncmp(p + ccol, (char *)rex.input, &len) != 0) { @@ -1746,42 +1850,58 @@ static void do_lower(int *d, int c) char *regtilde(char *source, int magic, bool preview) { char *newsub = source; + size_t newsublen = 0; + char tilde[3] = { '~', NUL, NUL }; + size_t tildelen = 1; + bool error = false; + + if (!magic) { + tilde[0] = '\\'; + tilde[1] = '~'; + tilde[2] = NUL; + tildelen = 2; + } + + char *p; + for (p = newsub; *p; p++) { + if (strncmp(p, tilde, tildelen) == 0) { + size_t prefixlen = (size_t)(p - newsub); // not including the tilde + char *postfix = p + tildelen; + size_t postfixlen; + size_t tmpsublen; + + if (newsublen == 0) { + newsublen = strlen(newsub); + } + newsublen -= tildelen; + postfixlen = newsublen - prefixlen; + tmpsublen = prefixlen + reg_prev_sublen + postfixlen; - for (char *p = newsub; *p; p++) { - if ((*p == '~' && magic) || (*p == '\\' && *(p + 1) == '~' && !magic)) { - if (reg_prev_sub != NULL) { - // length = len(newsub) - 1 + len(prev_sub) + 1 + if (tmpsublen > 0 && reg_prev_sub != NULL) { // Avoid making the text longer than MAXCOL, it will cause // trouble at some point. - size_t prevsublen = strlen(reg_prev_sub); - size_t newsublen = strlen(newsub); - if (prevsublen > MAXCOL || newsublen > MAXCOL - || newsublen + prevsublen > MAXCOL) { + if (tmpsublen > MAXCOL) { emsg(_(e_resulting_text_too_long)); + error = true; break; } - char *tmpsub = xmalloc(newsublen + prevsublen); + char *tmpsub = xmalloc(tmpsublen + 1); // copy prefix - size_t prefixlen = (size_t)(p - newsub); // not including ~ memmove(tmpsub, newsub, prefixlen); // interpret tilde - memmove(tmpsub + prefixlen, reg_prev_sub, prevsublen); + memmove(tmpsub + prefixlen, reg_prev_sub, reg_prev_sublen); // copy postfix - if (!magic) { - p++; // back off backslash - } - STRCPY(tmpsub + prefixlen + prevsublen, p + 1); + STRCPY(tmpsub + prefixlen + reg_prev_sublen, postfix); if (newsub != source) { // allocated newsub before xfree(newsub); } newsub = tmpsub; - p = newsub + prefixlen + prevsublen; - } else if (magic) { - STRMOVE(p, p + 1); // remove '~' + newsublen = tmpsublen; + p = newsub + prefixlen + reg_prev_sublen; } else { - STRMOVE(p, p + 2); // remove '\~' + memmove(p, postfix, postfixlen + 1); // remove the tilde (+1 for the NUL) } p--; } else { @@ -1792,32 +1912,31 @@ char *regtilde(char *source, int magic, bool preview) } } + if (error) { + if (newsub != source) { + xfree(newsub); + } + return source; + } + // Only change reg_prev_sub when not previewing. if (!preview) { // Store a copy of newsub in reg_prev_sub. It is always allocated, // because recursive calls may make the returned string invalid. - xfree(reg_prev_sub); - reg_prev_sub = xstrdup(newsub); + // Only store it if there something to store. + newsublen = (size_t)(p - newsub); + if (newsublen == 0) { + XFREE_CLEAR(reg_prev_sub); + } else { + xfree(reg_prev_sub); + reg_prev_sub = xstrnsave(newsub, newsublen); + } + reg_prev_sublen = newsublen; } return newsub; } -static bool can_f_submatch = false; // true when submatch() can be used - -// These pointers are used for reg_submatch(). Needed for when the -// substitution string is an expression that contains a call to substitute() -// and submatch(). -typedef struct { - regmatch_T *sm_match; - regmmatch_T *sm_mmatch; - linenr_T sm_firstlnum; - linenr_T sm_maxline; - int sm_line_lbr; -} regsubmatch_T; - -static regsubmatch_T rsm; // can only be used when can_f_submatch is true - /// Put the submatches in "argv[argskip]" which is a list passed into /// call_func() by vim_regsub_both(). static int fill_submatch_list(int argc FUNC_ATTR_UNUSED, typval_T *argv, int argskip, ufunc_T *fp) @@ -1979,11 +2098,13 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen // "flags & REGSUB_COPY" == 0 to the call with // "flags & REGSUB_COPY" != 0. if (copy) { - size_t reslen = eval_result[nested] != NULL ? strlen(eval_result[nested]) : 0; - if (eval_result[nested] != NULL && reslen < (size_t)destlen) { - STRCPY(dest, eval_result[nested]); - dst += reslen; - XFREE_CLEAR(eval_result[nested]); + if (eval_result[nested] != NULL) { + size_t eval_len = strlen(eval_result[nested]); + if (eval_len < (size_t)destlen) { + STRCPY(dest, eval_result[nested]); + dst += eval_len; + XFREE_CLEAR(eval_result[nested]); + } } } else { const bool prev_can_f_submatch = can_f_submatch; @@ -2218,7 +2339,7 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen len = rex.reg_mmatch->endpos[no].col - rex.reg_mmatch->startpos[no].col; } else { - len = (int)strlen(s); + len = reg_getline_len(clnum) - rex.reg_mmatch->startpos[no].col; } } } else { @@ -2248,7 +2369,7 @@ static int vim_regsub_both(char *source, typval_T *expr, char *dest, int destlen if (rex.reg_mmatch->endpos[no].lnum == clnum) { len = rex.reg_mmatch->endpos[no].col; } else { - len = (int)strlen(s); + len = reg_getline_len(clnum); } } else { break; @@ -2325,23 +2446,18 @@ exit: return (int)((dst - dest) + 1); } -/// Call reg_getline() with the line numbers from the submatch. If a -/// substitute() was used the reg_maxline and other values have been -/// overwritten. static char *reg_getline_submatch(linenr_T lnum) { - char *s; - linenr_T save_first = rex.reg_firstlnum; - linenr_T save_max = rex.reg_maxline; - - rex.reg_firstlnum = rsm.sm_firstlnum; - rex.reg_maxline = rsm.sm_maxline; - - s = reg_getline(lnum); + char *line; + reg_getline_common(lnum, RGLF_LINE | RGLF_SUBMATCH, &line, NULL); + return line; +} - rex.reg_firstlnum = save_first; - rex.reg_maxline = save_max; - return s; +static colnr_T reg_getline_submatch_len(linenr_T lnum) +{ + colnr_T length; + reg_getline_common(lnum, RGLF_LENGTH | RGLF_SUBMATCH, NULL, &length); + return length; } /// Used for the submatch() function: get the string from the n'th submatch in @@ -2379,13 +2495,13 @@ char *reg_submatch(int no) // Within one line: take form start to end col. len = rsm.sm_mmatch->endpos[no].col - rsm.sm_mmatch->startpos[no].col; if (round == 2) { - xstrlcpy(retval, s, (size_t)len + 1); + xmemcpyz(retval, s, (size_t)len); } len++; } else { // Multiple lines: take start line from start col, middle // lines completely and end line up to end col. - len = (ssize_t)strlen(s); + len = reg_getline_submatch_len(lnum) - rsm.sm_mmatch->startpos[no].col; if (round == 2) { STRCPY(retval, s); retval[len] = '\n'; @@ -2393,15 +2509,16 @@ char *reg_submatch(int no) len++; lnum++; while (lnum < rsm.sm_mmatch->endpos[no].lnum) { - s = reg_getline_submatch(lnum++); + s = reg_getline_submatch(lnum); if (round == 2) { STRCPY(retval + len, s); } - len += (ssize_t)strlen(s); + len += reg_getline_submatch_len(lnum); if (round == 2) { retval[len] = '\n'; } len++; + lnum++; } if (round == 2) { strncpy(retval + len, // NOLINT(runtime/printf) @@ -2463,8 +2580,9 @@ list_T *reg_submatch_list(int no) if (slnum == elnum) { tv_list_append_string(list, s, ecol - scol); } else { + int max_lnum = elnum - slnum; tv_list_append_string(list, s, -1); - for (int i = 1; i < elnum - slnum; i++) { + for (int i = 1; i < max_lnum; i++) { s = reg_getline_submatch(slnum + i); tv_list_append_string(list, s, -1); } @@ -4494,7 +4612,7 @@ static uint8_t *regatom(int *flagp) n = n * 10 + (uint32_t)(c - '0'); c = getchr(); } - if (c == '\'' && n == 0) { + if (no_Magic(c) == '\'' && n == 0) { // "\%'m", "\%<'m" and "\%>'m": Mark c = getchr(); ret = regnode(RE_MARK); @@ -5320,7 +5438,7 @@ static regprog_T *bt_regcomp(uint8_t *expr, int re_flags) } // Remember whether this pattern has any \z specials in it. r->reghasz = (uint8_t)re_has_z; - scan = r->program + 1; // First BRANCH. + scan = &r->program[1]; // First BRANCH. if (OP(regnext(scan)) == END) { // Only one top-level choice. scan = OPERAND(scan); @@ -5357,9 +5475,12 @@ static regprog_T *bt_regcomp(uint8_t *expr, int re_flags) longest = NULL; len = 0; for (; scan != NULL; scan = regnext(scan)) { - if (OP(scan) == EXACTLY && strlen((char *)OPERAND(scan)) >= (size_t)len) { - longest = OPERAND(scan); - len = (int)strlen((char *)OPERAND(scan)); + if (OP(scan) == EXACTLY) { + size_t scanlen = strlen((char *)OPERAND(scan)); + if (scanlen >= (size_t)len) { + longest = OPERAND(scan); + len = (int)scanlen; + } } } r->regmust = longest; @@ -6091,7 +6212,7 @@ static bool regmatch(uint8_t *scan, const proftime_T *tm, int *timed_out) pos = &fm->mark; const colnr_T pos_col = pos->lnum == rex.lnum + rex.reg_firstlnum && pos->col == MAXCOL - ? (colnr_T)strlen(reg_getline(pos->lnum - rex.reg_firstlnum)) + ? reg_getline_len(pos->lnum - rex.reg_firstlnum) : pos->col; if (pos->lnum == rex.lnum + rex.reg_firstlnum @@ -7237,7 +7358,7 @@ static bool regmatch(uint8_t *scan, const proftime_T *tm, int *timed_out) if (rex.line == NULL) { break; } - rex.input = rex.line + strlen((char *)rex.line); + rex.input = rex.line + reg_getline_len(rex.lnum); reg_breakcheck(); } else { MB_PTR_BACK(rex.line, rex.input); @@ -7322,7 +7443,7 @@ static int regtry(bt_regprog_T *prog, colnr_T col, proftime_T *tm, int *timed_ou // Clear the external match subpointers if necessaey. rex.need_clear_zsubexpr = (prog->reghasz == REX_SET); - if (regmatch(prog->program + 1, tm, timed_out) == 0) { + if (regmatch(&prog->program[1], tm, timed_out) == 0) { return 0; } @@ -7664,7 +7785,7 @@ static void regdump(uint8_t *pattern, bt_regprog_T *r) fprintf(f, "-------------------------------------\n\r\nregcomp(%s):\r\n", pattern); - s = r->program + 1; + s = &r->program[1]; // Loop until we find the END that isn't before a referred next (an END // can also appear in a NOMATCH operand). while (op != END || s <= end) { @@ -7735,8 +7856,10 @@ static uint8_t *regprop(uint8_t *op) { char *p; static char buf[50]; + static size_t buflen = 0; STRCPY(buf, ":"); + buflen = 1; switch ((int)OP(op)) { case BOL: @@ -7976,7 +8099,8 @@ static uint8_t *regprop(uint8_t *op) case MOPEN + 7: case MOPEN + 8: case MOPEN + 9: - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "MOPEN%d", OP(op) - MOPEN); + buflen += (size_t)snprintf(buf + buflen, sizeof(buf) - buflen, + "MOPEN%d", OP(op) - MOPEN); p = NULL; break; case MCLOSE + 0: @@ -7991,7 +8115,8 @@ static uint8_t *regprop(uint8_t *op) case MCLOSE + 7: case MCLOSE + 8: case MCLOSE + 9: - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "MCLOSE%d", OP(op) - MCLOSE); + buflen += (size_t)snprintf(buf + buflen, sizeof(buf) - buflen, + "MCLOSE%d", OP(op) - MCLOSE); p = NULL; break; case BACKREF + 1: @@ -8003,7 +8128,8 @@ static uint8_t *regprop(uint8_t *op) case BACKREF + 7: case BACKREF + 8: case BACKREF + 9: - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "BACKREF%d", OP(op) - BACKREF); + buflen += (size_t)snprintf(buf + buflen, sizeof(buf) - buflen, + "BACKREF%d", OP(op) - BACKREF); p = NULL; break; case NOPEN: @@ -8021,7 +8147,8 @@ static uint8_t *regprop(uint8_t *op) case ZOPEN + 7: case ZOPEN + 8: case ZOPEN + 9: - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ZOPEN%d", OP(op) - ZOPEN); + buflen += (size_t)snprintf(buf + buflen, sizeof(buf) - buflen, + "ZOPEN%d", OP(op) - ZOPEN); p = NULL; break; case ZCLOSE + 1: @@ -8033,7 +8160,8 @@ static uint8_t *regprop(uint8_t *op) case ZCLOSE + 7: case ZCLOSE + 8: case ZCLOSE + 9: - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ZCLOSE%d", OP(op) - ZCLOSE); + buflen += (size_t)snprintf(buf + buflen, sizeof(buf) - buflen, + "ZCLOSE%d", OP(op) - ZCLOSE); p = NULL; break; case ZREF + 1: @@ -8045,7 +8173,8 @@ static uint8_t *regprop(uint8_t *op) case ZREF + 7: case ZREF + 8: case ZREF + 9: - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "ZREF%d", OP(op) - ZREF); + buflen += (size_t)snprintf(buf + buflen, sizeof(buf) - buflen, + "ZREF%d", OP(op) - ZREF); p = NULL; break; case STAR: @@ -8085,8 +8214,8 @@ static uint8_t *regprop(uint8_t *op) case BRACE_COMPLEX + 7: case BRACE_COMPLEX + 8: case BRACE_COMPLEX + 9: - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "BRACE_COMPLEX%d", - OP(op) - BRACE_COMPLEX); + buflen += (size_t)snprintf(buf + buflen, sizeof(buf) - buflen, + "BRACE_COMPLEX%d", OP(op) - BRACE_COMPLEX); p = NULL; break; case MULTIBYTECODE: @@ -8096,12 +8225,13 @@ static uint8_t *regprop(uint8_t *op) p = "NEWL"; break; default: - snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf), "corrupt %d", OP(op)); + buflen += (size_t)snprintf(buf + buflen, sizeof(buf) - buflen, + "corrupt %d", OP(op)); p = NULL; break; } if (p != NULL) { - STRCAT(buf, p); + STRCPY(buf + buflen, p); } return (uint8_t *)buf; } @@ -10218,7 +10348,7 @@ static int nfa_regatom(void) } EMIT((int)n); break; - } else if (c == '\'' && n == 0) { + } else if (no_Magic(c) == '\'' && n == 0) { // \%'m \%<'m \%>'m EMIT(cmp == '<' ? NFA_MARK_LT : cmp == '>' ? NFA_MARK_GT : NFA_MARK); @@ -10555,7 +10685,7 @@ nfa_do_multibyte: // NFA_END_COMPOSING is the ). Note that right now we are // building the postfix form, not the NFA itself; // a composing char could be: a, b, c, NFA_COMPOSING - // where 'b' and 'c' are chars with codes > 256. */ + // where 'b' and 'c' are chars with codes > 256. while (true) { EMIT(c); if (i > 0) { @@ -13599,7 +13729,7 @@ static int recursive_regmatch(nfa_state_T *state, nfa_pim_T *pim, nfa_regprog_T rex.line = (uint8_t *)reg_getline(++rex.lnum); rex.input = rex.line; } else { - rex.input = rex.line + strlen((char *)rex.line); + rex.input = rex.line + reg_getline_len(rex.lnum); } } if ((int)(rex.input - rex.line) >= state->val) { @@ -13845,21 +13975,18 @@ static int skip_to_start(int c, colnr_T *colp) // Returns zero for no match, 1 for a match. static int find_match_text(colnr_T *startcol, int regstart, uint8_t *match_text) { -#define PTR2LEN(x) utf_ptr2len(x) - colnr_T col = *startcol; - int regstart_len = PTR2LEN((char *)rex.line + col); + const int regstart_len = utf_ptr2len((char *)rex.line + col); while (true) { bool match = true; 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_len = utf_ptr2len((char *)s1); int c1 = utf_ptr2char((char *)s1); - int c2_len = PTR2LEN((char *)s2); + int c2_len = utf_ptr2len((char *)s2); int c2 = utf_ptr2char((char *)s2); - if ((c1 != c2 && (!rex.reg_ic || utf_fold(c1) != utf_fold(c2))) || c1_len != c2_len) { match = false; @@ -13894,8 +14021,6 @@ static int find_match_text(colnr_T *startcol, int regstart, uint8_t *match_text) *startcol = col; return 0L; - -#undef PTR2LEN } static int nfa_did_time_out(void) @@ -15002,7 +15127,7 @@ static int nfa_regmatch(nfa_regprog_T *prog, nfa_state_T *start, regsubs_T *subm pos_T *pos = &fm->mark; const colnr_T pos_col = pos->lnum == rex.lnum + rex.reg_firstlnum && pos->col == MAXCOL - ? (colnr_T)strlen(reg_getline(pos->lnum - rex.reg_firstlnum)) + ? reg_getline_len(pos->lnum - rex.reg_firstlnum) : pos->col; result = pos->lnum == rex.lnum + rex.reg_firstlnum diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 76188499e3..d913d311db 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -69,7 +69,7 @@ /// It is shared between do_source() and getsourceline(). /// This is required, because it needs to be handed to do_cmdline() and /// sourcing can be done recursively. -struct source_cookie { +typedef struct { FILE *fp; ///< opened file for sourcing char *nextline; ///< if not NULL: line that was read ahead linenr_T sourcing_lnum; ///< line number of the source file @@ -83,7 +83,7 @@ struct source_cookie { int dbg_tick; ///< debug_tick when breakpoint was set int level; ///< top nesting level of sourced file vimconv_T conv; ///< type of conversion -}; +} source_cookie_T; typedef struct { char *path; @@ -1628,14 +1628,14 @@ static inline char *add_dir(char *dest, const char *const dir, const size_t dir_ const char *appname = get_appname(); size_t appname_len = strlen(appname); assert(appname_len < (IOSIZE - sizeof("-data"))); - xstrlcpy(IObuff, appname, appname_len + 1); + xmemcpyz(IObuff, appname, appname_len); #if defined(MSWIN) if (type == kXDGDataHome || type == kXDGStateHome) { xstrlcat(IObuff, "-data", IOSIZE); appname_len += 5; } #endif - xstrlcpy(dest, IObuff, appname_len + 1); + xmemcpyz(dest, IObuff, appname_len); dest += appname_len; if (suf1 != NULL) { *dest++ = PATHSEP; @@ -1822,20 +1822,20 @@ void ex_options(exarg_T *eap) /// @return address holding the next breakpoint line for a source cookie linenr_T *source_breakpoint(void *cookie) { - return &((struct source_cookie *)cookie)->breakpoint; + return &((source_cookie_T *)cookie)->breakpoint; } /// @return the address holding the debug tick for a source cookie. int *source_dbg_tick(void *cookie) { - return &((struct source_cookie *)cookie)->dbg_tick; + return &((source_cookie_T *)cookie)->dbg_tick; } /// @return the nesting level for a source cookie. int source_level(void *cookie) FUNC_ATTR_PURE { - return ((struct source_cookie *)cookie)->level; + return ((source_cookie_T *)cookie)->level; } /// Special function to open a file without handle inheritance. @@ -1889,11 +1889,6 @@ static bool concat_continued_line(garray_T *const ga, const int init_growsize, c } typedef struct { - linenr_T curr_lnum; - const linenr_T final_lnum; -} GetBufferLineCookie; - -typedef struct { char *buf; size_t offset; } GetStrLineCookie; @@ -2009,15 +2004,15 @@ void cmd_source_buffer(const exarg_T *const eap, bool ex_lua) ga_append(&ga, NL); } ((char *)ga.ga_data)[ga.ga_len - 1] = NUL; - const GetStrLineCookie cookie = { - .buf = ga.ga_data, - .offset = 0, - }; if (ex_lua || strequal(curbuf->b_p_ft, "lua") || (curbuf->b_fname && path_with_extension(curbuf->b_fname, "lua"))) { char *name = ex_lua ? ":{range}lua" : ":source (no file)"; - nlua_source_using_linegetter(get_str_line, (void *)&cookie, name); + nlua_source_str(ga.ga_data, name); } else { + const GetStrLineCookie cookie = { + .buf = ga.ga_data, + .offset = 0, + }; source_using_linegetter((void *)&cookie, get_str_line, ":source (no file)"); } ga_clear(&ga); @@ -2052,7 +2047,7 @@ int do_source_str(const char *cmd, const char *traceback_name) /// If a scriptitem_T was found or created "*ret_sid" is set to the SID. int do_source(char *fname, int check_other, int is_vimrc, int *ret_sid) { - struct source_cookie cookie; + source_cookie_T cookie; uint8_t *firstline = NULL; int retval = FAIL; int save_debug_break_level = debug_break_level; @@ -2392,7 +2387,7 @@ char *get_scriptname(LastSet last_set, bool *should_free) case SID_WINLAYOUT: return _("changed window size"); case SID_LUA: - return _("Lua"); + return _("Lua (run Nvim with -V1 for more details)"); case SID_API_CLIENT: snprintf(IObuff, IOSIZE, _("API client (channel id %" PRIu64 ")"), last_set.channel_id); return IObuff; @@ -2440,7 +2435,7 @@ linenr_T get_sourced_lnum(LineGetter fgetline, void *cookie) FUNC_ATTR_PURE { return fgetline == getsourceline - ? ((struct source_cookie *)cookie)->sourcing_lnum + ? ((source_cookie_T *)cookie)->sourcing_lnum : SOURCING_LNUM; } @@ -2546,7 +2541,7 @@ void f_getscriptinfo(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) /// some error. char *getsourceline(int c, void *cookie, int indent, bool do_concat) { - struct source_cookie *sp = (struct source_cookie *)cookie; + source_cookie_T *sp = (source_cookie_T *)cookie; char *line; // If breakpoints have been added/deleted need to check for it. @@ -2560,8 +2555,8 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) // Set the current sourcing line number. SOURCING_LNUM = sp->sourcing_lnum + 1; // Get current line. If there is a read-ahead line, use it, otherwise get - // one now. - if (sp->finished) { + // one now. "fp" is NULL if actually using a string. + if (sp->finished || sp->fp == NULL) { line = NULL; } else if (sp->nextline == NULL) { line = get_one_sourceline(sp); @@ -2624,7 +2619,7 @@ char *getsourceline(int c, void *cookie, int indent, bool do_concat) return line; } -static char *get_one_sourceline(struct source_cookie *sp) +static char *get_one_sourceline(source_cookie_T *sp) { garray_T ga; int len; @@ -2730,10 +2725,10 @@ retry: /// Without the multi-byte feature it's simply ignored. void ex_scriptencoding(exarg_T *eap) { - struct source_cookie *sp; + source_cookie_T *sp; char *name; - if (!getline_equal(eap->getline, eap->cookie, getsourceline)) { + if (!getline_equal(eap->ea_getline, eap->cookie, getsourceline)) { emsg(_("E167: :scriptencoding used outside of a sourced file")); return; } @@ -2745,7 +2740,7 @@ void ex_scriptencoding(exarg_T *eap) } // Setup for conversion from the specified encoding to 'encoding'. - sp = (struct source_cookie *)getline_cookie(eap->getline, eap->cookie); + sp = (source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie); convert_setup(&sp->conv, name, p_enc); if (name != eap->arg) { @@ -2756,7 +2751,7 @@ void ex_scriptencoding(exarg_T *eap) /// ":finish": Mark a sourced file as finished. void ex_finish(exarg_T *eap) { - if (getline_equal(eap->getline, eap->cookie, getsourceline)) { + if (getline_equal(eap->ea_getline, eap->cookie, getsourceline)) { do_finish(eap, false); } else { emsg(_("E168: :finish used outside of a sourced file")); @@ -2769,8 +2764,7 @@ void ex_finish(exarg_T *eap) void do_finish(exarg_T *eap, bool reanimate) { if (reanimate) { - ((struct source_cookie *)getline_cookie(eap->getline, - eap->cookie))->finished = false; + ((source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie))->finished = false; } // Cleanup (and deactivate) conditionals, but stop when a try conditional @@ -2782,8 +2776,7 @@ void do_finish(exarg_T *eap, bool reanimate) eap->cstack->cs_pending[idx] = CSTP_FINISH; report_make_pending(CSTP_FINISH, NULL); } else { - ((struct source_cookie *)getline_cookie(eap->getline, - eap->cookie))->finished = true; + ((source_cookie_T *)getline_cookie(eap->ea_getline, eap->cookie))->finished = true; } } @@ -2793,7 +2786,7 @@ void do_finish(exarg_T *eap, bool reanimate) bool source_finished(LineGetter fgetline, void *cookie) { return getline_equal(fgetline, cookie, getsourceline) - && ((struct source_cookie *)getline_cookie(fgetline, cookie))->finished; + && ((source_cookie_T *)getline_cookie(fgetline, cookie))->finished; } /// Return the autoload script name for a function or variable name diff --git a/src/nvim/search.c b/src/nvim/search.c index 48e41c290d..746c253708 100644 --- a/src/nvim/search.c +++ b/src/nvim/search.c @@ -99,9 +99,9 @@ static const char e_search_hit_bottom_without_match_for_str[] static SearchPattern spats[2] = { // Last used search pattern - [0] = { NULL, true, false, 0, { '/', false, false, 0 }, NULL }, + [0] = { NULL, 0, true, false, 0, { '/', false, false, 0 }, NULL }, // Last used substitute pattern - [1] = { NULL, true, false, 0, { '/', false, false, 0 }, NULL } + [1] = { NULL, 0, true, false, 0, { '/', false, false, 0 }, NULL } }; static int last_idx = 0; // index in spats[] for RE_LAST @@ -113,13 +113,15 @@ static char lastc_bytes[MB_MAXBYTES + 1]; static int lastc_bytelen = 1; // >1 for multi-byte char // copy of spats[], for keeping the search patterns while executing autocmds -static SearchPattern saved_spats[2]; +static SearchPattern saved_spats[ARRAY_SIZE(spats)]; static char *saved_mr_pattern = NULL; +static size_t saved_mr_patternlen = 0; static int saved_spats_last_idx = 0; static bool saved_spats_no_hlsearch = false; // allocated copy of pattern used by search_regcomp() static char *mr_pattern = NULL; +static size_t mr_patternlen = 0; // Type used by find_pattern_in_path() to remember which included files have // been searched already. @@ -144,8 +146,8 @@ typedef struct { /// @param regmatch return: pattern and ignore-case flag /// /// @return FAIL if failed, OK otherwise. -int search_regcomp(char *pat, char **used_pat, int pat_save, int pat_use, int options, - regmmatch_T *regmatch) +int search_regcomp(char *pat, size_t patlen, char **used_pat, int pat_save, int pat_use, + int options, regmmatch_T *regmatch) { rc_did_emsg = false; int magic = magic_isset(); @@ -168,10 +170,11 @@ int search_regcomp(char *pat, char **used_pat, int pat_save, int pat_use, int op return FAIL; } pat = spats[i].pat; + patlen = spats[i].patlen; magic = spats[i].magic; no_smartcase = spats[i].no_scs; } else if (options & SEARCH_HIS) { // put new pattern in history - add_to_history(HIST_SEARCH, pat, true, NUL); + add_to_history(HIST_SEARCH, pat, patlen, true, NUL); } if (used_pat) { @@ -182,19 +185,20 @@ int search_regcomp(char *pat, char **used_pat, int pat_save, int pat_use, int op if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { mr_pattern = reverse_text(pat); } else { - mr_pattern = xstrdup(pat); + mr_pattern = xstrnsave(pat, patlen); } + mr_patternlen = patlen; // Save the currently used pattern in the appropriate place, // unless the pattern should not be remembered. if (!(options & SEARCH_KEEP) && (cmdmod.cmod_flags & CMOD_KEEPPATTERNS) == 0) { // search or global command if (pat_save == RE_SEARCH || pat_save == RE_BOTH) { - save_re_pat(RE_SEARCH, pat, magic); + save_re_pat(RE_SEARCH, pat, patlen, magic); } // substitute or global command if (pat_save == RE_SUBST || pat_save == RE_BOTH) { - save_re_pat(RE_SUBST, pat, magic); + save_re_pat(RE_SUBST, pat, patlen, magic); } } @@ -213,14 +217,15 @@ char *get_search_pat(void) return mr_pattern; } -void save_re_pat(int idx, char *pat, int magic) +void save_re_pat(int idx, char *pat, size_t patlen, int magic) { if (spats[idx].pat == pat) { return; } free_spat(&spats[idx]); - spats[idx].pat = xstrdup(pat); + spats[idx].pat = xstrnsave(pat, patlen); + spats[idx].patlen = patlen; spats[idx].magic = magic; spats[idx].no_scs = no_smartcase; spats[idx].timestamp = os_time(); @@ -243,18 +248,19 @@ void save_search_patterns(void) 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); + for (size_t i = 0; i < ARRAY_SIZE(spats); i++) { + saved_spats[i] = spats[i]; + if (spats[i].pat != NULL) { + saved_spats[i].pat = xstrnsave(spats[i].pat, spats[i].patlen); + saved_spats[i].patlen = spats[i].patlen; + } } if (mr_pattern == NULL) { saved_mr_pattern = NULL; + saved_mr_patternlen = 0; } else { - saved_mr_pattern = xstrdup(mr_pattern); + saved_mr_pattern = xstrnsave(mr_pattern, mr_patternlen); + saved_mr_patternlen = mr_patternlen; } saved_spats_last_idx = last_idx; saved_spats_no_hlsearch = no_hlsearch; @@ -266,13 +272,14 @@ void restore_search_patterns(void) return; } - free_spat(&spats[0]); - spats[0] = saved_spats[0]; + for (size_t i = 0; i < ARRAY_SIZE(spats); i++) { + free_spat(&spats[i]); + spats[i] = saved_spats[i]; + } set_vv_searchforward(); - free_spat(&spats[1]); - spats[1] = saved_spats[1]; xfree(mr_pattern); mr_pattern = saved_mr_pattern; + mr_patternlen = saved_mr_patternlen; last_idx = saved_spats_last_idx; set_no_hlsearch(saved_spats_no_hlsearch); } @@ -286,12 +293,13 @@ static inline void free_spat(SearchPattern *const spat) #if defined(EXITFREE) void free_search_patterns(void) { - free_spat(&spats[0]); - free_spat(&spats[1]); - + for (size_t i = 0; i < ARRAY_SIZE(spats); i++) { + free_spat(&spats[i]); + } CLEAR_FIELD(spats); XFREE_CLEAR(mr_pattern); + mr_patternlen = 0; } #endif @@ -320,7 +328,8 @@ void save_last_search_pattern(void) saved_last_search_spat = spats[RE_SEARCH]; if (spats[RE_SEARCH].pat != NULL) { - saved_last_search_spat.pat = xstrdup(spats[RE_SEARCH].pat); + saved_last_search_spat.pat = xstrnsave(spats[RE_SEARCH].pat, spats[RE_SEARCH].patlen); + saved_last_search_spat.patlen = spats[RE_SEARCH].patlen; } saved_last_idx = last_idx; saved_no_hlsearch = no_hlsearch; @@ -341,6 +350,7 @@ void restore_last_search_pattern(void) xfree(spats[RE_SEARCH].pat); spats[RE_SEARCH] = saved_last_search_spat; saved_last_search_spat.pat = NULL; + saved_last_search_spat.patlen = 0; set_vv_searchforward(); last_idx = saved_last_idx; set_no_hlsearch(saved_no_hlsearch); @@ -487,8 +497,10 @@ void set_last_search_pat(const char *s, int idx, int magic, bool setlast) // An empty string means that nothing should be matched. if (*s == NUL) { spats[idx].pat = NULL; + spats[idx].patlen = 0; } else { - spats[idx].pat = xstrdup(s); + spats[idx].patlen = strlen(s); + spats[idx].pat = xstrnsave(s, spats[idx].patlen); } spats[idx].timestamp = os_time(); spats[idx].additional_data = NULL; @@ -507,8 +519,10 @@ void set_last_search_pat(const char *s, int idx, int magic, bool setlast) saved_spats[idx] = spats[0]; if (spats[idx].pat == NULL) { saved_spats[idx].pat = NULL; + saved_spats[idx].patlen = 0; } else { - saved_spats[idx].pat = xstrdup(spats[idx].pat); + saved_spats[idx].pat = xstrnsave(spats[idx].pat, spats[idx].patlen); + saved_spats[idx].patlen = spats[idx].patlen; } saved_spats_last_idx = last_idx; } @@ -528,7 +542,7 @@ void last_pat_prog(regmmatch_T *regmatch) return; } emsg_off++; // So it doesn't beep if bad expr - search_regcomp("", NULL, 0, last_idx, SEARCH_KEEP, regmatch); + search_regcomp("", 0, NULL, 0, last_idx, SEARCH_KEEP, regmatch); emsg_off--; } @@ -556,7 +570,7 @@ void last_pat_prog(regmmatch_T *regmatch) /// 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 *pat, - int count, int options, int pat_use, searchit_arg_T *extra_arg) + size_t patlen, int count, int options, int pat_use, searchit_arg_T *extra_arg) { int found; linenr_T lnum; // no init to shut up Apollo cc @@ -584,7 +598,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, timed_out = &extra_arg->sa_timed_out; } - if (search_regcomp(pat, NULL, RE_SEARCH, pat_use, + if (search_regcomp(pat, patlen, NULL, RE_SEARCH, pat_use, (options & (SEARCH_HIS + SEARCH_KEEP)), ®match) == FAIL) { if ((options & SEARCH_MSG) && !rc_did_emsg) { semsg(_("E383: Invalid search string: %s"), mr_pattern); @@ -592,6 +606,8 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, return FAIL; } + const bool search_from_match_end = vim_strchr(p_cpo, CPO_SEARCH) != NULL; + // find the string do { // loop for count // When not accepting a match at the start position set "extra_col" to a @@ -604,7 +620,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, && pos->col < MAXCOL - 2) { // Watch out for the "col" being MAXCOL - 2, used in a closed fold. ptr = ml_get_buf(buf, pos->lnum); - if ((int)strlen(ptr) <= pos->col) { + if (ml_get_buf_len(buf, pos->lnum) <= pos->col) { start_char_len = 1; } else { start_char_len = utfc_ptr2len(ptr + pos->col); @@ -699,7 +715,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, // If vi-compatible searching, continue at the end // of the match, otherwise continue one position // forward. - if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) { + if (search_from_match_end) { if (nmatched > 1) { // end is in next line, thus no match in // this line @@ -791,7 +807,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, // If vi-compatible searching, continue at the end // of the match, otherwise continue one position // forward. - if (vim_strchr(p_cpo, CPO_SEARCH) != NULL) { + if (search_from_match_end) { if (nmatched > 1) { break; } @@ -851,7 +867,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, if (endpos.col == 0) { if (pos->lnum > 1) { // just in case pos->lnum--; - pos->col = (colnr_T)strlen(ml_get_buf(buf, pos->lnum)); + pos->col = ml_get_buf_len(buf, pos->lnum); } } else { pos->col--; @@ -969,7 +985,7 @@ int searchit(win_T *win, buf_T *buf, pos_T *pos, pos_T *end_pos, Direction dir, // A pattern like "\n\zs" may go past the last line. if (pos->lnum > buf->b_ml.ml_line_count) { pos->lnum = buf->b_ml.ml_line_count; - pos->col = (int)strlen(ml_get_buf(buf, pos->lnum)); + pos->col = ml_get_buf_len(buf, pos->lnum); if (pos->col > 0) { pos->col--; } @@ -1031,11 +1047,12 @@ static int first_submatch(regmmatch_T *rp) /// @param sia optional arguments or NULL /// /// @return 0 for failure, 1 for found, 2 for found and line offset added. -int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, int options, - searchit_arg_T *sia) +int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, size_t patlen, int count, + int options, searchit_arg_T *sia) { pos_T pos; // position of the last match char *searchstr; + size_t searchstrlen; int retval; // Return value char *p; int64_t c; @@ -1043,9 +1060,11 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in char *strcopy = NULL; char *ps; char *msgbuf = NULL; - size_t len; + size_t msgbuflen = 0; bool has_offset = false; + searchcmdlen = 0; + // A line offset is not remembered, this is vi compatible. if (spats[0].off.line && vim_strchr(p_cpo, CPO_LINEOFF) != NULL) { spats[0].off.line = false; @@ -1076,11 +1095,11 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in // If the cursor is in a closed fold, don't find another match in the same // fold. if (dirc == '/') { - if (hasFolding(pos.lnum, NULL, &pos.lnum)) { + if (hasFolding(curwin, pos.lnum, NULL, &pos.lnum)) { pos.col = MAXCOL - 2; // avoid overflow when adding 1 } } else { - if (hasFolding(pos.lnum, &pos.lnum, NULL)) { + if (hasFolding(curwin, pos.lnum, &pos.lnum, NULL)) { pos.col = 0; } } @@ -1096,19 +1115,23 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in bool show_top_bot_msg = false; searchstr = pat; + searchstrlen = patlen; + dircp = NULL; // use previous pattern if (pat == NULL || *pat == NUL || *pat == search_delim) { if (spats[RE_SEARCH].pat == NULL) { // no previous pattern - searchstr = spats[RE_SUBST].pat; - if (searchstr == NULL) { + if (spats[RE_SUBST].pat == NULL) { emsg(_(e_noprevre)); retval = 0; goto end_do_search; } + searchstr = spats[RE_SUBST].pat; + searchstrlen = spats[RE_SUBST].patlen; } else { // make search_regcomp() use spats[RE_SEARCH].pat searchstr = ""; + searchstrlen = 0; } } @@ -1118,12 +1141,16 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in ps = strcopy; p = skip_regexp_ex(pat, search_delim, magic_isset(), &strcopy, NULL, NULL); if (strcopy != ps) { + size_t len = strlen(strcopy); // made a copy of "pat" to change "\?" to "?" - searchcmdlen += (int)(strlen(pat) - strlen(strcopy)); + searchcmdlen += (int)(patlen - len); pat = strcopy; + patlen = len; searchstr = strcopy; + searchstrlen = len; } if (*p == search_delim) { + searchstrlen = (size_t)(p - pat); dircp = p; // remember where we put the NUL *p++ = NUL; } @@ -1161,12 +1188,13 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in // compute length of search command for get_address() searchcmdlen += (int)(p - pat); + patlen -= (size_t)(p - pat); pat = p; // put pat after search command } + bool show_search_stats = false; if ((options & SEARCH_ECHO) && messaging() && !msg_silent && (!cmd_silent || !shortmess(SHM_SEARCHCOUNT))) { - char *trunc; char off_buf[40]; size_t off_len = 0; @@ -1176,56 +1204,59 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in // Get the offset, so we know how long it is. if (!cmd_silent && (spats[0].off.line || spats[0].off.end || spats[0].off.off)) { - p = off_buf; - *p++ = (char)dirc; + off_buf[off_len++] = (char)dirc; if (spats[0].off.end) { - *p++ = 'e'; + off_buf[off_len++] = 'e'; } else if (!spats[0].off.line) { - *p++ = 's'; + off_buf[off_len++] = 's'; } if (spats[0].off.off > 0 || spats[0].off.line) { - *p++ = '+'; + off_buf[off_len++] = '+'; } - *p = NUL; + off_buf[off_len] = NUL; if (spats[0].off.off != 0 || spats[0].off.line) { - snprintf(p, sizeof(off_buf) - 1 - (size_t)(p - off_buf), - "%" PRId64, spats[0].off.off); + off_len += (size_t)snprintf(off_buf + off_len, sizeof(off_buf) - off_len, + "%" PRId64, spats[0].off.off); } - off_len = strlen(off_buf); } + size_t plen; if (*searchstr == NUL) { p = spats[0].pat; + plen = spats[0].patlen; } else { p = searchstr; + plen = searchstrlen; } + size_t msgbufsize; if (!shortmess(SHM_SEARCHCOUNT) || cmd_silent) { // Reserve enough space for the search pattern + offset + // search stat. Use all the space available, so that the // search state is right aligned. If there is not enough space // msg_strtrunc() will shorten in the middle. if (ui_has(kUIMessages)) { - len = 0; // adjusted below + msgbufsize = 0; // adjusted below } else if (msg_scrolled != 0 && !cmd_silent) { // Use all the columns. - len = (size_t)((Rows - msg_row) * Columns - 1); + msgbufsize = (size_t)((Rows - msg_row) * Columns - 1); } else { // Use up to 'showcmd' column. - len = (size_t)((Rows - msg_row - 1) * Columns + sc_col - 1); + msgbufsize = (size_t)((Rows - msg_row - 1) * Columns + sc_col - 1); } - if (len < strlen(p) + off_len + SEARCH_STAT_BUF_LEN + 3) { - len = strlen(p) + off_len + SEARCH_STAT_BUF_LEN + 3; + if (msgbufsize < plen + off_len + SEARCH_STAT_BUF_LEN + 3) { + msgbufsize = plen + off_len + SEARCH_STAT_BUF_LEN + 3; } } else { // Reserve enough space for the search pattern + offset. - len = strlen(p) + off_len + 3; + msgbufsize = plen + off_len + 3; } xfree(msgbuf); - msgbuf = xmalloc(len); - memset(msgbuf, ' ', len); - msgbuf[len - 1] = NUL; + msgbuf = xmalloc(msgbufsize); + memset(msgbuf, ' ', msgbufsize); + msgbuflen = msgbufsize - 1; + msgbuf[msgbuflen] = NUL; // do not fill the msgbuf buffer, if cmd_silent is set, leave it // empty for the search_stat feature. @@ -1234,18 +1265,19 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in if (utf_iscomposing(utf_ptr2char(p))) { // Use a space to draw the composing char on. msgbuf[1] = ' '; - memmove(msgbuf + 2, p, strlen(p)); + memmove(msgbuf + 2, p, plen); } else { - memmove(msgbuf + 1, p, strlen(p)); + memmove(msgbuf + 1, p, plen); } if (off_len > 0) { - memmove(msgbuf + strlen(p) + 1, off_buf, off_len); + memmove(msgbuf + plen + 1, off_buf, off_len); } - trunc = msg_strtrunc(msgbuf, true); + char *trunc = msg_strtrunc(msgbuf, true); if (trunc != NULL) { xfree(msgbuf); msgbuf = trunc; + msgbuflen = strlen(msgbuf); } // The search pattern could be shown on the right in rightleft @@ -1260,7 +1292,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in while (*r == ' ') { r++; } - size_t pat_len = (size_t)(msgbuf + strlen(msgbuf) - r); + size_t pat_len = (size_t)(msgbuf + msgbuflen - r); memmove(msgbuf, r, pat_len); // overwrite old text if ((size_t)(r - msgbuf) >= pat_len) { @@ -1277,6 +1309,10 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in ui_flush(); msg_nowait = true; // don't wait for this message } + + if (!shortmess(SHM_SEARCHCOUNT)) { + show_search_stats = true; + } } // If there is a character offset, subtract it from the current @@ -1309,7 +1345,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in } c = searchit(curwin, curbuf, &pos, NULL, dirc == '/' ? FORWARD : BACKWARD, - searchstr, count, + searchstr, searchstrlen, count, (spats[0].off.end * SEARCH_END + (options & (SEARCH_KEEP + SEARCH_PEEK + SEARCH_HIS + SEARCH_MSG @@ -1379,17 +1415,12 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in } // Show [1/15] if 'S' is not in 'shortmess'. - if ((options & SEARCH_ECHO) - && messaging() - && !msg_silent - && c != FAIL - && !shortmess(SHM_SEARCHCOUNT) - && msgbuf != NULL) { + if (show_search_stats) { cmdline_search_stat(dirc, &pos, &curwin->w_cursor, - show_top_bot_msg, msgbuf, + show_top_bot_msg, msgbuf, msgbuflen, (count != 1 || has_offset || (!(fdo_flags & FDO_SEARCH) - && hasFolding(curwin->w_cursor.lnum, NULL, + && hasFolding(curwin, curwin->w_cursor.lnum, NULL, NULL))), SEARCH_STAT_DEF_MAX_COUNT, SEARCH_STAT_DEF_TIMEOUT); @@ -1413,6 +1444,7 @@ int do_search(oparg_T *oap, int dirc, int search_delim, char *pat, int count, in goto end_do_search; } pat++; + patlen--; } if (options & SEARCH_MARK) { @@ -1554,7 +1586,7 @@ int searchc(cmdarg_T *cap, bool t_cmd) char *p = get_cursor_line_ptr(); int col = curwin->w_cursor.col; - int len = (int)strlen(p); + int len = get_cursor_line_len(); while (count--) { while (true) { @@ -1958,7 +1990,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } linep = ml_get(pos.lnum); - pos.col = (colnr_T)strlen(linep); // pos.col on trailing NUL + pos.col = ml_get_len(pos.lnum); // pos.col on trailing NUL do_quotes = -1; line_breakcheck(); @@ -2105,7 +2137,7 @@ pos_T *findmatchlimit(oparg_T *oap, int initc, int flags, int64_t maxtravel) } if (pos.lnum > 1) { ptr = ml_get(pos.lnum - 1); - if (*ptr && *(ptr + strlen(ptr) - 1) == '\\') { + if (*ptr && *(ptr + ml_get_len(pos.lnum - 1) - 1) == '\\') { do_quotes = 1; if (start_in_quotes == kNone) { inquote = at_start; @@ -2418,7 +2450,8 @@ int current_search(int count, bool forward) } // Is the pattern is zero-width?, this time, don't care about the direction - int zero_width = is_zero_width(spats[last_idx].pat, true, &curwin->w_cursor, FORWARD); + int zero_width = is_zero_width(spats[last_idx].pat, spats[last_idx].patlen, + true, &curwin->w_cursor, FORWARD); if (zero_width == -1) { return FAIL; // pattern not found } @@ -2451,7 +2484,7 @@ int current_search(int count, bool forward) result = searchit(curwin, curbuf, &pos, &end_pos, (dir ? FORWARD : BACKWARD), - spats[last_idx].pat, i ? count : 1, + spats[last_idx].pat, spats[last_idx].patlen, i ? count : 1, SEARCH_KEEP | flags, RE_SEARCH, NULL); p_ws = old_p_ws; @@ -2460,7 +2493,7 @@ int current_search(int count, bool forward) // beginning of the file (cursor might be on the search match) // except when Visual mode is active, so that extending the visual // selection works. - if (i == 1 && !result) { // not found, abort */ + if (i == 1 && !result) { // not found, abort curwin->w_cursor = orig_pos; if (VIsual_active) { VIsual = save_VIsual; @@ -2472,7 +2505,7 @@ int current_search(int count, bool forward) } else { // try again from end of buffer // searching backwards, so set pos to last line and col pos.lnum = curwin->w_buffer->b_ml.ml_line_count; - pos.col = (colnr_T)strlen(ml_get(curwin->w_buffer->b_ml.ml_line_count)); + pos.col = ml_get_len(curwin->w_buffer->b_ml.ml_line_count); } } } @@ -2525,7 +2558,8 @@ int current_search(int count, bool forward) /// else from position "cur". /// "direction" is FORWARD or BACKWARD. /// Returns true, false or -1 for failure. -static int is_zero_width(char *pattern, bool move, pos_T *cur, Direction direction) +static int is_zero_width(char *pattern, size_t patternlen, bool move, pos_T *cur, + Direction direction) { regmmatch_T regmatch; int result = -1; @@ -2535,9 +2569,10 @@ static int is_zero_width(char *pattern, bool move, pos_T *cur, Direction directi if (pattern == NULL) { pattern = spats[last_idx].pat; + patternlen = spats[last_idx].patlen; } - if (search_regcomp(pattern, NULL, RE_SEARCH, RE_SEARCH, + if (search_regcomp(pattern, patternlen, NULL, RE_SEARCH, RE_SEARCH, SEARCH_KEEP, ®match) == FAIL) { return -1; } @@ -2552,7 +2587,7 @@ static int is_zero_width(char *pattern, bool move, pos_T *cur, Direction directi // accept a match at the cursor position flag = SEARCH_START; } - if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, 1, + if (searchit(curwin, curbuf, &pos, NULL, direction, pattern, patternlen, 1, SEARCH_KEEP + flag, RE_SEARCH, NULL) != FAIL) { int nmatched = 0; // Zero-width pattern should match somewhere, then we can check if @@ -2591,7 +2626,8 @@ bool linewhite(linenr_T lnum) /// Add the search count "[3/19]" to "msgbuf". /// See update_search_stat() for other arguments. static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool show_top_bot_msg, - char *msgbuf, bool recompute, int maxcount, int timeout) + char *msgbuf, size_t msgbuflen, bool recompute, int maxcount, + int timeout) { searchstat_T stat; @@ -2602,36 +2638,36 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh } char t[SEARCH_STAT_BUF_LEN]; + size_t len; if (curwin->w_p_rl && *curwin->w_p_rlc == 's') { if (stat.incomplete == 1) { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); + len = (size_t)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); + len = (size_t)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); + len = (size_t)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); + len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", + stat.cnt, stat.cur); } } else { if (stat.incomplete == 1) { - vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[?/??]"); + len = (size_t)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); + len = (size_t)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); + len = (size_t)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); + len = (size_t)vim_snprintf(t, SEARCH_STAT_BUF_LEN, "[%d/%d]", + stat.cur, stat.cnt); } } - size_t len = strlen(t); if (show_top_bot_msg && len + 2 < SEARCH_STAT_BUF_LEN) { memmove(t + 2, t, len); t[0] = 'W'; @@ -2639,11 +2675,10 @@ static void cmdline_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, bool sh len += 2; } - size_t msgbuf_len = strlen(msgbuf); - if (len > msgbuf_len) { - len = msgbuf_len; + if (len > msgbuflen) { + len = msgbuflen; } - memmove(msgbuf + msgbuf_len - len, t, len); + memmove(msgbuf + msgbuflen - len, t, len); if (dirc == '?' && stat.cur == maxcount + 1) { stat.cur = -1; @@ -2726,7 +2761,7 @@ static void update_search_stat(int dirc, pos_T *pos, pos_T *cursor_pos, searchst start = profile_setlimit(timeout); } while (!got_int && searchit(curwin, curbuf, &lastpos, &endpos, - FORWARD, NULL, 1, SEARCH_KEEP, RE_LAST, + FORWARD, NULL, 0, 1, SEARCH_KEEP, RE_LAST, NULL) != FAIL) { done_search = true; // Stop after passing the time limit. @@ -2860,7 +2895,8 @@ void f_searchcount(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) goto the_end; } xfree(spats[last_idx].pat); - spats[last_idx].pat = xstrdup(pattern); + spats[last_idx].patlen = strlen(pattern); + spats[last_idx].pat = xstrnsave(pattern, spats[last_idx].patlen); } if (spats[last_idx].pat == NULL || *spats[last_idx].pat == NUL) { goto the_end; // the previous pattern was never defined @@ -3564,8 +3600,10 @@ static char *get_line_and_copy(linenr_T lnum, char *buf) /// @param action What to do when we find it /// @param start_lnum first line to start searching /// @param end_lnum last line for searching +/// @param forceit If true, always switch to the found path void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool skip_comments, - int type, int count, int action, linenr_T start_lnum, linenr_T end_lnum) + int type, int count, int action, linenr_T start_lnum, linenr_T end_lnum, + int forceit) { SearchedFile *files; // Stack of included files SearchedFile *bigger; // When we need more space @@ -3600,10 +3638,10 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool // when CONT_SOL is set compare "ptr" with the beginning of the // line is faster than quote_meta/regcomp/regexec "ptr" -- Acevedo && !compl_status_sol()) { - size_t patlen = len + 5; - char *pat = xmalloc(patlen); + size_t patsize = len + 5; + char *pat = xmalloc(patsize); assert(len <= INT_MAX); - snprintf(pat, patlen, whole ? "\\<%.*s\\>" : "%.*s", (int)len, ptr); + snprintf(pat, patsize, whole ? "\\<%.*s\\>" : "%.*s", (int)len, ptr); // ignore case according to p_ic, p_scs and pat regmatch.rm_ic = ignorecase(pat); regmatch.regprog = vim_regcomp(pat, magic_isset() ? RE_MAGIC : 0); @@ -3621,8 +3659,7 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool incl_regmatch.rm_ic = false; // don't ignore case in incl. pat. } if (type == FIND_DEFINE && (*curbuf->b_p_def != NUL || *p_def != NUL)) { - def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL - ? p_def : curbuf->b_p_def, + def_regmatch.regprog = vim_regcomp(*curbuf->b_p_def == NUL ? p_def : curbuf->b_p_def, magic_isset() ? RE_MAGIC : 0); if (def_regmatch.regprog == NULL) { goto fpip_end; @@ -3675,9 +3712,8 @@ void find_pattern_in_path(char *ptr, Direction dir, size_t len, bool whole, bool true) & kEqualFiles) { if (type != CHECK_PATH && action == ACTION_SHOW_ALL && files[i].matched) { - msg_putchar('\n'); // cursor below last one */ - if (!got_int) { // don't display if 'q' typed at "--more--" - // message + msg_putchar('\n'); // cursor below last one + if (!got_int) { // don't display if 'q' typed at "--more--" message msg_home_replace_hl(new_fname); msg_puts(_(" (includes previously listed match)")); prev_fname = NULL; @@ -4025,17 +4061,17 @@ search_line: break; } if (!GETFILE_SUCCESS(getfile(curwin_save->w_buffer->b_fnum, NULL, - NULL, true, lnum, false))) { + NULL, true, lnum, forceit))) { break; // failed to jump to file } } else { setpcmark(); } curwin->w_cursor.lnum = lnum; - check_cursor(); + check_cursor(curwin); } else { if (!GETFILE_SUCCESS(getfile(0, files[depth].name, NULL, true, - files[depth].lnum, false))) { + files[depth].lnum, forceit))) { break; // failed to jump to file } // autocommands may have changed the lnum, we don't @@ -4051,7 +4087,7 @@ search_line: if (l_g_do_tagpreview != 0 && curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_VALID); win_enter(curwin_save, true); } @@ -4065,7 +4101,7 @@ exit_matched: && action == ACTION_EXPAND && !compl_status_sol() && *startp != NUL - && *(p = startp + utfc_ptr2len(startp)) != NUL) { + && *(startp + utfc_ptr2len(startp)) != NUL) { goto search_line; } } @@ -4164,8 +4200,9 @@ static void show_pat_in_path(char *line, int type, bool did_show, int action, FI if (got_int) { // 'q' typed at "--more--" message return; } + size_t linelen = strlen(line); while (true) { - char *p = line + strlen(line) - 1; + char *p = line + linelen - 1; if (fp != NULL) { // We used fgets(), so get rid of newline at end if (p >= line && *p == '\n') { @@ -4195,12 +4232,14 @@ static void show_pat_in_path(char *line, int type, bool did_show, int action, FI if (vim_fgets(line, LSIZE, fp)) { // end of file break; } + linelen = strlen(line); (*lnum)++; } else { if (++*lnum > curbuf->b_ml.ml_line_count) { break; } line = ml_get(*lnum); + linelen = (size_t)ml_get_len(*lnum); } msg_putchar('\n'); } diff --git a/src/nvim/search.h b/src/nvim/search.h index 09af34d87e..783756b781 100644 --- a/src/nvim/search.h +++ b/src/nvim/search.h @@ -84,6 +84,7 @@ typedef struct { /// Structure containing last search pattern and its attributes. typedef struct { char *pat; ///< The pattern (in allocated memory) or NULL. + size_t patlen; ///< The length of the patten (0 is pat is NULL). bool magic; ///< Magicness of the pattern. bool no_scs; ///< No smartcase for this pattern. Timestamp timestamp; ///< Time of the last change. diff --git a/src/nvim/shada.c b/src/nvim/shada.c index 0b148993f8..34c36f850f 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -1188,6 +1188,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) .off = cur_entry.data.search_pattern.offset, }, .pat = cur_entry.data.search_pattern.pat, + .patlen = strlen(cur_entry.data.search_pattern.pat), .additional_data = cur_entry.data.search_pattern.additional_data, .timestamp = cur_entry.timestamp, }; diff --git a/src/nvim/spell.c b/src/nvim/spell.c index c2091c6bae..d7a6adef58 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -811,7 +811,7 @@ static void find_word(matchinf_T *mip, int mode) if (ptr == mip->mi_word) { spell_casefold(mip->mi_win, ptr, wlen, fword, MAXWLEN); } else { - xstrlcpy(fword, ptr, (size_t)endlen[endidxcnt] + 1); + xmemcpyz(fword, ptr, (size_t)endlen[endidxcnt]); } } if (!can_compound(slang, fword, mip->mi_compflags)) { @@ -1290,11 +1290,11 @@ static inline bool can_syn_spell(win_T *wp, linenr_T lnum, int col) /// to after badly spelled word before the cursor. /// /// @param dir FORWARD or BACKWARD -/// @param allwords true for "[s"/"]s", false for "[S"/"]S" +/// @param behaviour Behaviour of the function /// @param attrp return: attributes of bad word or NULL (only when "dir" is FORWARD) /// /// @return 0 if not found, length of the badly spelled word otherwise. -size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *attrp) +size_t spell_move_to(win_T *wp, int dir, smt_T behaviour, bool curline, hlf_T *attrp) { pos_T found_pos; size_t found_len = 0; @@ -1342,7 +1342,7 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att while (!got_int) { char *line = ml_get_buf(wp->w_buffer, lnum); - len = strlen(line); + len = (size_t)ml_get_buf_len(wp->w_buffer, lnum); if (buflen < len + MAXWLEN + 2) { xfree(buf); buflen = len + MAXWLEN + 2; @@ -1398,7 +1398,9 @@ size_t spell_move_to(win_T *wp, int dir, bool allwords, bool curline, hlf_T *att if (attr != HLF_COUNT) { // We found a bad word. Check the attribute. - if (allwords || attr == HLF_SPB) { + if (behaviour == SMT_ALL + || (behaviour == SMT_BAD && attr == HLF_SPB) + || (behaviour == SMT_RARE && attr == HLF_SPR)) { // When searching forward only accept a bad word after // the cursor. if (dir == BACKWARD @@ -1810,7 +1812,7 @@ void count_common_word(slang_T *lp, char *word, int len, uint8_t count) } else if (len >= MAXWLEN) { return; } else { - xstrlcpy(buf, word, (size_t)len + 1); + xmemcpyz(buf, word, (size_t)len); p = buf; } @@ -1868,7 +1870,7 @@ int init_syl_tab(slang_T *slang) } syl_item_T *syl = GA_APPEND_VIA_PTR(syl_item_T, &slang->sl_syl_items); - xstrlcpy(syl->sy_chars, s, (size_t)l + 1); + xmemcpyz(syl->sy_chars, s, (size_t)l); syl->sy_len = l; } return OK; @@ -2253,7 +2255,7 @@ static void use_midword(slang_T *lp, win_T *wp) char *bp = xstrnsave(wp->w_s->b_spell_ismw_mb, (size_t)n + (size_t)l); xfree(wp->w_s->b_spell_ismw_mb); wp->w_s->b_spell_ismw_mb = bp; - xstrlcpy(bp + n, p, (size_t)l + 1); + xmemcpyz(bp + n, p, (size_t)l); } p += l; } @@ -2663,16 +2665,16 @@ void ex_spellrepall(exarg_T *eap) const size_t repl_to_len = strlen(repl_to); const int addlen = (int)(repl_to_len - repl_from_len); - const size_t frompatlen = repl_from_len + 7; - char *frompat = xmalloc(frompatlen); - snprintf(frompat, frompatlen, "\\V\\<%s\\>", repl_from); + const size_t frompatsize = repl_from_len + 7; + char *frompat = xmalloc(frompatsize); + size_t frompatlen = (size_t)snprintf(frompat, frompatsize, "\\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, '/', '/', frompat, 1, SEARCH_KEEP, NULL) == 0 + if (do_search(NULL, '/', '/', frompat, frompatlen, 1, SEARCH_KEEP, NULL) == 0 || u_save_cursor() == FAIL) { break; } @@ -2682,7 +2684,7 @@ void ex_spellrepall(exarg_T *eap) char *line = get_cursor_line_ptr(); if (addlen <= 0 || strncmp(line + curwin->w_cursor.col, repl_to, repl_to_len) != 0) { - char *p = xmalloc(strlen(line) + (size_t)addlen + 1); + char *p = xmalloc((size_t)get_cursor_line_len() + (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 + repl_from_len); diff --git a/src/nvim/spell.h b/src/nvim/spell.h index adbdd3705e..85e16d7f6c 100644 --- a/src/nvim/spell.h +++ b/src/nvim/spell.h @@ -21,6 +21,13 @@ extern char *e_format; extern char *repl_from; extern char *repl_to; +/// Values for behaviour in spell_move_to +typedef enum { + SMT_ALL = 0, ///< Move to "all" words + SMT_BAD, ///< Move to "bad" words only + SMT_RARE, ///< Move to "rare" words only +} smt_T; + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "spell.h.generated.h" #endif diff --git a/src/nvim/spellfile.c b/src/nvim/spellfile.c index 1c632d2700..046a0a56e5 100644 --- a/src/nvim/spellfile.c +++ b/src/nvim/spellfile.c @@ -2859,7 +2859,7 @@ static void process_compflags(spellinfo_T *spin, afffile_T *aff, char *compflags if (flag != 0) { // Find the flag in the hashtable. If it was used before, use // the existing ID. Otherwise add a new entry. - xstrlcpy(key, prevp, (size_t)(p - prevp) + 1); + xmemcpyz(key, prevp, (size_t)(p - prevp)); hashitem_T *hi = hash_find(&aff->af_comp, key); if (!HASHITEM_EMPTY(hi)) { id = HI2CI(hi)->ci_newID; @@ -3263,7 +3263,7 @@ static int get_pfxlist(afffile_T *affile, char *afflist, char *store_afflist) 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 - prevp) + 1); + xmemcpyz(key, prevp, (size_t)(p - prevp)); hashitem_T *hi = hash_find(&affile->af_pref, key); if (!HASHITEM_EMPTY(hi)) { int id = HI2AH(hi)->ah_newID; @@ -3293,7 +3293,7 @@ static void get_compflags(afffile_T *affile, char *afflist, char *store_afflist) char *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 - prevp) + 1); + xmemcpyz(key, prevp, (size_t)(p - prevp)); hashitem_T *hi = hash_find(&affile->af_comp, key); if (!HASHITEM_EMPTY(hi)) { store_afflist[cnt++] = (char)(uint8_t)HI2CI(hi)->ci_newID; @@ -3481,7 +3481,7 @@ static int store_aff_word(spellinfo_T *spin, char *word, char *afflist, afffile_ // Obey a "COMPOUNDFORBIDFLAG" of the affix: don't // use the compound flags. if (use_pfxlist != NULL && ae->ae_compforbid) { - xstrlcpy(pfx_pfxlist, use_pfxlist, (size_t)use_pfxlen + 1); + xmemcpyz(pfx_pfxlist, use_pfxlist, (size_t)use_pfxlen); use_pfxlist = pfx_pfxlist; } @@ -5114,13 +5114,12 @@ static void sug_write(spellinfo_T *spin, char *fname) for (linenr_T lnum = 1; lnum <= wcount; lnum++) { // <sugline>: <sugnr> ... NUL char *line = ml_get_buf(spin->si_spellbuf, lnum); - size_t len = strlen(line) + 1; - if (fwrite(line, len, 1, fd) == 0) { + int len = ml_get_buf_len(spin->si_spellbuf, lnum) + 1; + if (fwrite(line, (size_t)len, 1, fd) == 0) { emsg(_(e_write)); goto theend; } - assert((size_t)spin->si_memtot + len <= INT_MAX); - spin->si_memtot += (int)len; + spin->si_memtot += len; } // Write another byte to check for errors. @@ -5577,7 +5576,7 @@ static void init_spellfile(void) 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)); + xmemcpyz(buf, curbuf->b_s.b_p_spl, (size_t)(lstart - curbuf->b_s.b_p_spl - 1)); } else { // Copy the path from 'runtimepath' to buf[]. copy_option_part(&rtp, buf, MAXPATHL, ","); @@ -5586,7 +5585,7 @@ static void init_spellfile(void) // Use the first language name from 'spelllang' and the // encoding used in the first loaded .spl file. if (aspath) { - xstrlcpy(buf, curbuf->b_s.b_p_spl, (size_t)(lend - curbuf->b_s.b_p_spl + 1)); + xmemcpyz(buf, curbuf->b_s.b_p_spl, (size_t)(lend - curbuf->b_s.b_p_spl)); } else { // Create the "spell" directory if it doesn't exist yet. l = (int)strlen(buf); diff --git a/src/nvim/spellsuggest.c b/src/nvim/spellsuggest.c index 5c0e295f88..a7de20d14e 100644 --- a/src/nvim/spellsuggest.c +++ b/src/nvim/spellsuggest.c @@ -480,12 +480,11 @@ void spell_suggest(int count) badlen++; end_visual_mode(); // make sure we don't include the NUL at the end of the line - char *line = get_cursor_line_ptr(); - if (badlen > (int)strlen(line) - (int)curwin->w_cursor.col) { - badlen = (int)strlen(line) - (int)curwin->w_cursor.col; + if (badlen > get_cursor_line_len() - curwin->w_cursor.col) { + badlen = get_cursor_line_len() - curwin->w_cursor.col; } // Find the start of the badly spelled word. - } else if (spell_move_to(curwin, FORWARD, true, true, NULL) == 0 + } else if (spell_move_to(curwin, FORWARD, SMT_ALL, true, NULL) == 0 || curwin->w_cursor.col > prev_cursor.col) { // No bad word or it starts after the cursor: use the word under the // cursor. @@ -514,7 +513,7 @@ void spell_suggest(int count) int need_cap = check_need_cap(curwin, curwin->w_cursor.lnum, curwin->w_cursor.col); // Make a copy of current line since autocommands may free the line. - char *line = xstrdup(get_cursor_line_ptr()); + char *line = xstrnsave(get_cursor_line_ptr(), (size_t)get_cursor_line_len()); spell_suggest_timeout = 5000; // Get the list of suggestions. Limit to 'lines' - 2 or the number in @@ -562,7 +561,8 @@ void spell_suggest(int count) xstrlcpy(wcopy, stp->st_word, MAXWLEN + 1); int el = sug.su_badlen - stp->st_orglen; if (el > 0 && stp->st_wordlen + el <= MAXWLEN) { - xstrlcpy(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen, (size_t)el + 1); + assert(sug.su_badptr != NULL); + xmemcpyz(wcopy + stp->st_wordlen, sug.su_badptr + stp->st_orglen, (size_t)el); } vim_snprintf(IObuff, IOSIZE, "%2d", i + 1); if (cmdmsg_rl) { @@ -734,7 +734,7 @@ static void spell_find_suggest(char *badptr, int badlen, suginfo_T *su, int maxc if (su->su_badlen >= MAXWLEN) { su->su_badlen = MAXWLEN - 1; // just in case } - xstrlcpy(su->su_badword, su->su_badptr, (size_t)su->su_badlen + 1); + xmemcpyz(su->su_badword, su->su_badptr, (size_t)su->su_badlen); spell_casefold(curwin, su->su_badptr, su->su_badlen, su->su_fbadword, MAXWLEN); @@ -1368,9 +1368,9 @@ static void suggest_trie_walk(suginfo_T *su, langp_T *lp, char *fword, bool soun compflags[sp->ts_complen] = (uint8_t)((unsigned)flags >> 24); compflags[sp->ts_complen + 1] = NUL; - xstrlcpy(preword + sp->ts_prewordlen, + xmemcpyz(preword + sp->ts_prewordlen, tword + sp->ts_splitoff, - (size_t)(sp->ts_twordlen - sp->ts_splitoff) + 1); + (size_t)(sp->ts_twordlen - sp->ts_splitoff)); // Verify CHECKCOMPOUNDPATTERN rules. if (match_checkcompoundpattern(preword, sp->ts_prewordlen, @@ -2647,8 +2647,8 @@ static int stp_sal_score(suggest_T *stp, suginfo_T *su, slang_T *slang, char *ba // Add part of the bad word to the good word, so that we soundfold // what replaces the bad word. STRCPY(goodword, stp->st_word); - xstrlcpy(goodword + stp->st_wordlen, - su->su_badptr + su->su_badlen - lendiff, (size_t)lendiff + 1); + xmemcpyz(goodword + stp->st_wordlen, + su->su_badptr + su->su_badlen - lendiff, (size_t)lendiff); pgood = goodword; } else { pgood = stp->st_word; diff --git a/src/nvim/state.c b/src/nvim/state.c index 0df060ecf4..993db255de 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -135,9 +135,9 @@ void state_handle_k_event(void) } /// Return true if in the current mode we need to use virtual. -bool virtual_active(void) +bool virtual_active(win_T *wp) { - unsigned cur_ve_flags = get_ve_flags(); + unsigned cur_ve_flags = get_ve_flags(wp); // While an operator is being executed we return "virtual_op", because // VIsual_active has already been reset, thus we can't check for "block" @@ -289,7 +289,7 @@ static bool is_safe_now(void) && !debug_mode; } -/// Trigger SafeState if currently in s safe state, that is "safe" is TRUE and +/// Trigger SafeState if currently in a safe state, that is "safe" is true and /// there is no typeahead. void may_trigger_safestate(bool safe) { diff --git a/src/nvim/state.h b/src/nvim/state.h index 9002f018d2..8220d90a67 100644 --- a/src/nvim/state.h +++ b/src/nvim/state.h @@ -1,6 +1,7 @@ #pragma once #include "nvim/state_defs.h" // IWYU pragma: keep +#include "nvim/types_defs.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "state.h.generated.h" diff --git a/src/nvim/statusline.c b/src/nvim/statusline.c index b403f840ca..ca7083a9e3 100644 --- a/src/nvim/statusline.c +++ b/src/nvim/statusline.c @@ -1002,11 +1002,11 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op // Get the byte value now, in case we need it below. This is more // efficient than making a copy of the line. int byteval; - const size_t len = strlen(line_ptr); - if (wp->w_cursor.col > (colnr_T)len) { + const colnr_T len = ml_get_buf_len(wp->w_buffer, lnum); + if (wp->w_cursor.col > len) { // Line may have changed since checking the cursor column, or the lnum // was adjusted above. - wp->w_cursor.col = (colnr_T)len; + wp->w_cursor.col = len; wp->w_cursor.coladd = 0; byteval = 0; } else { @@ -2187,7 +2187,7 @@ int build_stl_str_hl(win_T *wp, char *out, size_t outlen, char *fmt, OptIndex op // matter? // if (called_emsg > called_emsg_before) if (opt_idx != kOptInvalid && did_emsg > did_emsg_before) { - set_string_option_direct(opt_idx, "", opt_scope, SID_ERROR); + set_option_direct(opt_idx, STATIC_CSTR_AS_OPTVAL(""), opt_scope, SID_ERROR); } // A user function may reset KeyTyped, restore it. diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 01bd610292..16ae35272b 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -299,8 +299,8 @@ char *vim_strsave_shellescape(const char *string, bool do_special, bool do_newli char *vim_strsave_up(const char *string) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char *p1 = xstrdup(string); - vim_strup(p1); + char *p1 = xmalloc(strlen(string) + 1); + vim_strcpy_up(p1, string); return p1; } @@ -309,8 +309,8 @@ char *vim_strsave_up(const char *string) 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(p1); + char *p1 = xmalloc(len + 1); + vim_strncpy_up(p1, string, len); return p1; } @@ -324,6 +324,39 @@ void vim_strup(char *p) } } +// strcpy plus vim_strup. +void vim_strcpy_up(char *restrict dst, const char *restrict src) + FUNC_ATTR_NONNULL_ALL +{ + uint8_t c; + while ((c = (uint8_t)(*src++)) != NUL) { + *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); + } + *dst = '\0'; +} + +// strncpy (NUL-terminated) plus vim_strup. +void vim_strncpy_up(char *restrict dst, const char *restrict src, size_t n) + FUNC_ATTR_NONNULL_ALL +{ + uint8_t c; + while (n-- && (c = (uint8_t)(*src++)) != NUL) { + *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); + } + *dst = '\0'; +} + +// memcpy (does not NUL-terminate) plus vim_strup. +void vim_memcpy_up(char *restrict dst, const char *restrict src, size_t n) + FUNC_ATTR_NONNULL_ALL +{ + uint8_t c; + while (n--) { + c = (uint8_t)(*src++); + *dst++ = (char)(uint8_t)(c < 'a' || c > 'z' ? c : c - 0x20); + } +} + /// Make given string all upper-case or all lower-case /// /// Handles multi-byte characters as good as possible. @@ -910,7 +943,7 @@ static int adjust_types(const char ***ap_types, int arg, int *num_posarg, const { if (*ap_types == NULL || *num_posarg < arg) { const char **new_types = *ap_types == NULL - ? xcalloc(sizeof(const char *), (size_t)arg) + ? xcalloc((size_t)arg, sizeof(const char *)) : xrealloc(*ap_types, (size_t)arg * sizeof(const char *)); for (int idx = *num_posarg; idx < arg; idx++) { @@ -953,6 +986,40 @@ static int adjust_types(const char ***ap_types, int arg, int *num_posarg, const return OK; } +static void format_overflow_error(const char *pstart) +{ + const char *p = pstart; + + while (ascii_isdigit((int)(*p))) { + p++; + } + + size_t arglen = (size_t)(p - pstart); + char *argcopy = xstrnsave(pstart, arglen); + semsg(_(e_val_too_large), argcopy); + xfree(argcopy); +} + +enum { MAX_ALLOWED_STRING_WIDTH = 6400, }; + +static int get_unsigned_int(const char *pstart, const char **p, unsigned *uj) +{ + *uj = (unsigned)(**p - '0'); + (*p)++; + + while (ascii_isdigit((int)(**p)) && *uj < MAX_ALLOWED_STRING_WIDTH) { + *uj = 10 * *uj + (unsigned)(**p - '0'); + (*p)++; + } + + if (*uj > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(pstart); + return FAIL; + } + + return OK; +} + static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char *fmt, typval_T *tvs) FUNC_ATTR_NONNULL_ARG(1, 2) { @@ -986,6 +1053,7 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * // variable for positional arg int pos_arg = -1; + const char *pstart = p + 1; p++; // skip '%' @@ -1005,11 +1073,12 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * } // Positional argument - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(pstart, &p, &uj) == FAIL) { + goto error; } + pos_arg = (int)uj; any_pos = 1; @@ -1047,10 +1116,10 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * if (ascii_isdigit((int)(*p))) { // Positional argument field width - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) { + goto error; } if (*p != '$') { @@ -1072,10 +1141,11 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * } else if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we treat // argument like common implementations do - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } if (*p == '$') { @@ -1093,10 +1163,10 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * if (ascii_isdigit((int)(*p))) { // Parse precision - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(arg + 1, &p, &uj) == FAIL) { + goto error; } if (*p == '$') { @@ -1119,10 +1189,11 @@ static int parse_fmt_types(const char ***ap_types, int *num_posarg, const char * } else if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we // treat argument like common implementations do - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } if (*p == '$') { @@ -1414,11 +1485,13 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st if (*ptype == '$') { // Positional argument - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } + pos_arg = (int)uj; p++; @@ -1449,15 +1522,18 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st // parse field width if (*p == '*') { + const char *digstart = p + 1; + p++; if (ascii_isdigit((int)(*p))) { // Positional argument field width - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } + arg_idx = (int)uj; p++; @@ -1469,6 +1545,11 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st &arg_cur, fmt), va_arg(ap, int))); + if (j > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(digstart); + goto error; + } + if (j >= 0) { min_field_width = (size_t)j; } else { @@ -1478,11 +1559,18 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st } else if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we treat // argument like common implementations do - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; + + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; + } - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (uj > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(digstart); + goto error; } + min_field_width = uj; } @@ -1494,22 +1582,32 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st if (ascii_isdigit((int)(*p))) { // size_t could be wider than unsigned int; make sure we // treat argument like common implementations do - unsigned uj = (unsigned)(*p++ - '0'); + const char *digstart = p; + unsigned uj; + + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; + } - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (uj > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(digstart); + goto error; } + precision = uj; } else if (*p == '*') { + const char *digstart = p; + p++; if (ascii_isdigit((int)(*p))) { // positional argument - unsigned uj = (unsigned)(*p++ - '0'); + unsigned uj; - while (ascii_isdigit((int)(*p))) { - uj = 10 * uj + (unsigned)(*p++ - '0'); + if (get_unsigned_int(digstart, &p, &uj) == FAIL) { + goto error; } + arg_idx = (int)uj; p++; @@ -1521,6 +1619,11 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st &arg_cur, fmt), va_arg(ap, int))); + if (j > MAX_ALLOWED_STRING_WIDTH) { + format_overflow_error(digstart); + goto error; + } + if (j >= 0) { precision = (size_t)j; } else { @@ -2127,6 +2230,7 @@ int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap_st emsg(_("E767: Too many arguments to printf()")); } +error: xfree(ap_types); va_end(ap); @@ -3024,3 +3128,39 @@ void f_trim(typval_T *argvars, typval_T *rettv, EvalFuncData fptr) } rettv->vval.v_string = xstrnsave(head, (size_t)(tail - head)); } + +/// compare two keyvalue_T structs by case sensitive value +int cmp_keyvalue_value(const void *a, const void *b) +{ + keyvalue_T *kv1 = (keyvalue_T *)a; + keyvalue_T *kv2 = (keyvalue_T *)b; + + return strcmp(kv1->value, kv2->value); +} + +/// compare two keyvalue_T structs by value with length +int cmp_keyvalue_value_n(const void *a, const void *b) +{ + keyvalue_T *kv1 = (keyvalue_T *)a; + keyvalue_T *kv2 = (keyvalue_T *)b; + + return strncmp(kv1->value, kv2->value, MAX(kv1->length, kv2->length)); +} + +/// compare two keyvalue_T structs by case insensitive value +int cmp_keyvalue_value_i(const void *a, const void *b) +{ + keyvalue_T *kv1 = (keyvalue_T *)a; + keyvalue_T *kv2 = (keyvalue_T *)b; + + return STRICMP(kv1->value, kv2->value); +} + +/// compare two keyvalue_T structs by case insensitive value with length +int cmp_keyvalue_value_ni(const void *a, const void *b) +{ + keyvalue_T *kv1 = (keyvalue_T *)a; + keyvalue_T *kv2 = (keyvalue_T *)b; + + return STRNICMP(kv1->value, kv2->value, MAX(kv1->length, kv2->length)); +} diff --git a/src/nvim/strings.h b/src/nvim/strings.h index 903559b062..f80e85afb0 100644 --- a/src/nvim/strings.h +++ b/src/nvim/strings.h @@ -32,6 +32,18 @@ static inline char *strappend(char *const dst, const char *const src) typedef kvec_t(char) StringBuilder; +// Return the length of a string literal +#define STRLEN_LITERAL(s) (sizeof(s) - 1) + +/// Store a key/value pair +typedef struct { + int key; ///< the key + char *value; ///< the value string + size_t length; ///< length of the value string +} keyvalue_T; + +#define KEYVALUE_ENTRY(k, v) { (k), (v), STRLEN_LITERAL(v) } + #ifdef INCLUDE_GENERATED_DECLARATIONS # include "strings.h.generated.h" #endif diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index ab8ab62b90..b63d2a729d 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -549,8 +549,8 @@ static void syn_sync(win_T *wp, linenr_T start_lnum, synstate_T *last_valid) // Skip lines that end in a backslash. for (; start_lnum > 1; start_lnum--) { - char *line = ml_get(start_lnum - 1); - if (*line == NUL || *(line + strlen(line) - 1) != '\\') { + char *l = ml_get(start_lnum - 1); + if (*l == NUL || *(l + ml_get_len(start_lnum - 1) - 1) != '\\') { break; } } @@ -2352,7 +2352,6 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ regmmatch_T regmatch; regmmatch_T best_regmatch; // startpos/endpos of best match lpos_T pos; - char *line; bool had_match = false; char buf_chartab[32]; // chartab array for syn option iskeyword @@ -2457,8 +2456,7 @@ static void find_endpos(int idx, lpos_T *startpos, lpos_T *m_endpos, lpos_T *hl_ break; } - line = ml_get_buf(syn_buf, startpos->lnum); - int line_len = (int)strlen(line); + int line_len = ml_get_buf_len(syn_buf, startpos->lnum); // take care of an empty match or negative offset if (pos.col <= matchcol) { @@ -2635,7 +2633,7 @@ static void syn_add_start_off(lpos_T *result, regmmatch_T *regmatch, synpat_T *s if (result->lnum > syn_buf->b_ml.ml_line_count) { // a "\n" at the end of the pattern may take us below the last line result->lnum = syn_buf->b_ml.ml_line_count; - col = (int)strlen(ml_get_buf(syn_buf, result->lnum)); + col = ml_get_buf_len(syn_buf, result->lnum); } if (off != 0) { base = ml_get_buf(syn_buf, result->lnum); @@ -2735,7 +2733,7 @@ static int check_keyword_id(char *const line, const int startcol, int *const end // Must make a copy of the keyword, so we can add a NUL and make it // lowercase. char keyword[MAXKEYWLEN + 1]; // assume max. keyword len is 80 - xstrlcpy(keyword, kwp, (size_t)kwlen + 1); + xmemcpyz(keyword, kwp, (size_t)kwlen); keyentry_T *kp = NULL; @@ -4951,7 +4949,7 @@ static int get_id_list(char **const arg, const int keylen, int16_t **const list, do { for (end = p; *end && !ascii_iswhite(*end) && *end != ','; end++) {} char *const name = xmalloc((size_t)(end - p) + 3); // leave room for "^$" - xstrlcpy(name + 1, p, (size_t)(end - p) + 1); + xmemcpyz(name + 1, p, (size_t)(end - p)); if (strcmp(name + 1, "ALLBUT") == 0 || strcmp(name + 1, "ALL") == 0 || strcmp(name + 1, "TOP") == 0 diff --git a/src/nvim/tag.c b/src/nvim/tag.c index ab5bfc6773..e7f483dd3d 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -316,11 +316,6 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose) static char **matches = NULL; static int flags; - if (tfu_in_use) { - emsg(_(e_cannot_modify_tag_stack_within_tagfunc)); - return; - } - #ifdef EXITFREE if (type == DT_FREE) { // remove the list of matches @@ -330,6 +325,15 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose) } #endif + if (tfu_in_use) { + emsg(_(e_cannot_modify_tag_stack_within_tagfunc)); + return; + } + + if (postponed_split == 0 && !check_can_set_curbuf_forceit(forceit)) { + return; + } + if (type == DT_HELP) { type = DT_TAG; no_regexp = true; @@ -445,7 +449,7 @@ void do_tag(char *tag, int type, int count, int forceit, bool verbose) } curwin->w_cursor.col = saved_fmark.mark.col; curwin->w_set_curswant = true; - check_cursor(); + check_cursor(curwin); if ((fdo_flags & FDO_TAG) && old_KeyTyped) { foldOpenCursor(); } @@ -998,7 +1002,7 @@ static int add_llist_tags(char *tag, int num_matches, char **matches) if (len > 128) { len = 128; } - xstrlcpy(tag_name, tagp.tagname, (size_t)len + 1); + xmemcpyz(tag_name, tagp.tagname, (size_t)len); tag_name[len] = NUL; // Save the tag file name @@ -1464,7 +1468,7 @@ static bool findtags_in_help_init(findtags_state_T *st) // language name in help_lang[]. i = (int)strlen(st->tag_fname); if (i > 3 && st->tag_fname[i - 3] == '-') { - xstrlcpy(st->help_lang, st->tag_fname + i - 2, 3); + xmemcpyz(st->help_lang, st->tag_fname + i - 2, 2); } else { STRCPY(st->help_lang, "en"); } @@ -2011,7 +2015,7 @@ static void findtags_add_match(findtags_state_T *st, tagptrs_T *tagpp, findtags_ if (tagpp->command + 2 < temp_end) { len = (size_t)(temp_end - tagpp->command - 2); mfp = xmalloc(len + 2); - xstrlcpy(mfp, tagpp->command + 2, len + 1); + xmemcpyz(mfp, tagpp->command + 2, len); } else { mfp = NULL; } @@ -2019,7 +2023,7 @@ static void findtags_add_match(findtags_state_T *st, tagptrs_T *tagpp, findtags_ } else { len = (size_t)(tagpp->tagname_end - tagpp->tagname); mfp = xmalloc(sizeof(char) + len + 1); - xstrlcpy(mfp, tagpp->tagname, len + 1); + xmemcpyz(mfp, tagpp->tagname, len); // if wanted, re-read line to get long form too if (State & MODE_INSERT) { @@ -2784,6 +2788,10 @@ static char *tag_full_fname(tagptrs_T *tagp) /// @return OK for success, NOTAGFILE when file not found, FAIL otherwise. static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help) { + if (postponed_split == 0 && !check_can_set_curbuf_forceit(forceit)) { + return FAIL; + } + char *pbuf_end; char *tofree_fname = NULL; tagptrs_T tagp; @@ -2934,6 +2942,8 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help) str = skip_regexp(pbuf + 1, pbuf[0], false) + 1; } if (str > pbuf_end - 1) { // search command with nothing following + size_t pbuflen = (size_t)(pbuf_end - pbuf); + bool save_p_ws = p_ws; int save_p_ic = p_ic; int save_p_scs = p_scs; @@ -2948,25 +2958,27 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help) // start search before first line curwin->w_cursor.lnum = 0; } - if (do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, 1, search_options, NULL)) { + if (do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, pbuflen - 1, 1, + search_options, NULL)) { retval = OK; } else { int found = 1; // try again, ignore case now p_ic = true; - if (!do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, 1, search_options, NULL)) { + if (!do_search(NULL, pbuf[0], pbuf[0], pbuf + 1, pbuflen - 1, 1, + search_options, NULL)) { // Failed to find pattern, take a guess: "^func (" found = 2; test_for_static(&tagp); char cc = *tagp.tagname_end; *tagp.tagname_end = NUL; - snprintf(pbuf, LSIZE, "^%s\\s\\*(", tagp.tagname); - if (!do_search(NULL, '/', '/', pbuf, 1, search_options, NULL)) { + pbuflen = (size_t)snprintf(pbuf, LSIZE, "^%s\\s\\*(", tagp.tagname); + if (!do_search(NULL, '/', '/', pbuf, pbuflen, 1, search_options, NULL)) { // Guess again: "^char * \<func (" - snprintf(pbuf, LSIZE, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(", - tagp.tagname); - if (!do_search(NULL, '/', '/', pbuf, 1, search_options, NULL)) { + pbuflen = (size_t)snprintf(pbuf, LSIZE, "^\\[#a-zA-Z_]\\.\\*\\<%s\\s\\*(", + tagp.tagname); + if (!do_search(NULL, '/', '/', pbuf, pbuflen, 1, search_options, NULL)) { found = 0; } } @@ -2994,7 +3006,7 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help) // A search command may have positioned the cursor beyond the end // of the line. May need to correct that here. - check_cursor(); + check_cursor(curwin); } else { const int save_secure = secure; @@ -3039,7 +3051,7 @@ static int jumpto_tag(const char *lbuf_arg, int forceit, bool keep_help) if (l_g_do_tagpreview != 0 && curwin != curwin_save && win_valid(curwin_save)) { // Return cursor to where we were - validate_cursor(); + validate_cursor(curwin); redraw_later(curwin, UPD_VALID); win_enter(curwin_save, true); } @@ -3260,7 +3272,7 @@ static int add_tag_field(dict_T *dict, const char *field_name, const char *start if (len > MAXPATHL - 1) { len = MAXPATHL - 1; } - xstrlcpy(buf, start, (size_t)len + 1); + xmemcpyz(buf, start, (size_t)len); } buf[len] = NUL; int retval = tv_dict_add_str(dict, field_name, strlen(field_name), buf); diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index b5a3cffe2f..2b05a8047e 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -307,7 +307,8 @@ void terminal_open(Terminal **termpp, buf_T *buf, TerminalOptions opts) // Set up screen term->vts = vterm_obtain_screen(term->vt); vterm_screen_enable_altscreen(term->vts, true); - vterm_screen_enable_reflow(term->vts, true); + // TODO(clason): reenable when https://github.com/neovim/neovim/issues/23762 is fixed + // vterm_screen_enable_reflow(term->vts, true); // delete empty lines at the end of the buffer vterm_screen_set_callbacks(term->vts, &vterm_screen_callbacks, term); vterm_screen_set_unrecognised_fallbacks(term->vts, &vterm_fallbacks, term); @@ -542,6 +543,9 @@ bool terminal_enter(void) } else { curwin->w_p_cul = false; } + if (curwin->w_p_cuc) { + redraw_later(curwin, UPD_SOME_VALID); + } curwin->w_p_cuc = false; curwin->w_p_so = 0; curwin->w_p_siso = 0; @@ -612,7 +616,7 @@ static void terminal_check_cursor(void) row_to_linenr(term, term->cursor.row)); // Nudge cursor when returning to normal-mode. int off = is_focused(term) ? 0 : (curwin->w_p_rl ? 1 : -1); - coladvance(MAX(0, term->cursor.col + off)); + coladvance(curwin, MAX(0, term->cursor.col + off)); } // Function executed before each iteration of terminal mode. @@ -626,7 +630,7 @@ static int terminal_check(VimState *state) } terminal_check_cursor(); - validate_cursor(); + validate_cursor(curwin); if (must_redraw) { update_screen(); @@ -1627,7 +1631,10 @@ end: return false; } - ins_char_typebuf(vgetc_char, vgetc_mod_mask); + int len = ins_char_typebuf(vgetc_char, vgetc_mod_mask, true); + if (KeyTyped) { + ungetchars(len); + } return true; } diff --git a/src/nvim/textformat.c b/src/nvim/textformat.c index bfe3ed5972..1722bcc968 100644 --- a/src/nvim/textformat.c +++ b/src/nvim/textformat.c @@ -86,8 +86,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on // When 'ai' is off we don't want a space under the cursor to be // deleted. Replace it with an 'x' temporarily. - if (!curbuf->b_p_ai - && !(State & VREPLACE_FLAG)) { + if (!curbuf->b_p_ai && !(State & VREPLACE_FLAG)) { cc = gchar_cursor(); if (ascii_iswhite(cc)) { save_char = (char)cc; @@ -106,14 +105,9 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on colnr_T col; bool did_do_comment = false; - // Cursor is currently at the end of line. No need to format - // if line length is less than textwidth (8 * textwidth for - // utf safety) - if (curwin->w_cursor.col < 8 * textwidth) { - colnr_T virtcol = get_nolist_virtcol() + char2cells(c != NUL ? c : gchar_cursor()); - if (virtcol <= (colnr_T)textwidth) { - break; - } + colnr_T virtcol = get_nolist_virtcol() + char2cells(c != NUL ? c : gchar_cursor()); + if (virtcol <= (colnr_T)textwidth) { + break; } if (no_leader) { @@ -158,19 +152,12 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on } // find column of textwidth border - coladvance((colnr_T)textwidth); + coladvance(curwin, (colnr_T)textwidth); wantcol = curwin->w_cursor.col; - // If startcol is large (a long line), formatting takes too much - // time. The algorithm is O(n^2), it walks from the end of the - // line to textwidth border every time for each line break. - // - // Ceil to 8 * textwidth to optimize. - curwin->w_cursor.col = startcol < 8 * textwidth ? startcol : 8 * textwidth; - + curwin->w_cursor.col = startcol; foundcol = 0; int skip_pos = 0; - bool first_pass = true; // Find position to break at. // Stop at first entered white when 'formatoptions' has 'v' @@ -178,9 +165,8 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on || (flags & INSCHAR_FORMAT) || curwin->w_cursor.lnum != Insstart.lnum || curwin->w_cursor.col >= Insstart.col) { - if (first_pass && c != NUL) { + if (curwin->w_cursor.col == startcol && c != NUL) { cc = c; - first_pass = false; } else { cc = gchar_cursor(); } @@ -446,7 +432,7 @@ void internal_format(int textwidth, int second_indent, int flags, bool format_on // Check if cursor is not past the NUL off the line, cindent // may have added or removed indent. curwin->w_cursor.col += startcol; - colnr_T len = (colnr_T)strlen(get_cursor_line_ptr()); + colnr_T len = get_cursor_line_len(); if (curwin->w_cursor.col > len) { curwin->w_cursor.col = len; } @@ -507,12 +493,11 @@ static int fmt_check_par(linenr_T lnum, int *leader_len, char **leader_flags, bo static bool ends_in_white(linenr_T lnum) { char *s = ml_get(lnum); - size_t l; if (*s == NUL) { return false; } - l = strlen(s) - 1; + colnr_T l = ml_get_len(lnum) - 1; return ascii_iswhite((uint8_t)s[l]); } @@ -545,7 +530,7 @@ static bool same_leader(linenr_T lnum, int leader1_len, char *leader1_flags, int return false; } if (*p == COM_START) { - int line_len = (int)strlen(ml_get(lnum)); + int line_len = ml_get_len(lnum); if (line_len <= leader1_len) { return false; } @@ -648,7 +633,7 @@ void auto_format(bool trailblank, bool prev_line) // in 'formatoptions' and there is a single character before the cursor. // Otherwise the line would be broken and when typing another non-white // next they are not joined back together. - int wasatend = (pos.col == (colnr_T)strlen(old)); + bool wasatend = (pos.col == get_cursor_line_len()); if (*old != NUL && !trailblank && wasatend) { dec_cursor(); int cc = gchar_cursor(); @@ -691,9 +676,9 @@ void auto_format(bool trailblank, bool prev_line) if (curwin->w_cursor.lnum > curbuf->b_ml.ml_line_count) { // "cannot happen" curwin->w_cursor.lnum = curbuf->b_ml.ml_line_count; - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); } else { - check_cursor_col(); + check_cursor_col(curwin); } // Insert mode: If the cursor is now after the end of the line while it @@ -702,7 +687,7 @@ void auto_format(bool trailblank, bool prev_line) // formatted. if (!wasatend && has_format_option(FO_WHITE_PAR)) { char *linep = get_cursor_line_ptr(); - colnr_T len = (colnr_T)strlen(linep); + colnr_T len = get_cursor_line_len(); if (curwin->w_cursor.col == len) { char *plinep = xstrnsave(linep, (size_t)len + 2); plinep[len] = ' '; @@ -716,7 +701,7 @@ void auto_format(bool trailblank, bool prev_line) } } - check_cursor(); + check_cursor(curwin); } /// When an extra space was added to continue a paragraph for auto-formatting, @@ -840,7 +825,7 @@ void op_format(oparg_T *oap, bool keep_cursor) saved_cursor.lnum = 0; // formatting may have made the cursor position invalid - check_cursor(); + check_cursor(curwin); } if (oap->is_VIsual) { @@ -1064,7 +1049,7 @@ void format_lines(linenr_T line_count, bool avoid_fex) // put cursor on last non-space State = MODE_NORMAL; // don't go past end-of-line - coladvance(MAXCOL); + coladvance(curwin, MAXCOL); while (curwin->w_cursor.col && ascii_isspace(gchar_cursor())) { dec_cursor(); } @@ -1120,7 +1105,7 @@ void format_lines(linenr_T line_count, bool avoid_fex) } first_par_line = false; // If the line is getting long, format it next time - if (strlen(get_cursor_line_ptr()) > (size_t)max_len) { + if (get_cursor_line_len() > max_len) { force_format = true; } else { force_format = false; diff --git a/src/nvim/textobject.c b/src/nvim/textobject.c index d9c2b3b111..3c81a840ea 100644 --- a/src/nvim/textobject.c +++ b/src/nvim/textobject.c @@ -187,7 +187,7 @@ bool findpar(bool *pincl, int dir, int count, int what, bool both) // skip folded lines fold_skipped = false; - if (first && hasFolding(curr, &fold_first, &fold_last)) { + if (first && hasFolding(curwin, curr, &fold_first, &fold_last)) { curr = ((dir > 0) ? fold_last : fold_first) + dir; fold_skipped = true; } @@ -218,7 +218,7 @@ bool findpar(bool *pincl, int dir, int count, int what, bool both) // Put the cursor on the last character in the last line and make the // motion inclusive. - if ((curwin->w_cursor.col = (colnr_T)strlen(line)) != 0) { + if ((curwin->w_cursor.col = ml_get_len(curr)) != 0) { curwin->w_cursor.col--; curwin->w_cursor.col -= utf_head_off(line, line + curwin->w_cursor.col); *pincl = true; @@ -318,8 +318,8 @@ int fwd_word(int count, bool bigword, bool eol) while (--count >= 0) { // When inside a range of folded lines, move to the last char of the // last line. - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { - coladvance(MAXCOL); + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { + coladvance(curwin, MAXCOL); } int sclass = cls(); // starting class @@ -374,7 +374,7 @@ int bck_word(int count, bool bigword, bool stop) while (--count >= 0) { // When inside a range of folded lines, move to the first char of the // first line. - if (hasFolding(curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) { + if (hasFolding(curwin, curwin->w_cursor.lnum, &curwin->w_cursor.lnum, NULL)) { curwin->w_cursor.col = 0; } sclass = cls(); @@ -431,8 +431,8 @@ int end_word(int count, bool bigword, bool stop, bool empty) while (--count >= 0) { // When inside a range of folded lines, move to the last char of the // last line. - if (hasFolding(curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { - coladvance(MAXCOL); + if (hasFolding(curwin, curwin->w_cursor.lnum, NULL, &curwin->w_cursor.lnum)) { + coladvance(curwin, MAXCOL); } sclass = cls(); if (inc_cursor() == -1) { diff --git a/src/nvim/tui/input.c b/src/nvim/tui/input.c index 214474ff51..f1594dfcb9 100644 --- a/src/nvim/tui/input.c +++ b/src/nvim/tui/input.c @@ -442,12 +442,12 @@ static void tk_getkeys(TermInput *input, bool force) forward_modified_utf8(input, &key); } else if (key.type == TERMKEY_TYPE_MOUSE) { forward_mouse_event(input, &key); + } else if (key.type == TERMKEY_TYPE_MODEREPORT) { + handle_modereport(input, &key); } else if (key.type == TERMKEY_TYPE_UNKNOWN_CSI) { handle_unknown_csi(input, &key); } else if (key.type == TERMKEY_TYPE_OSC || key.type == TERMKEY_TYPE_DCS) { handle_term_response(input, &key); - } else if (key.type == TERMKEY_TYPE_MODEREPORT) { - handle_modereport(input, &key); } } @@ -553,6 +553,13 @@ static void handle_term_response(TermInput *input, const TermKeyKey *key) if (termkey_interpret_string(input->tk, key, &str) == TERMKEY_RES_KEY) { assert(str != NULL); + // Handle DECRQSS SGR response for the query from tui_query_extended_underline(). + // Some terminals include "0" in the attribute list unconditionally; others don't. + if (key->type == TERMKEY_TYPE_DCS + && (strnequal(str, S_LEN("1$r4:3m")) || strnequal(str, S_LEN("1$r0;4:3m")))) { + tui_enable_extended_underline(input->tui_data); + } + // Send an event to nvim core. This will update the v:termresponse variable // and fire the TermResponse event MAXSIZE_TEMP_ARRAY(args, 2); diff --git a/src/nvim/tui/terminfo_defs.h b/src/nvim/tui/terminfo_defs.h index 74ba23e4d9..4e8978479d 100644 --- a/src/nvim/tui/terminfo_defs.h +++ b/src/nvim/tui/terminfo_defs.h @@ -12,6 +12,7 @@ // move_insert_mode, // move_standout_mode, // prtr_silent, +// AX, // columns#80, // init_tabs#8, // lines#24, @@ -93,7 +94,7 @@ static const int8_t ansi_terminfo[] = { 26,1,40,0,38,0,16,0,125,1,68,2,97,110,115,105,124,97,110,115,105,47,112,99,45,116,101,114,109,32,99,111,109,112,97,116,105,98,108,101,32,119,105,116,104,32,99,111,108,111,114,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,80,0,8,0,24,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,0,64,0,3,0,0,0,4,0,6,0,-1,-1,8,0,13,0,20,0,24,0,28,0,-1,-1,39,0,56,0,60,0,-1,-1,64,0,-1,-1,-1,-1,68,0,-1,-1,72,0,-1,-1,76,0,80,0,-1,-1,-1,-1,84,0,90,0,95,0,-1,-1,-1,-1,-1,-1,-1,-1,100,0,-1,-1,105,0,110,0,115,0,120,0,-127,0,-121,0,-1,-1,-1,-1,-1,-1,-113,0,-109,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-105,0,-1,-1,-101,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-99,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-95,0,-91,0,-1,-1,-87,0,-1,-1,-1,-1,-1,-1,-83,0,-1,-1,-1,-1,-1,-1,-79,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-75,0,-1,-1,-70,0,-61,0,-52,0,-43,0,-34,0,-25,0,-16,0,-7,0,2,1,11,1,-1,-1,-1,-1,-1,-1,-1,-1,20,1,25,1,30,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,50,1,-1,-1,61,1,-1,-1,63,1,-107,1,-1,-1,-104,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-100,1,-1,-1,-37,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-33,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-28,1,-17,1,-12,1,7,2,11,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,20,2,30,2,-1,-1,-1,-1,-1,-1,40,2,44,2,48,2,52,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,56,2,62,2,27,91,90,0,7,0,13,0,27,91,51,103,0,27,91,72,27,91,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,27,91,66,0,27,91,72,0,27,91,68,0,27,91,67,0,27,91,65,0,27,91,80,0,27,91,77,0,27,91,49,49,109,0,27,91,53,109,0,27,91,49,109,0,27,91,56,109,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,27,91,49,48,109,0,27,91,48,59,49,48,109,0,27,91,109,0,27,91,109,0,27,91,76,0,8,0,27,91,66,0,27,91,72,0,27,91,76,0,27,91,68,0,27,91,67,0,27,91,65,0,13,27,91,83,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,27,91,52,105,0,27,91,53,105,0,37,112,49,37,99,27,91,37,112,50,37,123,49,125,37,45,37,100,98,0,27,91,37,105,37,112,49,37,100,100,0,10,0,27,91,48,59,49,48,37,63,37,112,49,37,116,59,55,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,51,37,116,59,55,37,59,37,63,37,112,52,37,116,59,53,37,59,37,63,37,112,54,37,116,59,49,37,59,37,63,37,112,55,37,116,59,56,37,59,37,63,37,112,57,37,116,59,49,49,37,59,109,0,27,72,0,27,91,73,0,43,16,44,17,45,24,46,25,48,-37,96,4,97,-79,102,-8,103,-15,104,-80,106,-39,107,-65,108,-38,109,-64,110,-59,111,126,112,-60,113,-60,114,-60,115,95,116,-61,117,-76,118,-63,119,-62,120,-77,121,-13,122,-14,123,-29,124,-40,125,-100,126,-2,0,27,91,90,0,27,91,49,75,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,37,91,59,48,49,50,51,52,53,54,55,56,57,93,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,91,51,37,112,49,37,100,109,0,27,91,52,37,112,49,37,100,109,0,27,40,66,0,27,41,66,0,27,42,66,0,27,43,66,0,27,91,49,49,109,0,27,91,49,48,109,0,1,0,0,0,0,0,1,0,3,0,1,0,0,0,65,88,0 }; -// conemu|ANIS X3.64 and Xterm 256 colors for ConEmu with libuv, +// conemu|ANSI X3.64 and Xterm 256 colors for ConEmu with libuv, // auto_right_margin, // back_color_erase, // backspaces_with_bs, @@ -101,6 +102,9 @@ static const int8_t ansi_terminfo[] = { // move_insert_mode, // move_standout_mode, // no_pad_char, +// AX, +// XF, +// XT, // columns#80, // init_tabs#8, // lines#24, @@ -289,8 +293,94 @@ static const int8_t ansi_terminfo[] = { // user7@, // user8@, // user9@, +// BD=\E[?2004l, +// BE=\E[?2004h, +// Cr@, +// Cs@, +// E3=\E[3J, +// Ms@, +// PE=\E[201~, +// PS=\E[200~, +// RV=\E[>c, +// Se=\E[2 q, +// Ss=\E[%p1%d q, +// XM@, +// XR=\E[>0q, +// fd=\E[?1004l, +// fe=\E[?1004h, +// kDC3@, +// kDC4@, +// kDC5@, +// kDC6@, +// kDC7@, +// kDN@, +// kDN3@, +// kDN4@, +// kDN5@, +// kDN6@, +// kDN7@, +// kEND3@, +// kEND4@, +// kEND5@, +// kEND6@, +// kEND7@, +// kHOM3@, +// kHOM4@, +// kHOM5@, +// kHOM6@, +// kHOM7@, +// kIC3@, +// kIC4@, +// kIC5@, +// kIC6@, +// kIC7@, +// kLFT3@, +// kLFT4@, +// kLFT5@, +// kLFT6@, +// kLFT7@, +// kNXT3@, +// kNXT4@, +// kNXT5@, +// kNXT6@, +// kNXT7@, +// kPRV3@, +// kPRV4@, +// kPRV5@, +// kPRV6@, +// kPRV7@, +// kRIT3@, +// kRIT4@, +// kRIT5@, +// kRIT6@, +// kRIT7@, +// kUP=\E[1;2A, +// kUP3@, +// kUP4@, +// kUP5@, +// kUP6@, +// kUP7@, +// ka2=\EOx, +// kb1=\EOt, +// kb3=\EOv, +// kc2=\EOr, +// kp5=\EOE, +// kpADD=\EOk, +// kpCMA=\EOl, +// kpDIV=\EOo, +// kpDOT=\EOn, +// kpMUL=\EOj, +// kpSUB=\EOm, +// kpZRO=\EOp, +// kxIN=\E[I, +// kxOUT=\E[O, +// rmxx@, +// rv=\E\[41;[1-6][0-9][0-9];0c, +// smxx@, +// xm@, +// xr=\EP>\|XTerm\([1-9][0-9]+\)\E\\, static const int8_t conemu_terminfo[] = { - 30,2,61,0,38,0,15,0,-99,1,61,3,99,111,110,101,109,117,124,65,78,73,83,32,88,51,46,54,52,32,97,110,100,32,88,116,101,114,109,32,50,53,54,32,99,111,108,111,114,115,32,102,111,114,32,67,111,110,69,109,117,32,119,105,116,104,32,108,105,98,117,118,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,-2,-1,0,0,2,0,4,0,-2,-1,21,0,29,0,33,0,37,0,-1,-1,48,0,65,0,69,0,73,0,80,0,-1,-1,82,0,89,0,-1,-1,93,0,-2,-1,97,0,101,0,-1,-1,-1,-1,-2,-1,-2,-1,105,0,110,0,-1,-1,-2,-1,-2,-1,-2,-1,-1,-1,119,0,124,0,-127,0,-122,0,-2,-1,-113,0,-108,0,-1,-1,-2,-1,-99,0,-93,0,-2,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-87,0,-1,-1,-83,0,-1,-1,-1,-1,-1,-1,-81,0,-1,-1,-76,0,-1,-1,-1,-1,-1,-1,-1,-1,-72,0,-67,0,-61,0,-56,0,-51,0,-46,0,-41,0,-35,0,-29,0,-23,0,-17,0,-12,0,-1,-1,-7,0,-1,-1,-3,0,2,1,7,1,11,1,18,1,-1,-1,25,1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,29,1,-1,-1,32,1,41,1,50,1,59,1,68,1,77,1,86,1,95,1,104,1,113,1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,122,1,-2,-1,-2,-1,-1,-1,-1,-1,-114,1,-111,1,-100,1,-97,1,-95,1,-92,1,-2,-1,-1,-1,-49,1,-1,-1,-1,-1,-1,-1,-1,-1,-47,1,-43,1,-39,1,-35,1,-31,1,-1,-1,-1,-1,-2,-1,-1,-1,-27,1,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-23,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-19,1,-14,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-10,1,-1,-1,-1,-1,-3,1,-1,-1,-1,-1,-1,-1,-1,-1,4,2,11,2,18,2,-1,-1,-1,-1,25,2,-1,-1,32,2,-1,-1,-1,-1,-1,-1,39,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,46,2,52,2,58,2,64,2,70,2,76,2,82,2,88,2,94,2,100,2,106,2,112,2,118,2,124,2,-126,2,-120,2,-114,2,-108,2,-102,2,-96,2,-90,2,-84,2,-78,2,-72,2,-66,2,-60,2,-54,2,-48,2,-42,2,-36,2,-29,2,-23,2,-17,2,-11,2,-5,2,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,1,3,6,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,-2,-1,13,3,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,22,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,27,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,33,3,47,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,72,27,91,50,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,27,91,66,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,50,53,104,0,27,91,67,0,27,91,65,0,27,91,80,0,27,91,77,0,27,91,49,109,0,27,91,63,49,48,52,57,104,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,27,91,48,109,0,27,91,63,49,48,52,57,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,91,76,0,8,0,27,91,51,126,0,27,91,66,0,27,91,91,65,0,27,91,50,49,126,0,27,91,91,66,0,27,91,91,67,0,27,91,91,68,0,27,91,91,69,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,91,68,0,27,91,54,126,0,27,91,53,126,0,27,91,67,0,27,91,49,59,50,66,0,27,91,49,59,50,65,0,27,91,65,0,27,69,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,37,112,49,37,99,27,91,37,112,50,37,123,49,125,37,45,37,100,98,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,54,37,116,59,49,37,59,109,0,9,0,27,79,119,0,27,79,121,0,27,91,71,0,27,79,113,0,27,79,115,0,27,91,90,0,27,79,69,0,27,91,52,126,0,27,79,77,0,27,91,51,59,50,126,0,27,91,52,59,50,126,0,27,91,49,59,50,126,0,27,91,50,59,50,126,0,27,91,49,59,50,68,0,27,91,54,59,50,126,0,27,91,53,59,50,126,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,50,53,126,0,27,91,50,54,126,0,27,91,50,56,126,0,27,91,50,57,126,0,27,91,51,49,126,0,27,91,51,50,126,0,27,91,51,51,126,0,27,91,51,52,126,0,27,91,50,51,36,0,27,91,50,52,36,0,27,91,49,49,94,0,27,91,49,50,94,0,27,91,49,51,94,0,27,91,49,52,94,0,27,91,49,53,94,0,27,91,49,55,94,0,27,91,49,56,94,0,27,91,49,57,94,0,27,91,50,48,94,0,27,91,50,49,94,0,27,91,50,51,94,0,27,91,50,52,94,0,27,91,50,53,94,0,27,91,50,54,94,0,27,91,50,56,94,0,27,91,50,57,94,0,27,91,51,49,94,0,27,91,49,59,54,83,0,27,91,51,50,94,0,27,91,51,51,94,0,27,91,51,52,94,0,27,91,50,51,64,0,27,91,50,52,64,0,27,91,49,75,0,27,91,63,54,57,108,0,27,91,51,57,59,52,57,109,0,27,91,51,109,0,27,91,50,51,109,0,27,91,51,56,59,53,59,37,112,49,37,100,109,0,27,91,52,56,59,53,59,37,112,49,37,100,109,0,0,3,0,0,0,86,0,117,0,121,2,1,1,1,0,0,0,9,0,-2,-1,-2,-1,18,0,-2,-1,23,0,30,0,37,0,42,0,48,0,-2,-1,58,0,64,0,73,0,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,82,0,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,89,0,93,0,97,0,101,0,105,0,109,0,113,0,117,0,121,0,125,0,-127,0,-123,0,-119,0,-115,0,-2,-1,-111,0,-2,-1,-2,-1,-86,0,0,0,3,0,6,0,9,0,12,0,15,0,18,0,21,0,24,0,27,0,30,0,33,0,36,0,39,0,42,0,45,0,48,0,51,0,54,0,59,0,64,0,69,0,74,0,79,0,83,0,88,0,93,0,98,0,103,0,108,0,114,0,120,0,126,0,-124,0,-118,0,-112,0,-106,0,-100,0,-94,0,-88,0,-83,0,-78,0,-73,0,-68,0,-63,0,-57,0,-51,0,-45,0,-39,0,-33,0,-27,0,-21,0,-15,0,-9,0,-3,0,3,1,9,1,15,1,21,1,27,1,33,1,39,1,45,1,51,1,57,1,61,1,66,1,71,1,76,1,81,1,86,1,90,1,94,1,98,1,102,1,106,1,112,1,118,1,124,1,-126,1,-120,1,-114,1,-108,1,-103,1,-97,1,-92,1,-89,1,-84,1,-81,1,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,91,51,74,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,91,62,99,0,27,91,50,32,113,0,27,91,37,112,49,37,100,32,113,0,27,91,62,48,113,0,27,91,63,49,48,48,52,108,0,27,91,63,49,48,48,52,104,0,27,91,49,59,50,65,0,27,79,120,0,27,79,116,0,27,79,118,0,27,79,114,0,27,79,69,0,27,79,107,0,27,79,108,0,27,79,111,0,27,79,110,0,27,79,106,0,27,79,109,0,27,79,112,0,27,91,73,0,27,91,79,0,27,92,91,52,49,59,91,49,45,54,93,91,48,45,57,93,91,48,45,57,93,59,48,99,0,27,80,62,92,124,88,84,101,114,109,92,40,91,49,45,57,93,91,48,45,57,93,43,92,41,27,92,92,0,65,88,0,88,70,0,88,84,0,66,68,0,66,69,0,67,114,0,67,115,0,69,51,0,77,115,0,80,69,0,80,83,0,82,86,0,83,101,0,83,115,0,88,77,0,88,82,0,102,100,0,102,101,0,107,68,67,51,0,107,68,67,52,0,107,68,67,53,0,107,68,67,54,0,107,68,67,55,0,107,68,78,0,107,68,78,51,0,107,68,78,52,0,107,68,78,53,0,107,68,78,54,0,107,68,78,55,0,107,69,78,68,51,0,107,69,78,68,52,0,107,69,78,68,53,0,107,69,78,68,54,0,107,69,78,68,55,0,107,72,79,77,51,0,107,72,79,77,52,0,107,72,79,77,53,0,107,72,79,77,54,0,107,72,79,77,55,0,107,73,67,51,0,107,73,67,52,0,107,73,67,53,0,107,73,67,54,0,107,73,67,55,0,107,76,70,84,51,0,107,76,70,84,52,0,107,76,70,84,53,0,107,76,70,84,54,0,107,76,70,84,55,0,107,78,88,84,51,0,107,78,88,84,52,0,107,78,88,84,53,0,107,78,88,84,54,0,107,78,88,84,55,0,107,80,82,86,51,0,107,80,82,86,52,0,107,80,82,86,53,0,107,80,82,86,54,0,107,80,82,86,55,0,107,82,73,84,51,0,107,82,73,84,52,0,107,82,73,84,53,0,107,82,73,84,54,0,107,82,73,84,55,0,107,85,80,0,107,85,80,51,0,107,85,80,52,0,107,85,80,53,0,107,85,80,54,0,107,85,80,55,0,107,97,50,0,107,98,49,0,107,98,51,0,107,99,50,0,107,112,53,0,107,112,65,68,68,0,107,112,67,77,65,0,107,112,68,73,86,0,107,112,68,79,84,0,107,112,77,85,76,0,107,112,83,85,66,0,107,112,90,82,79,0,107,120,73,78,0,107,120,79,85,84,0,114,109,120,120,0,114,118,0,115,109,120,120,0,120,109,0,120,114,0 + 30,2,61,0,38,0,15,0,-99,1,61,3,99,111,110,101,109,117,124,65,78,83,73,32,88,51,46,54,52,32,97,110,100,32,88,116,101,114,109,32,50,53,54,32,99,111,108,111,114,115,32,102,111,114,32,67,111,110,69,109,117,32,119,105,116,104,32,108,105,98,117,118,0,0,1,0,0,0,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,-2,-1,0,0,2,0,4,0,-2,-1,21,0,29,0,33,0,37,0,-1,-1,48,0,65,0,69,0,73,0,80,0,-1,-1,82,0,89,0,-1,-1,93,0,-2,-1,97,0,101,0,-1,-1,-1,-1,-2,-1,-2,-1,105,0,110,0,-1,-1,-2,-1,-2,-1,-2,-1,-1,-1,119,0,124,0,-127,0,-122,0,-2,-1,-113,0,-108,0,-1,-1,-2,-1,-99,0,-93,0,-2,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-87,0,-1,-1,-83,0,-1,-1,-1,-1,-1,-1,-81,0,-1,-1,-76,0,-1,-1,-1,-1,-1,-1,-1,-1,-72,0,-67,0,-61,0,-56,0,-51,0,-46,0,-41,0,-35,0,-29,0,-23,0,-17,0,-12,0,-1,-1,-7,0,-1,-1,-3,0,2,1,7,1,11,1,18,1,-1,-1,25,1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,29,1,-1,-1,32,1,41,1,50,1,59,1,68,1,77,1,86,1,95,1,104,1,113,1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,122,1,-2,-1,-2,-1,-1,-1,-1,-1,-114,1,-111,1,-100,1,-97,1,-95,1,-92,1,-2,-1,-1,-1,-49,1,-1,-1,-1,-1,-1,-1,-1,-1,-47,1,-43,1,-39,1,-35,1,-31,1,-1,-1,-1,-1,-2,-1,-1,-1,-27,1,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-23,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-19,1,-14,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-10,1,-1,-1,-1,-1,-3,1,-1,-1,-1,-1,-1,-1,-1,-1,4,2,11,2,18,2,-1,-1,-1,-1,25,2,-1,-1,32,2,-1,-1,-1,-1,-1,-1,39,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,46,2,52,2,58,2,64,2,70,2,76,2,82,2,88,2,94,2,100,2,106,2,112,2,118,2,124,2,-126,2,-120,2,-114,2,-108,2,-102,2,-96,2,-90,2,-84,2,-78,2,-72,2,-66,2,-60,2,-54,2,-48,2,-42,2,-36,2,-29,2,-23,2,-17,2,-11,2,-5,2,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,1,3,6,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,-2,-1,13,3,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,22,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,27,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,33,3,47,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,72,27,91,50,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,27,91,66,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,50,53,104,0,27,91,67,0,27,91,65,0,27,91,80,0,27,91,77,0,27,91,49,109,0,27,91,63,49,48,52,57,104,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,27,91,48,109,0,27,91,63,49,48,52,57,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,91,76,0,8,0,27,91,51,126,0,27,91,66,0,27,91,91,65,0,27,91,50,49,126,0,27,91,91,66,0,27,91,91,67,0,27,91,91,68,0,27,91,91,69,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,91,68,0,27,91,54,126,0,27,91,53,126,0,27,91,67,0,27,91,49,59,50,66,0,27,91,49,59,50,65,0,27,91,65,0,27,69,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,37,112,49,37,99,27,91,37,112,50,37,123,49,125,37,45,37,100,98,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,54,37,116,59,49,37,59,109,0,9,0,27,79,119,0,27,79,121,0,27,91,71,0,27,79,113,0,27,79,115,0,27,91,90,0,27,79,69,0,27,91,52,126,0,27,79,77,0,27,91,51,59,50,126,0,27,91,52,59,50,126,0,27,91,49,59,50,126,0,27,91,50,59,50,126,0,27,91,49,59,50,68,0,27,91,54,59,50,126,0,27,91,53,59,50,126,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,50,53,126,0,27,91,50,54,126,0,27,91,50,56,126,0,27,91,50,57,126,0,27,91,51,49,126,0,27,91,51,50,126,0,27,91,51,51,126,0,27,91,51,52,126,0,27,91,50,51,36,0,27,91,50,52,36,0,27,91,49,49,94,0,27,91,49,50,94,0,27,91,49,51,94,0,27,91,49,52,94,0,27,91,49,53,94,0,27,91,49,55,94,0,27,91,49,56,94,0,27,91,49,57,94,0,27,91,50,48,94,0,27,91,50,49,94,0,27,91,50,51,94,0,27,91,50,52,94,0,27,91,50,53,94,0,27,91,50,54,94,0,27,91,50,56,94,0,27,91,50,57,94,0,27,91,51,49,94,0,27,91,49,59,54,83,0,27,91,51,50,94,0,27,91,51,51,94,0,27,91,51,52,94,0,27,91,50,51,64,0,27,91,50,52,64,0,27,91,49,75,0,27,91,63,54,57,108,0,27,91,51,57,59,52,57,109,0,27,91,51,109,0,27,91,50,51,109,0,27,91,51,56,59,53,59,37,112,49,37,100,109,0,27,91,52,56,59,53,59,37,112,49,37,100,109,0,0,3,0,0,0,86,0,117,0,121,2,1,1,1,0,0,0,9,0,-2,-1,-2,-1,18,0,-2,-1,23,0,30,0,37,0,42,0,48,0,-2,-1,58,0,64,0,73,0,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,82,0,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,89,0,93,0,97,0,101,0,105,0,109,0,113,0,117,0,121,0,125,0,-127,0,-123,0,-119,0,-115,0,-2,-1,-111,0,-2,-1,-2,-1,-86,0,0,0,3,0,6,0,9,0,12,0,15,0,18,0,21,0,24,0,27,0,30,0,33,0,36,0,39,0,42,0,45,0,48,0,51,0,54,0,59,0,64,0,69,0,74,0,79,0,83,0,88,0,93,0,98,0,103,0,108,0,114,0,120,0,126,0,-124,0,-118,0,-112,0,-106,0,-100,0,-94,0,-88,0,-83,0,-78,0,-73,0,-68,0,-63,0,-57,0,-51,0,-45,0,-39,0,-33,0,-27,0,-21,0,-15,0,-9,0,-3,0,3,1,9,1,15,1,21,1,27,1,33,1,39,1,45,1,51,1,57,1,61,1,66,1,71,1,76,1,81,1,86,1,90,1,94,1,98,1,102,1,106,1,112,1,118,1,124,1,-126,1,-120,1,-114,1,-108,1,-103,1,-97,1,-92,1,-89,1,-84,1,-81,1,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,91,51,74,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,91,62,99,0,27,91,50,32,113,0,27,91,37,112,49,37,100,32,113,0,27,91,62,48,113,0,27,91,63,49,48,48,52,108,0,27,91,63,49,48,48,52,104,0,27,91,49,59,50,65,0,27,79,120,0,27,79,116,0,27,79,118,0,27,79,114,0,27,79,69,0,27,79,107,0,27,79,108,0,27,79,111,0,27,79,110,0,27,79,106,0,27,79,109,0,27,79,112,0,27,91,73,0,27,91,79,0,27,92,91,52,49,59,91,49,45,54,93,91,48,45,57,93,91,48,45,57,93,59,48,99,0,27,80,62,92,124,88,84,101,114,109,92,40,91,49,45,57,93,91,48,45,57,93,43,92,41,27,92,92,0,65,88,0,88,70,0,88,84,0,66,68,0,66,69,0,67,114,0,67,115,0,69,51,0,77,115,0,80,69,0,80,83,0,82,86,0,83,101,0,83,115,0,88,77,0,88,82,0,102,100,0,102,101,0,107,68,67,51,0,107,68,67,52,0,107,68,67,53,0,107,68,67,54,0,107,68,67,55,0,107,68,78,0,107,68,78,51,0,107,68,78,52,0,107,68,78,53,0,107,68,78,54,0,107,68,78,55,0,107,69,78,68,51,0,107,69,78,68,52,0,107,69,78,68,53,0,107,69,78,68,54,0,107,69,78,68,55,0,107,72,79,77,51,0,107,72,79,77,52,0,107,72,79,77,53,0,107,72,79,77,54,0,107,72,79,77,55,0,107,73,67,51,0,107,73,67,52,0,107,73,67,53,0,107,73,67,54,0,107,73,67,55,0,107,76,70,84,51,0,107,76,70,84,52,0,107,76,70,84,53,0,107,76,70,84,54,0,107,76,70,84,55,0,107,78,88,84,51,0,107,78,88,84,52,0,107,78,88,84,53,0,107,78,88,84,54,0,107,78,88,84,55,0,107,80,82,86,51,0,107,80,82,86,52,0,107,80,82,86,53,0,107,80,82,86,54,0,107,80,82,86,55,0,107,82,73,84,51,0,107,82,73,84,52,0,107,82,73,84,53,0,107,82,73,84,54,0,107,82,73,84,55,0,107,85,80,0,107,85,80,51,0,107,85,80,52,0,107,85,80,53,0,107,85,80,54,0,107,85,80,55,0,107,97,50,0,107,98,49,0,107,98,51,0,107,99,50,0,107,112,53,0,107,112,65,68,68,0,107,112,67,77,65,0,107,112,68,73,86,0,107,112,68,79,84,0,107,112,77,85,76,0,107,112,83,85,66,0,107,112,90,82,79,0,107,120,73,78,0,107,120,79,85,84,0,114,109,120,120,0,114,118,0,115,109,120,120,0,120,109,0,120,114,0 }; // cygwin|ANSI emulation for Cygwin, @@ -672,6 +762,43 @@ static const int8_t interix_8colour_terminfo[] = { // user7=\E[6n, // user8=\E[?%[;0123456789]c, // user9=\E[c, +// BD=\E[?2004l, +// BE=\E[?2004h, +// PE=\E[201~, +// PS=\E[200~, +// TS=\E]2;, +// XM=\E[?1000%?%p1%{1}%=%th%el%;, +// kDN3=\E\E[B, +// kDN4=\E[1;10B, +// kDN5=\E[1;5B, +// kDN6=\E[1;6B, +// kEND3=\E[1;9F, +// kEND4=\E[1;10F, +// kEND5=\E[1;5F, +// kEND6=\E[1;6F, +// kEND7=\E[1;13F, +// kEND8=\E[1;14F, +// kHOM3=\E[1;9H, +// kHOM4=\E[1;10H, +// kHOM5=\E[1;5H, +// kHOM6=\E[1;6H, +// kHOM7=\E[1;13H, +// kHOM8=\E[1;14H, +// kLFT3=\E\E[D, +// kLFT4=\E[1;10D, +// kLFT5=\E[1;5D, +// kLFT6=\E[1;6D, +// kNXT3=\E\E[6~, +// kPRV3=\E\E[5~, +// kRIT3=\E\E[C, +// kRIT4=\E[1;10C, +// kRIT5=\E[1;5C, +// kRIT6=\E[1;6C, +// kUP3=\E\E[A, +// kUP4=\E[1;10A, +// kUP5=\E[1;5A, +// kUP6=\E[1;6A, +// xm=\E[M%?%p4%t%p3%e%{3}%;%' '%+%c%p2%'\041'%+%c%p1%'\041'%+%c, static const int8_t iterm_256colour_terminfo[] = { 30,2,49,0,29,0,15,0,105,1,-29,3,105,84,101,114,109,50,46,97,112,112,124,105,116,101,114,109,50,124,116,101,114,109,105,110,97,108,32,101,109,117,108,97,116,111,114,32,102,111,114,32,77,97,99,32,79,83,32,88,0,0,1,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,1,0,0,1,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,50,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,0,0,4,0,6,0,8,0,25,0,30,0,37,0,41,0,45,0,-1,-1,56,0,73,0,75,0,79,0,86,0,-1,-1,88,0,95,0,-1,-1,99,0,-1,-1,103,0,107,0,111,0,-1,-1,117,0,119,0,124,0,-127,0,-1,-1,-109,0,-104,0,-1,-1,-1,-1,-99,0,-94,0,-89,0,-1,-1,-84,0,-82,0,-77,0,-1,-1,-59,0,-54,0,-48,0,-42,0,-1,-1,-24,0,-1,-1,-1,-1,-1,-1,-1,-1,-22,0,-18,0,-1,-1,-14,0,-1,-1,-1,-1,-1,-1,-12,0,-1,-1,-7,0,-1,-1,-1,-1,-1,-1,-1,-1,-3,0,1,1,7,1,11,1,15,1,19,1,25,1,31,1,37,1,43,1,49,1,-1,-1,-1,-1,53,1,-1,-1,57,1,62,1,67,1,71,1,78,1,-1,-1,85,1,89,1,97,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,105,1,-1,-1,108,1,117,1,126,1,-121,1,-112,1,-103,1,-94,1,-85,1,-76,1,-67,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-58,1,-1,-1,-1,-1,-32,1,-29,1,-18,1,-15,1,-13,1,-10,1,68,2,-1,-1,71,2,73,2,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-1,-1,-1,-1,78,2,-1,-1,-127,2,-1,-1,-1,-1,-123,2,-117,2,-1,-1,-1,-1,-111,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-104,2,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-100,2,-1,-1,-1,-1,-1,-1,-1,-1,-93,2,-1,-1,-86,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-79,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-72,2,-66,2,-60,2,-53,2,-46,2,-39,2,-32,2,-24,2,-16,2,-8,2,0,3,8,3,16,3,24,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,37,3,48,3,53,3,72,3,76,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,85,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,90,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,96,3,-1,-1,-1,-1,-1,-1,100,3,-93,3,27,91,90,0,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,51,103,0,27,91,72,27,91,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,10,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,50,53,104,0,27,91,67,0,27,91,65,0,27,91,80,0,27,91,77,0,27,93,50,59,7,0,14,0,27,91,53,109,0,27,91,49,109,0,27,91,63,49,48,52,57,104,27,91,50,50,59,48,59,48,116,0,27,91,50,109,0,27,91,52,104,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,15,0,27,91,109,15,0,27,91,63,49,48,52,57,108,27,91,50,51,59,48,59,48,116,0,27,91,52,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,91,63,53,104,36,60,50,48,48,47,62,27,91,63,53,108,0,7,0,27,91,64,0,27,91,76,0,127,0,27,91,51,126,0,27,79,66,0,27,79,80,0,27,91,50,49,126,0,27,79,81,0,27,79,82,0,27,79,83,0,27,91,49,53,126,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,79,72,0,27,79,68,0,27,91,54,126,0,27,91,53,126,0,27,79,67,0,27,91,49,59,50,66,0,27,91,49,59,50,65,0,27,79,65,0,27,91,63,49,108,27,62,0,27,91,63,49,104,27,61,0,27,69,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,27,91,33,112,27,91,63,51,59,52,108,27,91,52,108,27,62,27,91,63,49,48,48,48,108,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,54,37,116,59,49,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,52,37,116,59,53,37,59,37,63,37,112,53,37,116,59,50,37,59,109,37,63,37,112,57,37,116,14,37,101,15,37,59,0,27,72,0,9,0,27,93,50,59,0,96,96,97,97,102,102,103,103,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,0,27,91,90,0,27,91,63,55,104,0,27,91,63,55,108,0,27,40,66,27,41,48,0,27,79,70,0,27,91,49,59,50,70,0,27,91,49,59,50,72,0,27,91,49,59,50,68,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,49,59,50,80,0,27,91,49,59,50,81,0,27,91,49,59,50,82,0,27,91,49,59,50,83,0,27,91,49,53,59,50,126,0,27,91,49,55,59,50,126,0,27,91,49,56,59,50,126,0,27,91,49,57,59,50,126,0,27,91,50,48,59,50,126,0,27,91,50,49,59,50,126,0,27,91,50,51,59,50,126,0,27,91,50,52,59,50,126,0,27,91,49,75,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,37,91,59,48,49,50,51,52,53,54,55,56,57,93,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,91,51,109,0,27,91,50,51,109,0,27,91,77,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,0,0,0,0,0,37,0,74,0,7,2,0,0,9,0,18,0,25,0,32,0,37,0,64,0,69,0,77,0,84,0,91,0,98,0,106,0,113,0,120,0,-128,0,-120,0,-113,0,-105,0,-98,0,-91,0,-83,0,-75,0,-70,0,-62,0,-55,0,-48,0,-42,0,-36,0,-31,0,-23,0,-16,0,-9,0,-4,0,4,1,11,1,18,1,0,0,3,0,6,0,9,0,12,0,15,0,18,0,23,0,28,0,33,0,38,0,44,0,50,0,56,0,62,0,68,0,74,0,80,0,86,0,92,0,98,0,104,0,110,0,116,0,122,0,-128,0,-122,0,-116,0,-110,0,-104,0,-98,0,-92,0,-86,0,-81,0,-76,0,-71,0,-66,0,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,93,50,59,0,27,91,63,49,48,48,48,37,63,37,112,49,37,123,49,125,37,61,37,116,104,37,101,108,37,59,0,27,27,91,66,0,27,91,49,59,49,48,66,0,27,91,49,59,53,66,0,27,91,49,59,54,66,0,27,91,49,59,57,70,0,27,91,49,59,49,48,70,0,27,91,49,59,53,70,0,27,91,49,59,54,70,0,27,91,49,59,49,51,70,0,27,91,49,59,49,52,70,0,27,91,49,59,57,72,0,27,91,49,59,49,48,72,0,27,91,49,59,53,72,0,27,91,49,59,54,72,0,27,91,49,59,49,51,72,0,27,91,49,59,49,52,72,0,27,27,91,68,0,27,91,49,59,49,48,68,0,27,91,49,59,53,68,0,27,91,49,59,54,68,0,27,27,91,54,126,0,27,27,91,53,126,0,27,27,91,67,0,27,91,49,59,49,48,67,0,27,91,49,59,53,67,0,27,91,49,59,54,67,0,27,27,91,65,0,27,91,49,59,49,48,65,0,27,91,49,59,53,65,0,27,91,49,59,54,65,0,27,91,77,37,63,37,112,52,37,116,37,112,51,37,101,37,123,51,125,37,59,37,39,32,39,37,43,37,99,37,112,50,37,39,33,39,37,43,37,99,37,112,49,37,39,33,39,37,43,37,99,0,66,68,0,66,69,0,80,69,0,80,83,0,84,83,0,88,77,0,107,68,78,51,0,107,68,78,52,0,107,68,78,53,0,107,68,78,54,0,107,69,78,68,51,0,107,69,78,68,52,0,107,69,78,68,53,0,107,69,78,68,54,0,107,69,78,68,55,0,107,69,78,68,56,0,107,72,79,77,51,0,107,72,79,77,52,0,107,72,79,77,53,0,107,72,79,77,54,0,107,72,79,77,55,0,107,72,79,77,56,0,107,76,70,84,51,0,107,76,70,84,52,0,107,76,70,84,53,0,107,76,70,84,54,0,107,78,88,84,51,0,107,80,82,86,51,0,107,82,73,84,51,0,107,82,73,84,52,0,107,82,73,84,53,0,107,82,73,84,54,0,107,85,80,51,0,107,85,80,52,0,107,85,80,53,0,107,85,80,54,0,120,109,0 }; @@ -685,10 +812,12 @@ static const int8_t iterm_256colour_terminfo[] = { // move_insert_mode, // move_standout_mode, // xon_xoff, +// AX, // init_tabs#8, // max_colors#8, // max_pairs#64, // no_color_video#18, +// U8#1, // acs_chars=++\054\054--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, // bell=^G, // carriage_return=\r, @@ -794,6 +923,8 @@ static const int8_t iterm_256colour_terminfo[] = { // user7=\E[6n, // user8=\E[?6c, // user9=\E[c, +// E3=\E[3J, +// kcbt2=\E[Z, static const int8_t linux_16colour_terminfo[] = { 26,1,20,0,29,0,16,0,125,1,66,3,108,105,110,117,120,124,76,105,110,117,120,32,99,111,110,115,111,108,101,0,0,1,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,-1,-1,8,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,0,64,0,18,0,-1,-1,0,0,2,0,4,0,21,0,26,0,33,0,37,0,41,0,-1,-1,52,0,69,0,71,0,75,0,87,0,-1,-1,89,0,101,0,-1,-1,105,0,109,0,121,0,125,0,-1,-1,-1,-1,-127,0,-125,0,-120,0,-1,-1,-1,-1,-115,0,-110,0,-1,-1,-1,-1,-105,0,-100,0,-95,0,-90,0,-81,0,-79,0,-1,-1,-1,-1,-74,0,-69,0,-63,0,-57,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-39,0,-35,0,-1,-1,-31,0,-1,-1,-1,-1,-1,-1,-29,0,-1,-1,-24,0,-1,-1,-1,-1,-1,-1,-1,-1,-20,0,-15,0,-9,0,-4,0,1,1,6,1,11,1,17,1,23,1,29,1,35,1,40,1,-1,-1,45,1,-1,-1,49,1,54,1,59,1,-1,-1,-1,-1,-1,-1,63,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,67,1,-1,-1,70,1,79,1,88,1,97,1,-1,-1,106,1,115,1,124,1,-1,-1,-123,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-114,1,-1,-1,-1,-1,-1,-1,-108,1,-105,1,-94,1,-91,1,-89,1,-86,1,1,2,-1,-1,4,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,6,2,-1,-1,-1,-1,-1,-1,-1,-1,10,2,-1,-1,75,2,-1,-1,-1,-1,78,2,84,2,-1,-1,-1,-1,90,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,94,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,99,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,101,2,107,2,113,2,119,2,125,2,-125,2,-119,2,-113,2,-107,2,-101,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-95,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-90,2,-79,2,-74,2,-68,2,-64,2,-55,2,-51,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,30,3,-1,-1,-1,-1,-1,-1,34,3,44,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,54,3,60,3,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,51,103,0,27,91,72,27,91,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,10,0,27,91,72,0,27,91,63,50,53,108,27,91,63,49,99,0,8,0,27,91,63,50,53,104,27,91,63,48,99,0,27,91,67,0,27,91,65,0,27,91,63,50,53,104,27,91,63,56,99,0,27,91,80,0,27,91,77,0,14,0,27,91,53,109,0,27,91,49,109,0,27,91,50,109,0,27,91,52,104,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,15,0,27,91,109,15,0,27,91,52,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,91,63,53,104,36,60,50,48,48,47,62,27,91,63,53,108,0,27,91,64,0,27,91,76,0,127,0,27,91,51,126,0,27,91,66,0,27,91,91,65,0,27,91,50,49,126,0,27,91,91,66,0,27,91,91,67,0,27,91,91,68,0,27,91,91,69,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,91,68,0,27,91,54,126,0,27,91,53,126,0,27,91,67,0,27,91,65,0,13,10,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,65,0,27,99,27,93,82,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,59,49,48,37,63,37,112,49,37,116,59,55,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,51,37,116,59,55,37,59,37,63,37,112,52,37,116,59,53,37,59,37,63,37,112,53,37,116,59,50,37,59,37,63,37,112,54,37,116,59,49,37,59,109,37,63,37,112,57,37,116,14,37,101,15,37,59,0,27,72,0,9,0,27,91,71,0,43,43,44,44,45,45,46,46,48,48,96,96,97,97,102,102,103,103,104,104,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,0,27,9,0,27,91,63,55,104,0,27,91,63,55,108,0,27,41,48,0,27,91,52,126,0,26,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,50,53,126,0,27,91,50,54,126,0,27,91,50,56,126,0,27,91,50,57,126,0,27,91,51,49,126,0,27,91,51,50,126,0,27,91,51,51,126,0,27,91,51,52,126,0,27,91,49,75,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,54,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,93,82,0,27,93,80,37,112,49,37,120,37,112,50,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,48,50,120,37,112,51,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,48,50,120,37,112,52,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,48,50,120,0,27,91,77,0,27,91,51,37,112,49,37,100,109,0,27,91,52,37,112,49,37,100,109,0,27,91,49,49,109,0,27,91,49,48,109,0,1,0,1,0,2,0,6,0,24,0,1,0,1,0,0,0,5,0,0,0,3,0,6,0,9,0,27,91,51,74,0,27,91,90,0,65,88,0,85,56,0,69,51,0,107,99,98,116,50,0 }; @@ -807,10 +938,12 @@ static const int8_t linux_16colour_terminfo[] = { // move_insert_mode, // move_standout_mode, // xon_xoff, +// XT, // init_tabs#8, // max_colors#0x100, // max_pairs#0x10000, // no_color_video#22, +// U8#1, // acs_chars=``aaffggjjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, // back_tab=\E[Z, // bell=^G, @@ -935,6 +1068,36 @@ static const int8_t linux_16colour_terminfo[] = { // user7=\E[6n, // user8=\E[?6c, // user9=\E[c, +// BD=\E[?2004l, +// BE=\E[?2004h, +// E3=\E[3J, +// PE=\E[201~, +// PS=\E[200~, +// TS=\E]0;, +// XM=\E[?1006;1000%?%p1%{1}%=%th%el%;, +// kDN5=\E[B, +// kLFT5=\E[D, +// kRIT5=\E[C, +// kUP5=\E[A, +// kp1=\EOq, +// kp2=\EOr, +// kp3=\EOs, +// kp4=\EOt, +// kp5=\EOu, +// kp6=\EOv, +// kp7=\EOw, +// kp8=\EOx, +// kp9=\EOy, +// kpADD=\EOl, +// kpDIV=\EOQ, +// kpDOT=\EOn, +// kpMUL=\EOR, +// kpNUM=\EOP, +// kpSUB=\EOS, +// kpZRO=\EOp, +// rmxx=\E[29m, +// smxx=\E[9m, +// xm=\E[<%i%p3%d;%p1%d;%p2%d;%?%p4%tM%em%;, static const int8_t putty_256colour_terminfo[] = { 30,2,48,0,29,0,16,0,125,1,-70,4,112,117,116,116,121,45,50,53,54,99,111,108,111,114,124,80,117,84,84,89,32,48,46,53,56,32,119,105,116,104,32,120,116,101,114,109,32,50,53,54,45,99,111,108,111,114,115,0,1,1,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,-1,-1,-1,-1,8,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,22,0,0,0,0,0,4,0,6,0,8,0,25,0,30,0,37,0,41,0,45,0,-1,-1,56,0,73,0,76,0,80,0,87,0,-1,-1,89,0,96,0,-1,-1,100,0,-1,-1,103,0,107,0,111,0,-1,-1,117,0,119,0,124,0,-127,0,-1,-1,-1,-1,-118,0,-1,-1,-1,-1,-113,0,-108,0,-103,0,-98,0,-89,0,-87,0,-82,0,-1,-1,-73,0,-68,0,-62,0,-56,0,-1,-1,-38,0,-1,-1,-36,0,-1,-1,-1,-1,-1,-1,-2,0,-1,-1,2,1,-1,-1,-1,-1,-1,-1,4,1,-1,-1,9,1,-1,-1,-1,-1,-1,-1,13,1,17,1,23,1,29,1,35,1,41,1,47,1,53,1,59,1,65,1,71,1,77,1,82,1,-1,-1,87,1,-1,-1,91,1,96,1,101,1,105,1,109,1,-1,-1,113,1,117,1,125,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-123,1,-1,-1,-120,1,-111,1,-102,1,-1,-1,-93,1,-84,1,-75,1,-66,1,-57,1,-48,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-39,1,-1,-1,-19,1,-1,-1,-1,-1,14,2,17,2,28,2,31,2,33,2,36,2,108,2,-1,-1,111,2,113,2,-1,-1,-1,-1,-1,-1,118,2,122,2,126,2,-126,2,-122,2,-1,-1,-1,-1,-118,2,-1,-1,-67,2,-1,-1,-1,-1,-63,2,-57,2,-1,-1,-1,-1,-51,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-44,2,-39,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-35,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-33,2,-27,2,-21,2,-15,2,-9,2,-3,2,3,3,9,3,15,3,21,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,27,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,32,3,43,3,48,3,54,3,58,3,67,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,71,3,-1,-1,-1,-1,-1,-1,75,3,-118,3,-1,-1,-1,-1,-1,-1,-54,3,-48,3,-42,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-36,3,-82,4,-76,4,27,91,90,0,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,51,103,0,27,91,72,27,91,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,27,68,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,50,53,104,0,27,91,67,0,27,77,0,27,91,80,0,27,91,77,0,27,93,48,59,7,0,14,0,27,91,53,109,0,27,91,49,109,0,27,91,63,49,48,52,57,104,0,27,91,52,104,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,15,0,27,91,109,15,0,27,91,63,49,48,52,57,108,0,27,91,52,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,91,63,53,104,36,60,49,48,48,47,62,27,91,63,53,108,0,7,0,27,55,27,91,114,27,91,109,27,91,63,55,104,27,91,63,49,59,52,59,54,108,27,91,52,108,27,56,27,62,27,93,82,0,27,91,76,0,127,0,27,91,51,126,0,27,79,66,0,27,79,121,0,27,91,49,49,126,0,27,91,50,49,126,0,27,91,49,50,126,0,27,91,49,51,126,0,27,91,49,52,126,0,27,91,49,53,126,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,79,68,0,27,91,54,126,0,27,91,53,126,0,27,79,67,0,27,91,66,0,27,91,65,0,27,79,65,0,27,91,63,49,108,27,62,0,27,91,63,49,104,27,61,0,13,10,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,37,112,49,37,99,27,91,37,112,50,37,123,49,125,37,45,37,100,98,0,27,60,27,91,34,112,27,91,53,48,59,54,34,112,27,99,27,91,63,51,108,27,93,82,27,91,63,49,48,48,48,108,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,49,37,112,54,37,124,37,116,59,49,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,52,37,116,59,53,37,59,109,37,63,37,112,57,37,116,14,37,101,15,37,59,0,27,72,0,9,0,27,93,48,59,0,27,79,113,0,27,79,115,0,27,79,114,0,27,79,112,0,27,79,110,0,96,96,97,97,102,102,103,103,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,0,27,91,90,0,27,91,63,55,104,0,27,91,63,55,108,0,27,40,66,27,41,48,0,27,91,52,126,0,27,79,77,0,26,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,50,53,126,0,27,91,50,54,126,0,27,91,50,56,126,0,27,91,50,57,126,0,27,91,51,49,126,0,27,91,51,50,126,0,27,91,51,51,126,0,27,91,51,52,126,0,27,91,49,75,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,54,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,93,82,0,27,91,60,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,49,48,109,0,27,91,49,49,109,0,27,91,49,50,109,0,37,63,37,112,49,37,123,56,125,37,61,37,116,27,37,37,71,-30,-105,-104,27,37,37,64,37,101,37,112,49,37,123,49,48,125,37,61,37,116,27,37,37,71,-30,-105,-103,27,37,37,64,37,101,37,112,49,37,123,49,50,125,37,61,37,116,27,37,37,71,-30,-103,-128,27,37,37,64,37,101,37,112,49,37,123,49,51,125,37,61,37,116,27,37,37,71,-30,-103,-86,27,37,37,64,37,101,37,112,49,37,123,49,52,125,37,61,37,116,27,37,37,71,-30,-103,-85,27,37,37,64,37,101,37,112,49,37,123,49,53,125,37,61,37,116,27,37,37,71,-30,-104,-68,27,37,37,64,37,101,37,112,49,37,123,50,55,125,37,61,37,116,27,37,37,71,-30,-122,-112,27,37,37,64,37,101,37,112,49,37,123,49,53,53,125,37,61,37,116,27,37,37,71,-32,-126,-94,27,37,37,64,37,101,37,112,49,37,99,37,59,0,27,91,49,49,109,0,27,91,49,48,109,0,1,0,1,0,30,0,62,0,86,1,1,0,1,0,0,0,0,0,9,0,18,0,23,0,30,0,37,0,42,0,74,0,78,0,82,0,86,0,90,0,94,0,98,0,102,0,106,0,110,0,114,0,118,0,122,0,126,0,-126,0,-122,0,-118,0,-114,0,-110,0,-106,0,-102,0,-96,0,-91,0,0,0,3,0,6,0,9,0,12,0,15,0,18,0,21,0,24,0,27,0,32,0,38,0,44,0,49,0,53,0,57,0,61,0,65,0,69,0,73,0,77,0,81,0,85,0,91,0,97,0,103,0,109,0,115,0,121,0,127,0,-124,0,-119,0,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,91,51,74,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,93,48,59,0,27,91,63,49,48,48,54,59,49,48,48,48,37,63,37,112,49,37,123,49,125,37,61,37,116,104,37,101,108,37,59,0,27,91,66,0,27,91,68,0,27,91,67,0,27,91,65,0,27,79,113,0,27,79,114,0,27,79,115,0,27,79,116,0,27,79,117,0,27,79,118,0,27,79,119,0,27,79,120,0,27,79,121,0,27,79,108,0,27,79,81,0,27,79,110,0,27,79,82,0,27,79,80,0,27,79,83,0,27,79,112,0,27,91,50,57,109,0,27,91,57,109,0,27,91,60,37,105,37,112,51,37,100,59,37,112,49,37,100,59,37,112,50,37,100,59,37,63,37,112,52,37,116,77,37,101,109,37,59,0,88,84,0,85,56,0,66,68,0,66,69,0,69,51,0,80,69,0,80,83,0,84,83,0,88,77,0,107,68,78,53,0,107,76,70,84,53,0,107,82,73,84,53,0,107,85,80,53,0,107,112,49,0,107,112,50,0,107,112,51,0,107,112,52,0,107,112,53,0,107,112,54,0,107,112,55,0,107,112,56,0,107,112,57,0,107,112,65,68,68,0,107,112,68,73,86,0,107,112,68,79,84,0,107,112,77,85,76,0,107,112,78,85,77,0,107,112,83,85,66,0,107,112,90,82,79,0,114,109,120,120,0,115,109,120,120,0,120,109,0 }; @@ -949,6 +1112,8 @@ static const int8_t putty_256colour_terminfo[] = { // move_insert_mode, // move_standout_mode, // xon_xoff, +// AX, +// XT, // columns#80, // init_tabs#8, // lines#24, @@ -1099,6 +1264,28 @@ static const int8_t putty_256colour_terminfo[] = { // user7=\E[6n, // user8=\E[?1;2c, // user9=\E[c, +// kDC5=\E[3\136, +// kDC6=\E[3@, +// kDN=\E[b, +// kDN5=\EOb, +// kEND5=\E[8\136, +// kEND6=\E[8@, +// kHOM5=\E[7\136, +// kHOM6=\E[7@, +// kIC5=\E[2\136, +// kIC6=\E[2@, +// kLFT5=\EOd, +// kNXT5=\E[6\136, +// kNXT6=\E[6@, +// kPRV5=\E[5\136, +// kPRV6=\E[5@, +// kRIT5=\EOc, +// kUP=\E[a, +// kUP5=\EOa, +// ka2=\EOx, +// kb1=\EOt, +// kb3=\EOv, +// kc2=\EOr, static const int8_t rxvt_256colour_terminfo[] = { 30,2,47,0,38,0,15,0,110,1,-35,4,114,120,118,116,45,50,53,54,99,111,108,111,114,124,114,120,118,116,32,50,46,55,46,57,32,119,105,116,104,32,120,116,101,114,109,32,50,53,54,45,99,111,108,111,114,115,0,0,1,0,0,1,1,0,0,0,0,0,0,0,1,1,0,0,0,0,0,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,-1,-1,0,0,2,0,4,0,21,0,26,0,34,0,38,0,42,0,-1,-1,53,0,70,0,72,0,76,0,83,0,-1,-1,85,0,92,0,-1,-1,96,0,-1,-1,-1,-1,100,0,-1,-1,-1,-1,104,0,106,0,111,0,116,0,-1,-1,-1,-1,125,0,-1,-1,-1,-1,-126,0,-121,0,-116,0,-1,-1,-111,0,-109,0,-104,0,-1,-1,-91,0,-86,0,-80,0,-74,0,-1,-1,-1,-1,-56,0,-42,0,-1,-1,-1,-1,-1,-1,-8,0,-1,-1,-4,0,-1,-1,-1,-1,-1,-1,-2,0,-1,-1,3,1,-1,-1,7,1,-1,-1,12,1,18,1,24,1,30,1,36,1,42,1,48,1,54,1,60,1,66,1,72,1,78,1,83,1,-1,-1,88,1,-1,-1,92,1,97,1,102,1,106,1,110,1,-1,-1,114,1,118,1,121,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,124,1,-123,1,-114,1,-1,-1,-105,1,-96,1,-87,1,-1,-1,-78,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-69,1,-36,1,-1,-1,-1,-1,14,2,17,2,28,2,31,2,33,2,36,2,103,2,-1,-1,106,2,-1,-1,-1,-1,-1,-1,-1,-1,108,2,112,2,116,2,120,2,124,2,-1,-1,-1,-1,-128,2,-1,-1,-77,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-73,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-66,2,-61,2,-1,-1,-57,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-52,2,-1,-1,-47,2,-42,2,-1,-1,-1,-1,-1,-1,-1,-1,-37,2,-32,2,-27,2,-1,-1,-1,-1,-23,2,-1,-1,-18,2,-1,-1,-1,-1,-1,-1,-13,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-9,2,-3,2,3,3,9,3,15,3,21,3,27,3,33,3,39,3,45,3,51,3,57,3,63,3,69,3,75,3,81,3,87,3,93,3,99,3,105,3,111,3,117,3,123,3,-127,3,-121,3,-115,3,-109,3,-103,3,-97,3,-91,3,-85,3,-79,3,-73,3,-67,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-61,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-56,3,-45,3,-40,3,-32,3,-28,3,-19,3,-12,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,82,4,-1,-1,-1,-1,-1,-1,86,4,-107,4,-1,-1,-1,-1,-1,-1,-43,4,-39,4,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,51,103,0,27,91,72,27,91,50,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,10,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,50,53,104,0,27,91,67,0,27,91,65,0,27,91,77,0,14,0,27,91,53,109,0,27,91,49,109,0,27,55,27,91,63,52,55,104,0,27,91,52,104,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,15,0,27,91,109,15,0,27,91,50,74,27,91,63,52,55,108,27,56,0,27,91,52,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,91,63,53,104,36,60,49,48,48,47,62,27,91,63,53,108,0,27,91,63,52,55,108,27,61,27,91,63,49,108,0,27,91,114,27,91,109,27,91,50,74,27,91,72,27,91,63,55,104,27,91,63,49,59,51,59,52,59,54,108,27,91,52,108,0,27,91,76,0,8,0,27,91,51,126,0,27,91,66,0,27,91,56,94,0,27,91,50,49,126,0,27,91,49,49,126,0,27,91,50,49,126,0,27,91,49,50,126,0,27,91,49,51,126,0,27,91,49,52,126,0,27,91,49,53,126,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,55,126,0,27,91,50,126,0,27,91,68,0,27,91,54,126,0,27,91,53,126,0,27,91,67,0,27,91,97,0,27,91,98,0,27,91,65,0,27,62,0,27,61,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,65,0,27,62,27,91,49,59,51,59,52,59,53,59,54,108,27,91,63,55,104,27,91,109,27,91,114,27,91,50,74,27,91,72,0,27,91,114,27,91,109,27,91,50,74,27,91,72,27,91,63,55,104,27,91,63,49,59,51,59,52,59,54,108,27,91,52,108,27,62,27,91,63,49,48,48,48,108,27,91,63,50,53,104,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,54,37,116,59,49,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,52,37,116,59,53,37,59,109,37,63,37,112,57,37,116,14,37,101,15,37,59,0,27,72,0,9,0,27,79,119,0,27,79,121,0,27,79,117,0,27,79,113,0,27,79,115,0,96,96,97,97,102,102,103,103,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,0,27,91,90,0,27,40,66,27,41,48,0,27,91,56,126,0,27,79,77,0,27,91,49,126,0,27,91,51,36,0,27,91,52,126,0,27,91,56,36,0,27,91,55,36,0,27,91,50,36,0,27,91,100,0,27,91,54,36,0,27,91,53,36,0,27,91,99,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,50,53,126,0,27,91,50,54,126,0,27,91,50,56,126,0,27,91,50,57,126,0,27,91,51,49,126,0,27,91,51,50,126,0,27,91,51,51,126,0,27,91,51,52,126,0,27,91,50,51,36,0,27,91,50,52,36,0,27,91,49,49,94,0,27,91,49,50,94,0,27,91,49,51,94,0,27,91,49,52,94,0,27,91,49,53,94,0,27,91,49,55,94,0,27,91,49,56,94,0,27,91,49,57,94,0,27,91,50,48,94,0,27,91,50,49,94,0,27,91,50,51,94,0,27,91,50,52,94,0,27,91,50,53,94,0,27,91,50,54,94,0,27,91,50,56,94,0,27,91,50,57,94,0,27,91,51,49,94,0,27,91,51,50,94,0,27,91,51,51,94,0,27,91,51,52,94,0,27,91,50,51,64,0,27,91,50,52,64,0,27,91,49,75,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,49,59,50,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,93,49,48,52,7,0,27,93,52,59,37,112,49,37,100,59,114,103,98,58,37,112,50,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,51,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,52,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,27,92,0,27,91,77,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,27,40,66,0,27,40,48,0,0,2,0,0,0,22,0,46,0,-36,0,1,1,0,0,5,0,10,0,14,0,18,0,23,0,28,0,33,0,38,0,43,0,48,0,52,0,57,0,62,0,67,0,72,0,76,0,80,0,84,0,88,0,92,0,96,0,0,0,3,0,6,0,11,0,16,0,20,0,25,0,31,0,37,0,43,0,49,0,54,0,59,0,65,0,71,0,77,0,83,0,89,0,95,0,99,0,104,0,108,0,112,0,116,0,27,91,51,94,0,27,91,51,64,0,27,91,98,0,27,79,98,0,27,91,56,94,0,27,91,56,64,0,27,91,55,94,0,27,91,55,64,0,27,91,50,94,0,27,91,50,64,0,27,79,100,0,27,91,54,94,0,27,91,54,64,0,27,91,53,94,0,27,91,53,64,0,27,79,99,0,27,91,97,0,27,79,97,0,27,79,120,0,27,79,116,0,27,79,118,0,27,79,114,0,65,88,0,88,84,0,107,68,67,53,0,107,68,67,54,0,107,68,78,0,107,68,78,53,0,107,69,78,68,53,0,107,69,78,68,54,0,107,72,79,77,53,0,107,72,79,77,54,0,107,73,67,53,0,107,73,67,54,0,107,76,70,84,53,0,107,78,88,84,53,0,107,78,88,84,54,0,107,80,82,86,53,0,107,80,82,86,54,0,107,82,73,84,53,0,107,85,80,0,107,85,80,53,0,107,97,50,0,107,98,49,0,107,98,51,0,107,99,50,0 }; @@ -1111,11 +1298,14 @@ static const int8_t rxvt_256colour_terminfo[] = { // has_meta_key, // move_insert_mode, // move_standout_mode, +// AX, +// G0, // columns#80, // init_tabs#8, // lines#24, // max_colors#0x100, // max_pairs#0x10000, +// U8#1, // acs_chars=++\054\054--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, // back_tab=\E[Z, // bell=^G, @@ -1211,6 +1401,8 @@ static const int8_t rxvt_256colour_terminfo[] = { // user7=\E[6n, // user8=\E[?1;2c, // user9=\E[c, +// E0=\E(B, +// S0=\E(%p1%c, static const int8_t screen_256colour_terminfo[] = { 30,2,43,0,43,0,15,0,105,1,41,3,115,99,114,101,101,110,45,50,53,54,99,111,108,111,114,124,71,78,85,32,83,99,114,101,101,110,32,119,105,116,104,32,50,53,54,32,99,111,108,111,114,115,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,0,0,4,0,6,0,8,0,25,0,30,0,37,0,41,0,45,0,-1,-1,56,0,73,0,75,0,79,0,86,0,-1,-1,88,0,100,0,-1,-1,104,0,107,0,113,0,117,0,-1,-1,-1,-1,121,0,123,0,-128,0,-123,0,-1,-1,-114,0,-109,0,-1,-1,-1,-1,-104,0,-99,0,-94,0,-1,-1,-89,0,-87,0,-82,0,-1,-1,-73,0,-68,0,-62,0,-56,0,-1,-1,-1,-1,-1,-1,-53,0,-1,-1,-1,-1,-1,-1,-49,0,-1,-1,-45,0,-1,-1,-1,-1,-1,-1,-43,0,-1,-1,-38,0,-1,-1,-1,-1,-1,-1,-1,-1,-34,0,-30,0,-24,0,-20,0,-16,0,-12,0,-6,0,0,1,6,1,12,1,18,1,23,1,-1,-1,28,1,-1,-1,32,1,37,1,42,1,-1,-1,-1,-1,-1,-1,46,1,50,1,58,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,66,1,-1,-1,69,1,78,1,87,1,96,1,105,1,114,1,123,1,-124,1,-115,1,-106,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-97,1,-1,-1,-1,-1,-80,1,-77,1,-66,1,-63,1,-61,1,-58,1,26,2,-1,-1,29,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,31,2,-1,-1,96,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,100,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,107,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,112,2,118,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,124,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-127,2,-116,2,-111,2,-103,2,-99,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-90,2,-1,-1,-1,-1,-1,-1,-86,2,-23,2,27,91,90,0,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,51,103,0,27,91,72,27,91,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,10,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,51,52,104,27,91,63,50,53,104,0,27,91,67,0,27,77,0,27,91,51,52,108,0,27,91,80,0,27,91,77,0,14,0,27,91,53,109,0,27,91,49,109,0,27,91,63,49,48,52,57,104,0,27,91,50,109,0,27,91,52,104,0,27,91,55,109,0,27,91,51,109,0,27,91,52,109,0,15,0,27,91,109,15,0,27,91,63,49,48,52,57,108,0,27,91,52,108,0,27,91,50,51,109,0,27,91,50,52,109,0,27,103,0,27,41,48,0,27,91,76,0,8,0,27,91,51,126,0,27,79,66,0,27,79,80,0,27,91,50,49,126,0,27,79,81,0,27,79,82,0,27,79,83,0,27,91,49,53,126,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,79,68,0,27,91,54,126,0,27,91,53,126,0,27,79,67,0,27,79,65,0,27,91,63,49,108,27,62,0,27,91,63,49,104,27,61,0,27,69,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,27,99,27,91,63,49,48,48,48,108,27,91,63,50,53,104,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,54,37,116,59,49,37,59,37,63,37,112,49,37,116,59,51,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,51,37,116,59,55,37,59,37,63,37,112,52,37,116,59,53,37,59,37,63,37,112,53,37,116,59,50,37,59,109,37,63,37,112,57,37,116,14,37,101,15,37,59,0,27,72,0,9,0,43,43,44,44,45,45,46,46,48,48,96,96,97,97,102,102,103,103,104,104,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,0,27,91,90,0,27,40,66,27,41,48,0,27,91,52,126,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,49,75,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,49,59,50,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,91,77,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,0,2,0,1,0,2,0,7,0,27,0,1,1,1,0,0,0,0,0,4,0,0,0,3,0,6,0,9,0,12,0,27,40,66,0,27,40,37,112,49,37,99,0,65,88,0,71,48,0,85,56,0,69,48,0,83,48,0 }; @@ -1224,6 +1416,7 @@ static const int8_t screen_256colour_terminfo[] = { // move_insert_mode, // move_standout_mode, // no_pad_char, +// XT, // columns#80, // init_tabs#8, // lines#24, @@ -1406,6 +1599,28 @@ static const int8_t screen_256colour_terminfo[] = { // user7=\E[6n, // user8=\E[?1;2c, // user9=\E[c, +// BD=\E[?2004l, +// BE=\E[?2004h, +// Ms=\E]52;%p1%s;%p2%s^G, +// PE=\E[201~, +// PS=\E[200~, +// Se=\E[2 q, +// Ss=\E[%p1%d q, +// TS=\E]0;, +// kDN3=\E[1;3B, +// kDN5=\E[1;5B, +// kLFT3=\E[1;3D, +// kLFT5=\E[1;5D, +// kNXT3=\E[6;3~, +// kNXT5=\E[6;5~, +// kPRV3=\E[5;3~, +// kPRV5=\E[5;5~, +// kRIT3=\E[1;3C, +// kRIT5=\E[1;5C, +// kUP3=\E[1;3A, +// kUP5=\E[1;5A, +// rmxx=\E[29m, +// smxx=\E[9m, static const int8_t st_256colour_terminfo[] = { 30,2,55,0,29,0,15,0,105,1,-28,5,115,116,45,50,53,54,99,111,108,111,114,124,115,116,116,101,114,109,45,50,53,54,99,111,108,111,114,124,115,105,109,112,108,101,116,101,114,109,32,119,105,116,104,32,50,53,54,32,99,111,108,111,114,115,0,0,1,0,0,1,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,1,1,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,0,0,4,0,6,0,8,0,25,0,30,0,38,0,42,0,46,0,-1,-1,57,0,74,0,76,0,80,0,87,0,-1,-1,89,0,96,0,-1,-1,100,0,-1,-1,104,0,108,0,112,0,-1,-1,118,0,122,0,127,0,-124,0,-1,-1,-115,0,-110,0,-105,0,-1,-1,-100,0,-95,0,-90,0,-85,0,-76,0,-72,0,-67,0,-1,-1,-58,0,-53,0,-47,0,-41,0,-1,-1,-23,0,-1,-1,-21,0,-1,-1,-1,-1,-1,-1,-6,0,-1,-1,-2,0,-1,-1,0,1,-1,-1,7,1,12,1,19,1,23,1,30,1,37,1,-1,-1,44,1,48,1,54,1,58,1,62,1,66,1,72,1,78,1,84,1,90,1,96,1,101,1,106,1,113,1,-1,-1,117,1,122,1,127,1,-125,1,-118,1,-1,-1,-111,1,-107,1,-99,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-91,1,-82,1,-73,1,-64,1,-55,1,-46,1,-37,1,-28,1,-19,1,-10,1,-1,-1,-1,-1,-1,-1,-1,1,3,2,8,2,-1,-1,13,2,16,2,-1,-1,-1,-1,31,2,34,2,45,2,48,2,50,2,53,2,-110,2,-1,-1,-107,2,-105,2,-1,-1,-1,-1,-1,-1,-100,2,-95,2,-90,2,-86,2,-81,2,-1,-1,-1,-1,-76,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-11,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-7,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,2,-1,-1,-1,-1,5,3,-1,-1,-1,-1,-1,-1,-1,-1,12,3,19,3,26,3,-1,-1,-1,-1,33,3,-1,-1,40,3,-1,-1,-1,-1,-1,-1,47,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,54,3,60,3,66,3,73,3,80,3,87,3,94,3,102,3,110,3,118,3,126,3,-122,3,-114,3,-106,3,-98,3,-91,3,-84,3,-77,3,-70,3,-62,3,-54,3,-46,3,-38,3,-30,3,-22,3,-14,3,-6,3,1,4,8,4,15,4,22,4,30,4,38,4,46,4,54,4,62,4,70,4,78,4,86,4,93,4,100,4,107,4,114,4,122,4,-126,4,-118,4,-110,4,-102,4,-94,4,-86,4,-78,4,-71,4,-64,4,-57,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-52,4,-41,4,-36,4,-28,4,-24,4,-15,4,-8,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,86,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,91,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,97,5,-1,-1,-1,-1,-1,-1,101,5,-92,5,27,91,90,0,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,51,103,0,27,91,72,27,91,50,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,10,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,50,53,104,0,27,91,67,0,27,91,65,0,27,91,80,0,27,91,77,0,27,93,48,59,7,0,27,40,48,0,27,91,53,109,0,27,91,49,109,0,27,91,63,49,48,52,57,104,0,27,91,50,109,0,27,91,52,104,0,27,91,56,109,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,27,40,66,0,27,91,48,109,0,27,91,63,49,48,52,57,108,0,27,91,52,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,91,63,53,104,36,60,49,48,48,47,62,27,91,63,53,108,0,7,0,27,91,52,108,27,62,27,91,63,49,48,51,52,108,0,27,91,76,0,127,0,27,91,51,59,53,126,0,27,91,51,126,0,27,91,51,59,50,126,0,27,79,66,0,27,91,50,59,50,126,0,27,91,49,59,50,70,0,27,91,49,59,53,70,0,27,79,80,0,27,91,50,49,126,0,27,79,81,0,27,79,82,0,27,79,83,0,27,91,49,53,126,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,91,50,59,53,126,0,27,79,68,0,27,91,54,126,0,27,91,53,126,0,27,79,67,0,27,91,49,59,50,66,0,27,91,49,59,50,65,0,27,79,65,0,27,91,63,49,108,27,62,0,27,91,63,49,104,27,61,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,27,91,105,0,27,91,52,105,0,27,91,53,105,0,27,99,0,27,91,52,108,27,62,27,91,63,49,48,51,52,108,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,37,63,37,112,57,37,116,27,40,48,37,101,27,40,66,37,59,27,91,48,37,63,37,112,54,37,116,59,49,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,52,37,116,59,53,37,59,37,63,37,112,53,37,116,59,50,37,59,37,63,37,112,55,37,116,59,56,37,59,109,0,27,72,0,9,0,27,93,48,59,0,27,91,49,126,0,27,91,53,126,0,27,79,117,0,27,91,52,126,0,27,91,54,126,0,43,67,44,68,45,65,46,66,48,69,96,96,97,97,102,102,103,103,104,70,105,71,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,0,27,41,48,0,27,91,52,126,0,27,91,51,59,50,126,0,27,91,49,59,50,70,0,27,91,49,59,50,72,0,27,91,50,59,50,126,0,27,91,49,59,50,68,0,27,91,54,59,50,126,0,27,91,53,59,50,126,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,49,59,50,80,0,27,91,49,59,50,81,0,27,91,49,59,50,82,0,27,91,49,59,50,83,0,27,91,49,53,59,50,126,0,27,91,49,55,59,50,126,0,27,91,49,56,59,50,126,0,27,91,49,57,59,50,126,0,27,91,50,48,59,50,126,0,27,91,50,49,59,50,126,0,27,91,50,51,59,50,126,0,27,91,50,52,59,50,126,0,27,91,49,59,53,80,0,27,91,49,59,53,81,0,27,91,49,59,53,82,0,27,91,49,59,53,83,0,27,91,49,53,59,53,126,0,27,91,49,55,59,53,126,0,27,91,49,56,59,53,126,0,27,91,49,57,59,53,126,0,27,91,50,48,59,53,126,0,27,91,50,49,59,53,126,0,27,91,50,51,59,53,126,0,27,91,50,52,59,53,126,0,27,91,49,59,54,80,0,27,91,49,59,54,81,0,27,91,49,59,54,82,0,27,91,49,59,54,83,0,27,91,49,53,59,54,126,0,27,91,49,55,59,54,126,0,27,91,49,56,59,54,126,0,27,91,49,57,59,54,126,0,27,91,50,48,59,54,126,0,27,91,50,49,59,54,126,0,27,91,50,51,59,54,126,0,27,91,50,52,59,54,126,0,27,91,49,59,51,80,0,27,91,49,59,51,81,0,27,91,49,59,51,82,0,27,91,49,59,51,83,0,27,91,49,53,59,51,126,0,27,91,49,55,59,51,126,0,27,91,49,56,59,51,126,0,27,91,49,57,59,51,126,0,27,91,50,48,59,51,126,0,27,91,50,49,59,51,126,0,27,91,50,51,59,51,126,0,27,91,50,52,59,51,126,0,27,91,49,59,52,80,0,27,91,49,59,52,81,0,27,91,49,59,52,82,0,27,91,49,75,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,49,59,50,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,93,49,48,52,7,0,27,93,52,59,37,112,49,37,100,59,114,103,98,58,37,112,50,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,51,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,52,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,27,92,0,27,91,51,109,0,27,91,50,51,109,0,27,91,77,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,1,0,0,0,22,0,45,0,15,1,1,0,0,0,9,0,18,0,36,0,43,0,50,0,56,0,66,0,71,0,78,0,85,0,92,0,99,0,106,0,113,0,120,0,127,0,-122,0,-115,0,-108,0,-101,0,-95,0,0,0,3,0,6,0,9,0,12,0,15,0,18,0,21,0,24,0,27,0,32,0,37,0,43,0,49,0,55,0,61,0,67,0,73,0,79,0,85,0,90,0,95,0,100,0,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,93,53,50,59,37,112,49,37,115,59,37,112,50,37,115,7,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,91,50,32,113,0,27,91,37,112,49,37,100,32,113,0,27,93,48,59,0,27,91,49,59,51,66,0,27,91,49,59,53,66,0,27,91,49,59,51,68,0,27,91,49,59,53,68,0,27,91,54,59,51,126,0,27,91,54,59,53,126,0,27,91,53,59,51,126,0,27,91,53,59,53,126,0,27,91,49,59,51,67,0,27,91,49,59,53,67,0,27,91,49,59,51,65,0,27,91,49,59,53,65,0,27,91,50,57,109,0,27,91,57,109,0,88,84,0,66,68,0,66,69,0,77,115,0,80,69,0,80,83,0,83,101,0,83,115,0,84,83,0,107,68,78,51,0,107,68,78,53,0,107,76,70,84,51,0,107,76,70,84,53,0,107,78,88,84,51,0,107,78,88,84,53,0,107,80,82,86,51,0,107,80,82,86,53,0,107,82,73,84,51,0,107,82,73,84,53,0,107,85,80,51,0,107,85,80,53,0,114,109,120,120,0,115,109,120,120,0 }; @@ -1419,11 +1634,15 @@ static const int8_t st_256colour_terminfo[] = { // has_status_line, // move_insert_mode, // move_standout_mode, +// AX, +// G0, +// XF, // columns#80, // init_tabs#8, // lines#24, // max_colors#0x100, // max_pairs#0x10000, +// U8#1, // acs_chars=++\054\054--..00``aaffgghhiijjkkllmmnnooppqqrrssttuuvvwwxxyyzz{{||}}~~, // back_tab=\E[Z, // bell=^G, @@ -1586,6 +1805,82 @@ static const int8_t st_256colour_terminfo[] = { // user7=\E[6n, // user8=\E[?1;2c, // user9=\E[c, +// BD=\E[?2004l, +// BE=\E[?2004h, +// Cr=\E]112^G, +// Cs=\E]12;%p1%s^G, +// E0=\E(B, +// E3=\E[3J, +// Ms=\E]52;%p1%s;%p2%s^G, +// PE=\E[201~, +// PS=\E[200~, +// RV=\E[>c, +// S0=\E(%p1%c, +// Se=\E[2 q, +// Smulx=\E[4\072%p1%dm, +// Ss=\E[%p1%d q, +// TS=\E]0;, +// XR=\E[>0q, +// fd=\E[?1004l, +// fe=\E[?1004h, +// kDC3=\E[3;3~, +// kDC4=\E[3;4~, +// kDC5=\E[3;5~, +// kDC6=\E[3;6~, +// kDC7=\E[3;7~, +// kDN=\E[1;2B, +// kDN3=\E[1;3B, +// kDN4=\E[1;4B, +// kDN5=\E[1;5B, +// kDN6=\E[1;6B, +// kDN7=\E[1;7B, +// kEND3=\E[1;3F, +// kEND4=\E[1;4F, +// kEND5=\E[1;5F, +// kEND6=\E[1;6F, +// kEND7=\E[1;7F, +// kHOM3=\E[1;3H, +// kHOM4=\E[1;4H, +// kHOM5=\E[1;5H, +// kHOM6=\E[1;6H, +// kHOM7=\E[1;7H, +// kIC3=\E[2;3~, +// kIC4=\E[2;4~, +// kIC5=\E[2;5~, +// kIC6=\E[2;6~, +// kIC7=\E[2;7~, +// kLFT3=\E[1;3D, +// kLFT4=\E[1;4D, +// kLFT5=\E[1;5D, +// kLFT6=\E[1;6D, +// kLFT7=\E[1;7D, +// kNXT3=\E[6;3~, +// kNXT4=\E[6;4~, +// kNXT5=\E[6;5~, +// kNXT6=\E[6;6~, +// kNXT7=\E[6;7~, +// kPRV3=\E[5;3~, +// kPRV4=\E[5;4~, +// kPRV5=\E[5;5~, +// kPRV6=\E[5;6~, +// kPRV7=\E[5;7~, +// kRIT3=\E[1;3C, +// kRIT4=\E[1;4C, +// kRIT5=\E[1;5C, +// kRIT6=\E[1;6C, +// kRIT7=\E[1;7C, +// kUP=\E[1;2A, +// kUP3=\E[1;3A, +// kUP4=\E[1;4A, +// kUP5=\E[1;5A, +// kUP6=\E[1;6A, +// kUP7=\E[1;7A, +// kxIN=\E[I, +// kxOUT=\E[O, +// rmxx=\E[29m, +// rv=\E\[[0-9]+;[0-9]+;[0-9]+c, +// smxx=\E[9m, +// xr=\EP>\|[ -~]+\E\\, static const int8_t tmux_256colour_terminfo[] = { 30,2,35,0,43,0,15,0,105,1,22,5,116,109,117,120,45,50,53,54,99,111,108,111,114,124,116,109,117,120,32,119,105,116,104,32,50,53,54,32,99,111,108,111,114,115,0,0,1,0,0,1,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,1,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,0,0,4,0,6,0,8,0,25,0,30,0,37,0,41,0,45,0,-1,-1,56,0,73,0,75,0,79,0,86,0,-1,-1,88,0,100,0,-1,-1,104,0,107,0,113,0,117,0,121,0,-1,-1,127,0,-127,0,-122,0,-117,0,-1,-1,-108,0,-103,0,-98,0,-1,-1,-93,0,-88,0,-83,0,-1,-1,-78,0,-76,0,-71,0,-1,-1,-62,0,-57,0,-51,0,-45,0,-1,-1,-42,0,-1,-1,-40,0,-1,-1,-1,-1,-1,-1,-36,0,-1,-1,-32,0,-1,-1,-1,-1,-1,-1,-30,0,-1,-1,-25,0,-1,-1,-1,-1,-1,-1,-1,-1,-21,0,-17,0,-11,0,-7,0,-3,0,1,1,7,1,13,1,19,1,25,1,31,1,36,1,-1,-1,41,1,-1,-1,45,1,50,1,55,1,59,1,66,1,-1,-1,73,1,77,1,85,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,93,1,-1,-1,96,1,105,1,114,1,123,1,-124,1,-115,1,-106,1,-97,1,-88,1,-79,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-70,1,-1,-1,-1,-1,-53,1,-50,1,-39,1,-36,1,-34,1,-31,1,58,2,-1,-1,61,2,63,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,68,2,-1,-1,-123,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-119,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-112,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-107,2,-1,-1,-1,-1,-100,2,-1,-1,-1,-1,-1,-1,-1,-1,-93,2,-86,2,-79,2,-1,-1,-1,-1,-72,2,-1,-1,-65,2,-1,-1,-1,-1,-1,-1,-58,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-51,2,-45,2,-39,2,-32,2,-25,2,-18,2,-11,2,-3,2,5,3,13,3,21,3,29,3,37,3,45,3,53,3,60,3,67,3,74,3,81,3,89,3,97,3,105,3,113,3,121,3,-127,3,-119,3,-111,3,-104,3,-97,3,-90,3,-83,3,-75,3,-67,3,-59,3,-51,3,-43,3,-35,3,-27,3,-19,3,-12,3,-5,3,2,4,9,4,17,4,25,4,33,4,41,4,49,4,57,4,65,4,73,4,80,4,87,4,94,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,99,4,110,4,115,4,123,4,127,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-120,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-115,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-109,4,-1,-1,-1,-1,-1,-1,-105,4,-42,4,27,91,90,0,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,51,103,0,27,91,72,27,91,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,10,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,51,52,104,27,91,63,50,53,104,0,27,91,67,0,27,77,0,27,91,51,52,108,0,27,91,80,0,27,91,77,0,27,93,48,59,7,0,14,0,27,91,53,109,0,27,91,49,109,0,27,91,63,49,48,52,57,104,0,27,91,50,109,0,27,91,52,104,0,27,91,56,109,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,15,0,27,91,109,15,0,27,91,63,49,48,52,57,108,0,27,91,52,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,103,0,7,0,27,41,48,0,27,91,76,0,8,0,27,91,51,126,0,27,79,66,0,27,79,80,0,27,91,50,49,126,0,27,79,81,0,27,79,82,0,27,79,83,0,27,91,49,53,126,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,79,68,0,27,91,54,126,0,27,91,53,126,0,27,79,67,0,27,91,49,59,50,66,0,27,91,49,59,50,65,0,27,79,65,0,27,91,63,49,108,27,62,0,27,91,63,49,104,27,61,0,27,69,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,27,99,27,91,63,49,48,48,48,108,27,91,63,50,53,104,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,54,37,116,59,49,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,52,37,116,59,53,37,59,37,63,37,112,53,37,116,59,50,37,59,37,63,37,112,55,37,116,59,56,37,59,109,37,63,37,112,57,37,116,14,37,101,15,37,59,0,27,72,0,9,0,27,93,48,59,0,43,43,44,44,45,45,46,46,48,48,96,96,97,97,102,102,103,103,104,104,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,0,27,91,90,0,27,40,66,27,41,48,0,27,91,52,126,0,27,91,51,59,50,126,0,27,91,49,59,50,70,0,27,91,49,59,50,72,0,27,91,50,59,50,126,0,27,91,49,59,50,68,0,27,91,54,59,50,126,0,27,91,53,59,50,126,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,49,59,50,80,0,27,91,49,59,50,81,0,27,91,49,59,50,82,0,27,91,49,59,50,83,0,27,91,49,53,59,50,126,0,27,91,49,55,59,50,126,0,27,91,49,56,59,50,126,0,27,91,49,57,59,50,126,0,27,91,50,48,59,50,126,0,27,91,50,49,59,50,126,0,27,91,50,51,59,50,126,0,27,91,50,52,59,50,126,0,27,91,49,59,53,80,0,27,91,49,59,53,81,0,27,91,49,59,53,82,0,27,91,49,59,53,83,0,27,91,49,53,59,53,126,0,27,91,49,55,59,53,126,0,27,91,49,56,59,53,126,0,27,91,49,57,59,53,126,0,27,91,50,48,59,53,126,0,27,91,50,49,59,53,126,0,27,91,50,51,59,53,126,0,27,91,50,52,59,53,126,0,27,91,49,59,54,80,0,27,91,49,59,54,81,0,27,91,49,59,54,82,0,27,91,49,59,54,83,0,27,91,49,53,59,54,126,0,27,91,49,55,59,54,126,0,27,91,49,56,59,54,126,0,27,91,49,57,59,54,126,0,27,91,50,48,59,54,126,0,27,91,50,49,59,54,126,0,27,91,50,51,59,54,126,0,27,91,50,52,59,54,126,0,27,91,49,59,51,80,0,27,91,49,59,51,81,0,27,91,49,59,51,82,0,27,91,49,59,51,83,0,27,91,49,53,59,51,126,0,27,91,49,55,59,51,126,0,27,91,49,56,59,51,126,0,27,91,49,57,59,51,126,0,27,91,50,48,59,51,126,0,27,91,50,49,59,51,126,0,27,91,50,51,59,51,126,0,27,91,50,52,59,51,126,0,27,91,49,59,52,80,0,27,91,49,59,52,81,0,27,91,49,59,52,82,0,27,91,49,75,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,49,59,50,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,91,51,109,0,27,91,50,51,109,0,27,91,77,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,3,0,1,0,76,0,-100,0,-70,3,1,1,1,0,1,0,0,0,0,0,9,0,18,0,25,0,37,0,41,0,46,0,64,0,71,0,78,0,83,0,91,0,97,0,108,0,118,0,123,0,-127,0,-118,0,-109,0,-102,0,-95,0,-88,0,-81,0,-74,0,-67,0,-60,0,-53,0,-46,0,-39,0,-32,0,-25,0,-18,0,-11,0,-4,0,3,1,10,1,17,1,24,1,31,1,38,1,45,1,52,1,59,1,66,1,73,1,80,1,87,1,94,1,101,1,108,1,115,1,122,1,-127,1,-120,1,-113,1,-106,1,-99,1,-92,1,-85,1,-78,1,-71,1,-64,1,-57,1,-50,1,-43,1,-36,1,-29,1,-22,1,-15,1,-8,1,-1,1,3,2,7,2,13,2,38,2,43,2,0,0,3,0,6,0,9,0,12,0,15,0,18,0,21,0,24,0,27,0,30,0,33,0,36,0,39,0,42,0,45,0,48,0,54,0,57,0,60,0,63,0,66,0,69,0,74,0,79,0,84,0,89,0,94,0,98,0,103,0,108,0,113,0,118,0,123,0,-127,0,-121,0,-115,0,-109,0,-103,0,-97,0,-91,0,-85,0,-79,0,-73,0,-68,0,-63,0,-58,0,-53,0,-48,0,-42,0,-36,0,-30,0,-24,0,-18,0,-12,0,-6,0,0,1,6,1,12,1,18,1,24,1,30,1,36,1,42,1,48,1,54,1,60,1,66,1,72,1,76,1,81,1,86,1,91,1,96,1,101,1,106,1,112,1,117,1,120,1,125,1,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,93,49,49,50,7,0,27,93,49,50,59,37,112,49,37,115,7,0,27,40,66,0,27,91,51,74,0,27,93,53,50,59,37,112,49,37,115,59,37,112,50,37,115,7,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,91,62,99,0,27,40,37,112,49,37,99,0,27,91,50,32,113,0,27,91,52,58,37,112,49,37,100,109,0,27,91,37,112,49,37,100,32,113,0,27,93,48,59,0,27,91,62,48,113,0,27,91,63,49,48,48,52,108,0,27,91,63,49,48,48,52,104,0,27,91,51,59,51,126,0,27,91,51,59,52,126,0,27,91,51,59,53,126,0,27,91,51,59,54,126,0,27,91,51,59,55,126,0,27,91,49,59,50,66,0,27,91,49,59,51,66,0,27,91,49,59,52,66,0,27,91,49,59,53,66,0,27,91,49,59,54,66,0,27,91,49,59,55,66,0,27,91,49,59,51,70,0,27,91,49,59,52,70,0,27,91,49,59,53,70,0,27,91,49,59,54,70,0,27,91,49,59,55,70,0,27,91,49,59,51,72,0,27,91,49,59,52,72,0,27,91,49,59,53,72,0,27,91,49,59,54,72,0,27,91,49,59,55,72,0,27,91,50,59,51,126,0,27,91,50,59,52,126,0,27,91,50,59,53,126,0,27,91,50,59,54,126,0,27,91,50,59,55,126,0,27,91,49,59,51,68,0,27,91,49,59,52,68,0,27,91,49,59,53,68,0,27,91,49,59,54,68,0,27,91,49,59,55,68,0,27,91,54,59,51,126,0,27,91,54,59,52,126,0,27,91,54,59,53,126,0,27,91,54,59,54,126,0,27,91,54,59,55,126,0,27,91,53,59,51,126,0,27,91,53,59,52,126,0,27,91,53,59,53,126,0,27,91,53,59,54,126,0,27,91,53,59,55,126,0,27,91,49,59,51,67,0,27,91,49,59,52,67,0,27,91,49,59,53,67,0,27,91,49,59,54,67,0,27,91,49,59,55,67,0,27,91,49,59,50,65,0,27,91,49,59,51,65,0,27,91,49,59,52,65,0,27,91,49,59,53,65,0,27,91,49,59,54,65,0,27,91,49,59,55,65,0,27,91,73,0,27,91,79,0,27,91,50,57,109,0,27,92,91,91,48,45,57,93,43,59,91,48,45,57,93,43,59,91,48,45,57,93,43,99,0,27,91,57,109,0,27,80,62,92,124,91,32,45,126,93,43,27,92,92,0,65,88,0,71,48,0,88,70,0,85,56,0,66,68,0,66,69,0,67,114,0,67,115,0,69,48,0,69,51,0,77,115,0,80,69,0,80,83,0,82,86,0,83,48,0,83,101,0,83,109,117,108,120,0,83,115,0,84,83,0,88,82,0,102,100,0,102,101,0,107,68,67,51,0,107,68,67,52,0,107,68,67,53,0,107,68,67,54,0,107,68,67,55,0,107,68,78,0,107,68,78,51,0,107,68,78,52,0,107,68,78,53,0,107,68,78,54,0,107,68,78,55,0,107,69,78,68,51,0,107,69,78,68,52,0,107,69,78,68,53,0,107,69,78,68,54,0,107,69,78,68,55,0,107,72,79,77,51,0,107,72,79,77,52,0,107,72,79,77,53,0,107,72,79,77,54,0,107,72,79,77,55,0,107,73,67,51,0,107,73,67,52,0,107,73,67,53,0,107,73,67,54,0,107,73,67,55,0,107,76,70,84,51,0,107,76,70,84,52,0,107,76,70,84,53,0,107,76,70,84,54,0,107,76,70,84,55,0,107,78,88,84,51,0,107,78,88,84,52,0,107,78,88,84,53,0,107,78,88,84,54,0,107,78,88,84,55,0,107,80,82,86,51,0,107,80,82,86,52,0,107,80,82,86,53,0,107,80,82,86,54,0,107,80,82,86,55,0,107,82,73,84,51,0,107,82,73,84,52,0,107,82,73,84,53,0,107,82,73,84,54,0,107,82,73,84,55,0,107,85,80,0,107,85,80,51,0,107,85,80,52,0,107,85,80,53,0,107,85,80,54,0,107,85,80,55,0,107,120,73,78,0,107,120,79,85,84,0,114,109,120,120,0,114,118,0,115,109,120,120,0,120,114,0 }; @@ -1598,6 +1893,8 @@ static const int8_t tmux_256colour_terminfo[] = { // eat_newline_glitch, // move_insert_mode, // move_standout_mode, +// AX, +// XT, // columns#80, // init_tabs#8, // lines#24, @@ -1774,11 +2071,80 @@ static const int8_t tmux_256colour_terminfo[] = { // user7=\E[6n, // user8=\E[?%[;0123456789]c, // user9=\E[c, +// BD=\E[?2004l, +// BE=\E[?2004h, +// Cr=\E]112^G, +// Cs=\E]12;%p1%s^G, +// Ms=\E]52;%p1%s;%p2%s^G, +// PE=\E[201~, +// PS=\E[200~, +// Rmol=\E[55m, +// Se=\E[1 q, +// Smol=\E[53m, +// Smulx=\E[4\072%p1%dm, +// Ss=\E[%p1%d q, +// XM=\E[?1006;1000%?%p1%{1}%=%th%el%;, +// kDC3=\E[3;3~, +// kDC4=\E[3;4~, +// kDC5=\E[3;5~, +// kDC6=\E[3;6~, +// kDC7=\E[3;7~, +// kDN=\E[1;2B, +// kDN3=\E[1;3B, +// kDN4=\E[1;4B, +// kDN5=\E[1;5B, +// kDN6=\E[1;6B, +// kDN7=\E[1;7B, +// kEND3=\E[1;3F, +// kEND4=\E[1;4F, +// kEND5=\E[1;5F, +// kEND6=\E[1;6F, +// kEND7=\E[1;7F, +// kHOM3=\E[1;3H, +// kHOM4=\E[1;4H, +// kHOM5=\E[1;5H, +// kHOM6=\E[1;6H, +// kHOM7=\E[1;7H, +// kIC3=\E[2;3~, +// kIC4=\E[2;4~, +// kIC5=\E[2;5~, +// kIC6=\E[2;6~, +// kIC7=\E[2;7~, +// kLFT3=\E[1;3D, +// kLFT4=\E[1;4D, +// kLFT5=\E[1;5D, +// kLFT6=\E[1;6D, +// kLFT7=\E[1;7D, +// kNXT3=\E[6;3~, +// kNXT4=\E[6;4~, +// kNXT5=\E[6;5~, +// kNXT6=\E[6;6~, +// kNXT7=\E[6;7~, +// kPRV3=\E[5;3~, +// kPRV4=\E[5;4~, +// kPRV5=\E[5;5~, +// kPRV6=\E[5;6~, +// kPRV7=\E[5;7~, +// kRIT3=\E[1;3C, +// kRIT4=\E[1;4C, +// kRIT5=\E[1;5C, +// kRIT6=\E[1;6C, +// kRIT7=\E[1;7C, +// kUP=\E[1;2A, +// kUP3=\E[1;3A, +// kUP4=\E[1;4A, +// kUP5=\E[1;5A, +// kUP6=\E[1;6A, +// kUP7=\E[1;7A, +// rmxx=\E[29m, +// setal=\E[58\0722\072\072%p1%{65536}%/%d\072%p1%{256}%/%{255}%&%d\072%p1%{255}%&%dm, +// smxx=\E[9m, +// xm=\E[<%i%p3%d;%p1%d;%p2%d;%?%p4%tM%em%;, static const int8_t vte_256colour_terminfo[] = { 30,2,39,0,38,0,15,0,-99,1,7,6,118,116,101,45,50,53,54,99,111,108,111,114,124,86,84,69,32,119,105,116,104,32,120,116,101,114,109,32,50,53,54,45,99,111,108,111,114,115,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,1,0,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,0,0,4,0,6,0,8,0,25,0,30,0,38,0,42,0,46,0,-1,-1,57,0,74,0,76,0,80,0,87,0,-1,-1,89,0,96,0,-1,-1,100,0,-1,-1,104,0,108,0,-1,-1,-1,-1,112,0,114,0,119,0,124,0,-1,-1,-114,0,-109,0,-104,0,-1,-1,-99,0,-94,0,-89,0,-84,0,-75,0,-73,0,-67,0,-1,-1,-49,0,-44,0,-38,0,-32,0,-1,-1,-1,-1,-1,-1,-14,0,-1,-1,-1,-1,-1,-1,19,1,-1,-1,23,1,-1,-1,-1,-1,-1,-1,25,1,-1,-1,30,1,-1,-1,-1,-1,-1,-1,-1,-1,34,1,38,1,44,1,48,1,52,1,56,1,62,1,68,1,74,1,80,1,86,1,90,1,-1,-1,95,1,-1,-1,99,1,104,1,109,1,113,1,120,1,-1,-1,127,1,-125,1,-117,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-109,1,-1,-1,-106,1,-97,1,-88,1,-79,1,-70,1,-61,1,-52,1,-43,1,-34,1,-25,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-16,1,4,2,7,2,-1,-1,-1,-1,58,2,61,2,72,2,75,2,77,2,80,2,-87,2,-1,-1,-84,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-82,2,-1,-1,-1,-1,-1,-1,-1,-1,-78,2,-1,-1,-25,2,-1,-1,-1,-1,-21,2,-15,2,-1,-1,-1,-1,-9,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,2,2,3,-1,-1,6,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,11,3,-1,-1,18,3,23,3,-1,-1,-1,-1,-1,-1,-1,-1,30,3,37,3,44,3,-1,-1,-1,-1,51,3,-1,-1,58,3,-1,-1,-1,-1,-1,-1,65,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,72,3,78,3,84,3,91,3,98,3,105,3,112,3,120,3,-128,3,-120,3,-112,3,-104,3,-96,3,-88,3,-80,3,-73,3,-66,3,-59,3,-52,3,-44,3,-36,3,-28,3,-20,3,-12,3,-4,3,4,4,12,4,19,4,26,4,33,4,40,4,48,4,56,4,64,4,72,4,80,4,88,4,96,4,104,4,111,4,118,4,125,4,-124,4,-116,4,-108,4,-100,4,-92,4,-84,4,-76,4,-68,4,-60,4,-53,4,-46,4,-39,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-34,4,-23,4,-18,4,1,5,5,5,14,5,21,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,115,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,120,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,126,5,-1,-1,-1,-1,-1,-1,-126,5,-63,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,1,6,4,6,27,91,90,0,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,51,103,0,27,91,72,27,91,50,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,10,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,50,53,104,0,27,91,67,0,27,91,65,0,27,91,80,0,27,91,77,0,14,0,27,91,53,109,0,27,91,49,109,0,27,91,63,49,48,52,57,104,27,91,50,50,59,48,59,48,116,0,27,91,50,109,0,27,91,52,104,0,27,91,56,109,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,15,0,27,91,48,109,15,0,27,91,63,49,48,52,57,108,27,91,50,51,59,48,59,48,116,0,27,91,52,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,91,63,53,104,36,60,49,48,48,47,62,27,91,63,53,108,0,27,91,109,27,91,63,55,104,27,91,52,108,27,62,27,55,27,91,114,27,91,63,49,59,51,59,52,59,54,108,27,56,0,27,91,76,0,127,0,27,91,51,126,0,27,79,66,0,27,79,80,0,27,91,50,49,126,0,27,79,81,0,27,79,82,0,27,79,83,0,27,91,49,53,126,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,79,72,0,27,91,50,126,0,27,79,68,0,27,91,54,126,0,27,91,53,126,0,27,79,67,0,27,91,49,59,50,66,0,27,91,49,59,50,65,0,27,79,65,0,27,91,63,49,108,27,62,0,27,91,63,49,104,27,61,0,27,69,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,37,112,49,37,99,27,91,37,112,50,37,123,49,125,37,45,37,100,98,0,27,99,0,27,55,27,91,114,27,56,27,91,109,27,91,63,55,104,27,91,33,112,27,91,63,49,59,51,59,52,59,54,108,27,91,52,108,27,62,27,91,63,49,48,48,48,108,27,91,63,50,53,104,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,54,37,116,59,49,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,52,37,116,59,53,37,59,37,63,37,112,53,37,116,59,50,37,59,37,63,37,112,55,37,116,59,56,37,59,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,109,37,63,37,112,57,37,116,14,37,101,15,37,59,0,27,72,0,9,0,27,91,69,0,96,96,97,97,102,102,103,103,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,0,27,91,90,0,27,91,63,55,104,0,27,91,63,55,108,0,27,40,66,27,41,48,0,27,79,70,0,27,79,77,0,27,91,49,126,0,27,91,51,59,50,126,0,27,91,52,126,0,27,91,49,59,50,70,0,27,91,49,59,50,72,0,27,91,50,59,50,126,0,27,91,49,59,50,68,0,27,91,54,59,50,126,0,27,91,53,59,50,126,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,49,59,50,80,0,27,91,49,59,50,81,0,27,91,49,59,50,82,0,27,91,49,59,50,83,0,27,91,49,53,59,50,126,0,27,91,49,55,59,50,126,0,27,91,49,56,59,50,126,0,27,91,49,57,59,50,126,0,27,91,50,48,59,50,126,0,27,91,50,49,59,50,126,0,27,91,50,51,59,50,126,0,27,91,50,52,59,50,126,0,27,91,49,59,53,80,0,27,91,49,59,53,81,0,27,91,49,59,53,82,0,27,91,49,59,53,83,0,27,91,49,53,59,53,126,0,27,91,49,55,59,53,126,0,27,91,49,56,59,53,126,0,27,91,49,57,59,53,126,0,27,91,50,48,59,53,126,0,27,91,50,49,59,53,126,0,27,91,50,51,59,53,126,0,27,91,50,52,59,53,126,0,27,91,49,59,54,80,0,27,91,49,59,54,81,0,27,91,49,59,54,82,0,27,91,49,59,54,83,0,27,91,49,53,59,54,126,0,27,91,49,55,59,54,126,0,27,91,49,56,59,54,126,0,27,91,49,57,59,54,126,0,27,91,50,48,59,54,126,0,27,91,50,49,59,54,126,0,27,91,50,51,59,54,126,0,27,91,50,52,59,54,126,0,27,91,49,59,51,80,0,27,91,49,59,51,81,0,27,91,49,59,51,82,0,27,91,49,59,51,83,0,27,91,49,53,59,51,126,0,27,91,49,55,59,51,126,0,27,91,49,56,59,51,126,0,27,91,49,57,59,51,126,0,27,91,50,48,59,51,126,0,27,91,50,49,59,51,126,0,27,91,50,51,59,51,126,0,27,91,50,52,59,51,126,0,27,91,49,59,52,80,0,27,91,49,59,52,81,0,27,91,49,59,52,82,0,27,91,49,75,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,37,91,59,48,49,50,51,52,53,54,55,56,57,93,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,93,49,48,52,7,0,27,93,52,59,37,112,49,37,100,59,114,103,98,58,37,112,50,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,51,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,52,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,27,92,0,27,91,51,109,0,27,91,50,51,109,0,27,91,60,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,27,108,0,27,109,0,0,2,0,0,0,69,0,-116,0,-52,3,1,1,0,0,9,0,18,0,25,0,37,0,55,0,62,0,69,0,75,0,81,0,87,0,98,0,108,0,-116,0,-109,0,-102,0,-95,0,-88,0,-81,0,-74,0,-67,0,-60,0,-53,0,-46,0,-39,0,-32,0,-25,0,-18,0,-11,0,-4,0,3,1,10,1,17,1,24,1,31,1,38,1,45,1,52,1,59,1,66,1,73,1,80,1,87,1,94,1,101,1,108,1,115,1,122,1,-127,1,-120,1,-113,1,-106,1,-99,1,-92,1,-85,1,-78,1,-71,1,-64,1,-57,1,-50,1,-43,1,-36,1,-29,1,-22,1,-15,1,-8,1,-2,1,59,2,64,2,0,0,3,0,6,0,9,0,12,0,15,0,18,0,21,0,24,0,27,0,32,0,35,0,40,0,46,0,49,0,52,0,57,0,62,0,67,0,72,0,77,0,81,0,86,0,91,0,96,0,101,0,106,0,112,0,118,0,124,0,-126,0,-120,0,-114,0,-108,0,-102,0,-96,0,-90,0,-85,0,-80,0,-75,0,-70,0,-65,0,-59,0,-53,0,-47,0,-41,0,-35,0,-29,0,-23,0,-17,0,-11,0,-5,0,1,1,7,1,13,1,19,1,25,1,31,1,37,1,43,1,49,1,55,1,59,1,64,1,69,1,74,1,79,1,84,1,89,1,95,1,100,1,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,93,49,49,50,7,0,27,93,49,50,59,37,112,49,37,115,7,0,27,93,53,50,59,37,112,49,37,115,59,37,112,50,37,115,7,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,91,53,53,109,0,27,91,49,32,113,0,27,91,53,51,109,0,27,91,52,58,37,112,49,37,100,109,0,27,91,37,112,49,37,100,32,113,0,27,91,63,49,48,48,54,59,49,48,48,48,37,63,37,112,49,37,123,49,125,37,61,37,116,104,37,101,108,37,59,0,27,91,51,59,51,126,0,27,91,51,59,52,126,0,27,91,51,59,53,126,0,27,91,51,59,54,126,0,27,91,51,59,55,126,0,27,91,49,59,50,66,0,27,91,49,59,51,66,0,27,91,49,59,52,66,0,27,91,49,59,53,66,0,27,91,49,59,54,66,0,27,91,49,59,55,66,0,27,91,49,59,51,70,0,27,91,49,59,52,70,0,27,91,49,59,53,70,0,27,91,49,59,54,70,0,27,91,49,59,55,70,0,27,91,49,59,51,72,0,27,91,49,59,52,72,0,27,91,49,59,53,72,0,27,91,49,59,54,72,0,27,91,49,59,55,72,0,27,91,50,59,51,126,0,27,91,50,59,52,126,0,27,91,50,59,53,126,0,27,91,50,59,54,126,0,27,91,50,59,55,126,0,27,91,49,59,51,68,0,27,91,49,59,52,68,0,27,91,49,59,53,68,0,27,91,49,59,54,68,0,27,91,49,59,55,68,0,27,91,54,59,51,126,0,27,91,54,59,52,126,0,27,91,54,59,53,126,0,27,91,54,59,54,126,0,27,91,54,59,55,126,0,27,91,53,59,51,126,0,27,91,53,59,52,126,0,27,91,53,59,53,126,0,27,91,53,59,54,126,0,27,91,53,59,55,126,0,27,91,49,59,51,67,0,27,91,49,59,52,67,0,27,91,49,59,53,67,0,27,91,49,59,54,67,0,27,91,49,59,55,67,0,27,91,49,59,50,65,0,27,91,49,59,51,65,0,27,91,49,59,52,65,0,27,91,49,59,53,65,0,27,91,49,59,54,65,0,27,91,49,59,55,65,0,27,91,50,57,109,0,27,91,53,56,58,50,58,58,37,112,49,37,123,54,53,53,51,54,125,37,47,37,100,58,37,112,49,37,123,50,53,54,125,37,47,37,123,50,53,53,125,37,38,37,100,58,37,112,49,37,123,50,53,53,125,37,38,37,100,109,0,27,91,57,109,0,27,91,60,37,105,37,112,51,37,100,59,37,112,49,37,100,59,37,112,50,37,100,59,37,63,37,112,52,37,116,77,37,101,109,37,59,0,65,88,0,88,84,0,66,68,0,66,69,0,67,114,0,67,115,0,77,115,0,80,69,0,80,83,0,82,109,111,108,0,83,101,0,83,109,111,108,0,83,109,117,108,120,0,83,115,0,88,77,0,107,68,67,51,0,107,68,67,52,0,107,68,67,53,0,107,68,67,54,0,107,68,67,55,0,107,68,78,0,107,68,78,51,0,107,68,78,52,0,107,68,78,53,0,107,68,78,54,0,107,68,78,55,0,107,69,78,68,51,0,107,69,78,68,52,0,107,69,78,68,53,0,107,69,78,68,54,0,107,69,78,68,55,0,107,72,79,77,51,0,107,72,79,77,52,0,107,72,79,77,53,0,107,72,79,77,54,0,107,72,79,77,55,0,107,73,67,51,0,107,73,67,52,0,107,73,67,53,0,107,73,67,54,0,107,73,67,55,0,107,76,70,84,51,0,107,76,70,84,52,0,107,76,70,84,53,0,107,76,70,84,54,0,107,76,70,84,55,0,107,78,88,84,51,0,107,78,88,84,52,0,107,78,88,84,53,0,107,78,88,84,54,0,107,78,88,84,55,0,107,80,82,86,51,0,107,80,82,86,52,0,107,80,82,86,53,0,107,80,82,86,54,0,107,80,82,86,55,0,107,82,73,84,51,0,107,82,73,84,52,0,107,82,73,84,53,0,107,82,73,84,54,0,107,82,73,84,55,0,107,85,80,0,107,85,80,51,0,107,85,80,52,0,107,85,80,53,0,107,85,80,54,0,107,85,80,55,0,114,109,120,120,0,115,101,116,97,108,0,115,109,120,120,0,120,109,0 }; -// vtpcon|ANIS emulation for console virtual terminal sequence with libuv, +// vtpcon|ANSI emulation for console virtual terminal sequence with libuv, // auto_right_margin, // back_color_erase, // backspaces_with_bs, @@ -1787,6 +2153,9 @@ static const int8_t vte_256colour_terminfo[] = { // move_insert_mode, // move_standout_mode, // no_pad_char, +// AX, +// XF, +// XT, // columns#80, // init_tabs#8, // lines#24, @@ -1978,8 +2347,95 @@ static const int8_t vte_256colour_terminfo[] = { // user7@, // user8@, // user9@, +// BD=\E[?2004l, +// BE=\E[?2004h, +// Cr@, +// Cs@, +// E3=\E[3J, +// Ms@, +// PE=\E[201~, +// PS=\E[200~, +// RV=\E[>c, +// Se=\E[2 q, +// Ss=\E[%p1%d q, +// TS=\E]0;, +// XM@, +// XR=\E[>0q, +// fd=\E[?1004l, +// fe=\E[?1004h, +// kDC3@, +// kDC4@, +// kDC5@, +// kDC6@, +// kDC7@, +// kDN@, +// kDN3@, +// kDN4@, +// kDN5@, +// kDN6@, +// kDN7@, +// kEND3@, +// kEND4@, +// kEND5@, +// kEND6@, +// kEND7@, +// kHOM3@, +// kHOM4@, +// kHOM5@, +// kHOM6@, +// kHOM7@, +// kIC3@, +// kIC4@, +// kIC5@, +// kIC6@, +// kIC7@, +// kLFT3@, +// kLFT4@, +// kLFT5@, +// kLFT6@, +// kLFT7@, +// kNXT3@, +// kNXT4@, +// kNXT5@, +// kNXT6@, +// kNXT7@, +// kPRV3@, +// kPRV4@, +// kPRV5@, +// kPRV6@, +// kPRV7@, +// kRIT3@, +// kRIT4@, +// kRIT5@, +// kRIT6@, +// kRIT7@, +// kUP=\E[1;2A, +// kUP3@, +// kUP4@, +// kUP5@, +// kUP6@, +// kUP7@, +// ka2=\EOx, +// kb1=\EOt, +// kb3=\EOv, +// kc2=\EOr, +// kp5=\EOE, +// kpADD=\EOk, +// kpCMA=\EOl, +// kpDIV=\EOo, +// kpDOT=\EOn, +// kpMUL=\EOj, +// kpSUB=\EOm, +// kpZRO=\EOp, +// kxIN=\E[I, +// kxOUT=\E[O, +// rmxx@, +// rv=\E\[41;[1-6][0-9][0-9];0c, +// smxx@, +// xm@, +// xr=\EP>\|XTerm\([1-9][0-9]+\)\E\\, static const int8_t vtpcon_terminfo[] = { - 30,2,71,0,38,0,15,0,-99,1,64,4,118,116,112,99,111,110,124,65,78,73,83,32,101,109,117,108,97,116,105,111,110,32,102,111,114,32,99,111,110,115,111,108,101,32,118,105,114,116,117,97,108,32,116,101,114,109,105,110,97,108,32,115,101,113,117,101,110,99,101,32,119,105,116,104,32,108,105,98,117,118,0,0,1,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,0,0,4,0,6,0,8,0,-2,-1,25,0,33,0,37,0,41,0,-1,-1,52,0,69,0,73,0,77,0,84,0,-1,-1,86,0,99,0,-1,-1,103,0,-2,-1,107,0,111,0,115,0,-1,-1,121,0,-2,-1,125,0,-126,0,-1,-1,-2,-1,-2,-1,-2,-1,-1,-1,-117,0,-112,0,-107,0,-102,0,-93,0,-89,0,-84,0,-1,-1,-2,-1,-75,0,-69,0,-2,-1,-1,-1,-63,0,-1,-1,-61,0,-1,-1,-1,-1,-1,-1,-51,0,-1,-1,-47,0,-1,-1,-1,-1,-1,-1,-45,0,-1,-1,-40,0,-1,-1,-1,-1,-1,-1,-1,-1,-36,0,-31,0,-25,0,-20,0,-15,0,-10,0,-5,0,1,1,7,1,13,1,19,1,24,1,-1,-1,29,1,-1,-1,33,1,38,1,43,1,47,1,54,1,-1,-1,61,1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,65,1,-1,-1,68,1,77,1,86,1,95,1,104,1,113,1,122,1,-125,1,-116,1,-107,1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,-98,1,-2,-1,-2,-1,-1,-1,-1,-1,-78,1,-75,1,-64,1,-61,1,-59,1,-56,1,-13,1,-1,-1,-10,1,-8,1,-1,-1,-1,-1,-1,-1,-3,1,1,2,5,2,9,2,13,2,-1,-1,-1,-1,17,2,-1,-1,40,2,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,44,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,48,2,53,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,57,2,-1,-1,-1,-1,64,2,-1,-1,-1,-1,-1,-1,-1,-1,71,2,78,2,85,2,-1,-1,-1,-1,92,2,-1,-1,99,2,-1,-1,-1,-1,-1,-1,106,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,113,2,119,2,125,2,-125,2,-119,2,-113,2,-107,2,-101,2,-95,2,-89,2,-83,2,-77,2,-71,2,-65,2,-59,2,-53,2,-47,2,-41,2,-35,2,-29,2,-23,2,-17,2,-11,2,-5,2,1,3,7,3,13,3,19,3,25,3,31,3,38,3,44,3,50,3,56,3,62,3,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,68,3,73,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,-2,-1,80,3,-2,-1,89,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-74,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-69,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-63,3,0,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,27,91,90,0,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,72,27,91,50,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,27,91,66,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,49,50,108,27,91,63,50,53,104,0,27,91,67,0,27,91,65,0,27,91,80,0,27,91,77,0,27,93,48,59,7,0,27,40,48,0,27,91,49,109,0,27,91,63,49,48,52,57,104,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,27,40,66,0,27,91,48,109,0,27,91,63,49,48,52,57,108,0,27,91,50,55,109,0,27,91,50,52,109,0,7,0,27,91,33,112,27,91,63,51,108,0,27,91,76,0,8,0,27,91,51,126,0,27,91,66,0,27,91,91,65,0,27,91,50,49,126,0,27,91,91,66,0,27,91,91,67,0,27,91,91,68,0,27,91,91,69,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,91,68,0,27,91,54,126,0,27,91,53,126,0,27,91,67,0,27,91,49,59,50,66,0,27,91,49,59,50,65,0,27,91,65,0,27,69,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,37,112,49,37,99,27,91,37,112,50,37,123,49,125,37,45,37,100,98,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,54,37,116,59,49,37,59,109,0,27,72,0,9,0,27,93,48,59,0,27,79,119,0,27,79,121,0,27,91,71,0,27,79,113,0,27,79,115,0,106,106,107,107,108,108,109,109,110,110,113,113,116,116,117,117,118,118,119,119,120,120,0,27,91,90,0,27,79,69,0,27,91,52,126,0,27,79,77,0,27,91,51,59,50,126,0,27,91,52,59,50,126,0,27,91,49,59,50,126,0,27,91,50,59,50,126,0,27,91,49,59,50,68,0,27,91,54,59,50,126,0,27,91,53,59,50,126,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,50,53,126,0,27,91,50,54,126,0,27,91,50,56,126,0,27,91,50,57,126,0,27,91,51,49,126,0,27,91,51,50,126,0,27,91,51,51,126,0,27,91,51,52,126,0,27,91,50,51,36,0,27,91,50,52,36,0,27,91,49,49,94,0,27,91,49,50,94,0,27,91,49,51,94,0,27,91,49,52,94,0,27,91,49,53,94,0,27,91,49,55,94,0,27,91,49,56,94,0,27,91,49,57,94,0,27,91,50,48,94,0,27,91,50,49,94,0,27,91,50,51,94,0,27,91,50,52,94,0,27,91,50,53,94,0,27,91,50,54,94,0,27,91,50,56,94,0,27,91,50,57,94,0,27,91,51,49,94,0,27,91,49,59,54,83,0,27,91,51,50,94,0,27,91,51,51,94,0,27,91,51,52,94,0,27,91,50,51,64,0,27,91,50,52,64,0,27,91,49,75,0,27,91,63,54,57,108,0,27,91,51,57,59,52,57,109,0,27,93,52,59,37,112,49,37,100,59,114,103,98,58,37,112,50,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,51,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,52,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,27,0,27,91,51,109,0,27,91,50,51,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,3,0,0,0,87,0,119,0,-127,2,1,1,1,0,0,0,9,0,-2,-1,-2,-1,18,0,-2,-1,23,0,30,0,37,0,42,0,48,0,58,0,-2,-1,63,0,69,0,78,0,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,87,0,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,94,0,98,0,102,0,106,0,110,0,114,0,118,0,122,0,126,0,-126,0,-122,0,-118,0,-114,0,-110,0,-2,-1,-106,0,-2,-1,-2,-1,-81,0,0,0,3,0,6,0,9,0,12,0,15,0,18,0,21,0,24,0,27,0,30,0,33,0,36,0,39,0,42,0,45,0,48,0,51,0,54,0,57,0,62,0,67,0,72,0,77,0,82,0,86,0,91,0,96,0,101,0,106,0,111,0,117,0,123,0,-127,0,-121,0,-115,0,-109,0,-103,0,-97,0,-91,0,-85,0,-80,0,-75,0,-70,0,-65,0,-60,0,-54,0,-48,0,-42,0,-36,0,-30,0,-24,0,-18,0,-12,0,-6,0,0,1,6,1,12,1,18,1,24,1,30,1,36,1,42,1,48,1,54,1,60,1,64,1,69,1,74,1,79,1,84,1,89,1,93,1,97,1,101,1,105,1,109,1,115,1,121,1,127,1,-123,1,-117,1,-111,1,-105,1,-100,1,-94,1,-89,1,-86,1,-81,1,-78,1,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,91,51,74,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,91,62,99,0,27,91,50,32,113,0,27,91,37,112,49,37,100,32,113,0,27,93,48,59,0,27,91,62,48,113,0,27,91,63,49,48,48,52,108,0,27,91,63,49,48,48,52,104,0,27,91,49,59,50,65,0,27,79,120,0,27,79,116,0,27,79,118,0,27,79,114,0,27,79,69,0,27,79,107,0,27,79,108,0,27,79,111,0,27,79,110,0,27,79,106,0,27,79,109,0,27,79,112,0,27,91,73,0,27,91,79,0,27,92,91,52,49,59,91,49,45,54,93,91,48,45,57,93,91,48,45,57,93,59,48,99,0,27,80,62,92,124,88,84,101,114,109,92,40,91,49,45,57,93,91,48,45,57,93,43,92,41,27,92,92,0,65,88,0,88,70,0,88,84,0,66,68,0,66,69,0,67,114,0,67,115,0,69,51,0,77,115,0,80,69,0,80,83,0,82,86,0,83,101,0,83,115,0,84,83,0,88,77,0,88,82,0,102,100,0,102,101,0,107,68,67,51,0,107,68,67,52,0,107,68,67,53,0,107,68,67,54,0,107,68,67,55,0,107,68,78,0,107,68,78,51,0,107,68,78,52,0,107,68,78,53,0,107,68,78,54,0,107,68,78,55,0,107,69,78,68,51,0,107,69,78,68,52,0,107,69,78,68,53,0,107,69,78,68,54,0,107,69,78,68,55,0,107,72,79,77,51,0,107,72,79,77,52,0,107,72,79,77,53,0,107,72,79,77,54,0,107,72,79,77,55,0,107,73,67,51,0,107,73,67,52,0,107,73,67,53,0,107,73,67,54,0,107,73,67,55,0,107,76,70,84,51,0,107,76,70,84,52,0,107,76,70,84,53,0,107,76,70,84,54,0,107,76,70,84,55,0,107,78,88,84,51,0,107,78,88,84,52,0,107,78,88,84,53,0,107,78,88,84,54,0,107,78,88,84,55,0,107,80,82,86,51,0,107,80,82,86,52,0,107,80,82,86,53,0,107,80,82,86,54,0,107,80,82,86,55,0,107,82,73,84,51,0,107,82,73,84,52,0,107,82,73,84,53,0,107,82,73,84,54,0,107,82,73,84,55,0,107,85,80,0,107,85,80,51,0,107,85,80,52,0,107,85,80,53,0,107,85,80,54,0,107,85,80,55,0,107,97,50,0,107,98,49,0,107,98,51,0,107,99,50,0,107,112,53,0,107,112,65,68,68,0,107,112,67,77,65,0,107,112,68,73,86,0,107,112,68,79,84,0,107,112,77,85,76,0,107,112,83,85,66,0,107,112,90,82,79,0,107,120,73,78,0,107,120,79,85,84,0,114,109,120,120,0,114,118,0,115,109,120,120,0,120,109,0,120,114,0 + 30,2,71,0,38,0,15,0,-99,1,64,4,118,116,112,99,111,110,124,65,78,83,73,32,101,109,117,108,97,116,105,111,110,32,102,111,114,32,99,111,110,115,111,108,101,32,118,105,114,116,117,97,108,32,116,101,114,109,105,110,97,108,32,115,101,113,117,101,110,99,101,32,119,105,116,104,32,108,105,98,117,118,0,0,1,0,0,0,0,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,1,0,0,1,0,0,0,0,0,0,0,0,1,0,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,0,0,4,0,6,0,8,0,-2,-1,25,0,33,0,37,0,41,0,-1,-1,52,0,69,0,73,0,77,0,84,0,-1,-1,86,0,99,0,-1,-1,103,0,-2,-1,107,0,111,0,115,0,-1,-1,121,0,-2,-1,125,0,-126,0,-1,-1,-2,-1,-2,-1,-2,-1,-1,-1,-117,0,-112,0,-107,0,-102,0,-93,0,-89,0,-84,0,-1,-1,-2,-1,-75,0,-69,0,-2,-1,-1,-1,-63,0,-1,-1,-61,0,-1,-1,-1,-1,-1,-1,-51,0,-1,-1,-47,0,-1,-1,-1,-1,-1,-1,-45,0,-1,-1,-40,0,-1,-1,-1,-1,-1,-1,-1,-1,-36,0,-31,0,-25,0,-20,0,-15,0,-10,0,-5,0,1,1,7,1,13,1,19,1,24,1,-1,-1,29,1,-1,-1,33,1,38,1,43,1,47,1,54,1,-1,-1,61,1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,65,1,-1,-1,68,1,77,1,86,1,95,1,104,1,113,1,122,1,-125,1,-116,1,-107,1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,-98,1,-2,-1,-2,-1,-1,-1,-1,-1,-78,1,-75,1,-64,1,-61,1,-59,1,-56,1,-13,1,-1,-1,-10,1,-8,1,-1,-1,-1,-1,-1,-1,-3,1,1,2,5,2,9,2,13,2,-1,-1,-1,-1,17,2,-1,-1,40,2,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,44,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,48,2,53,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,57,2,-1,-1,-1,-1,64,2,-1,-1,-1,-1,-1,-1,-1,-1,71,2,78,2,85,2,-1,-1,-1,-1,92,2,-1,-1,99,2,-1,-1,-1,-1,-1,-1,106,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,113,2,119,2,125,2,-125,2,-119,2,-113,2,-107,2,-101,2,-95,2,-89,2,-83,2,-77,2,-71,2,-65,2,-59,2,-53,2,-47,2,-41,2,-35,2,-29,2,-23,2,-17,2,-11,2,-5,2,1,3,7,3,13,3,19,3,25,3,31,3,38,3,44,3,50,3,56,3,62,3,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,68,3,73,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,-2,-1,80,3,-2,-1,89,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-74,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-69,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-63,3,0,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,27,91,90,0,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,72,27,91,50,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,27,91,66,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,49,50,108,27,91,63,50,53,104,0,27,91,67,0,27,91,65,0,27,91,80,0,27,91,77,0,27,93,48,59,7,0,27,40,48,0,27,91,49,109,0,27,91,63,49,48,52,57,104,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,27,40,66,0,27,91,48,109,0,27,91,63,49,48,52,57,108,0,27,91,50,55,109,0,27,91,50,52,109,0,7,0,27,91,33,112,27,91,63,51,108,0,27,91,76,0,8,0,27,91,51,126,0,27,91,66,0,27,91,91,65,0,27,91,50,49,126,0,27,91,91,66,0,27,91,91,67,0,27,91,91,68,0,27,91,91,69,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,91,68,0,27,91,54,126,0,27,91,53,126,0,27,91,67,0,27,91,49,59,50,66,0,27,91,49,59,50,65,0,27,91,65,0,27,69,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,37,112,49,37,99,27,91,37,112,50,37,123,49,125,37,45,37,100,98,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,27,91,48,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,54,37,116,59,49,37,59,109,0,27,72,0,9,0,27,93,48,59,0,27,79,119,0,27,79,121,0,27,91,71,0,27,79,113,0,27,79,115,0,106,106,107,107,108,108,109,109,110,110,113,113,116,116,117,117,118,118,119,119,120,120,0,27,91,90,0,27,79,69,0,27,91,52,126,0,27,79,77,0,27,91,51,59,50,126,0,27,91,52,59,50,126,0,27,91,49,59,50,126,0,27,91,50,59,50,126,0,27,91,49,59,50,68,0,27,91,54,59,50,126,0,27,91,53,59,50,126,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,50,53,126,0,27,91,50,54,126,0,27,91,50,56,126,0,27,91,50,57,126,0,27,91,51,49,126,0,27,91,51,50,126,0,27,91,51,51,126,0,27,91,51,52,126,0,27,91,50,51,36,0,27,91,50,52,36,0,27,91,49,49,94,0,27,91,49,50,94,0,27,91,49,51,94,0,27,91,49,52,94,0,27,91,49,53,94,0,27,91,49,55,94,0,27,91,49,56,94,0,27,91,49,57,94,0,27,91,50,48,94,0,27,91,50,49,94,0,27,91,50,51,94,0,27,91,50,52,94,0,27,91,50,53,94,0,27,91,50,54,94,0,27,91,50,56,94,0,27,91,50,57,94,0,27,91,51,49,94,0,27,91,49,59,54,83,0,27,91,51,50,94,0,27,91,51,51,94,0,27,91,51,52,94,0,27,91,50,51,64,0,27,91,50,52,64,0,27,91,49,75,0,27,91,63,54,57,108,0,27,91,51,57,59,52,57,109,0,27,93,52,59,37,112,49,37,100,59,114,103,98,58,37,112,50,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,51,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,52,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,27,0,27,91,51,109,0,27,91,50,51,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,3,0,0,0,87,0,119,0,-127,2,1,1,1,0,0,0,9,0,-2,-1,-2,-1,18,0,-2,-1,23,0,30,0,37,0,42,0,48,0,58,0,-2,-1,63,0,69,0,78,0,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,87,0,-2,-1,-2,-1,-2,-1,-2,-1,-2,-1,94,0,98,0,102,0,106,0,110,0,114,0,118,0,122,0,126,0,-126,0,-122,0,-118,0,-114,0,-110,0,-2,-1,-106,0,-2,-1,-2,-1,-81,0,0,0,3,0,6,0,9,0,12,0,15,0,18,0,21,0,24,0,27,0,30,0,33,0,36,0,39,0,42,0,45,0,48,0,51,0,54,0,57,0,62,0,67,0,72,0,77,0,82,0,86,0,91,0,96,0,101,0,106,0,111,0,117,0,123,0,-127,0,-121,0,-115,0,-109,0,-103,0,-97,0,-91,0,-85,0,-80,0,-75,0,-70,0,-65,0,-60,0,-54,0,-48,0,-42,0,-36,0,-30,0,-24,0,-18,0,-12,0,-6,0,0,1,6,1,12,1,18,1,24,1,30,1,36,1,42,1,48,1,54,1,60,1,64,1,69,1,74,1,79,1,84,1,89,1,93,1,97,1,101,1,105,1,109,1,115,1,121,1,127,1,-123,1,-117,1,-111,1,-105,1,-100,1,-94,1,-89,1,-86,1,-81,1,-78,1,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,91,51,74,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,91,62,99,0,27,91,50,32,113,0,27,91,37,112,49,37,100,32,113,0,27,93,48,59,0,27,91,62,48,113,0,27,91,63,49,48,48,52,108,0,27,91,63,49,48,48,52,104,0,27,91,49,59,50,65,0,27,79,120,0,27,79,116,0,27,79,118,0,27,79,114,0,27,79,69,0,27,79,107,0,27,79,108,0,27,79,111,0,27,79,110,0,27,79,106,0,27,79,109,0,27,79,112,0,27,91,73,0,27,91,79,0,27,92,91,52,49,59,91,49,45,54,93,91,48,45,57,93,91,48,45,57,93,59,48,99,0,27,80,62,92,124,88,84,101,114,109,92,40,91,49,45,57,93,91,48,45,57,93,43,92,41,27,92,92,0,65,88,0,88,70,0,88,84,0,66,68,0,66,69,0,67,114,0,67,115,0,69,51,0,77,115,0,80,69,0,80,83,0,82,86,0,83,101,0,83,115,0,84,83,0,88,77,0,88,82,0,102,100,0,102,101,0,107,68,67,51,0,107,68,67,52,0,107,68,67,53,0,107,68,67,54,0,107,68,67,55,0,107,68,78,0,107,68,78,51,0,107,68,78,52,0,107,68,78,53,0,107,68,78,54,0,107,68,78,55,0,107,69,78,68,51,0,107,69,78,68,52,0,107,69,78,68,53,0,107,69,78,68,54,0,107,69,78,68,55,0,107,72,79,77,51,0,107,72,79,77,52,0,107,72,79,77,53,0,107,72,79,77,54,0,107,72,79,77,55,0,107,73,67,51,0,107,73,67,52,0,107,73,67,53,0,107,73,67,54,0,107,73,67,55,0,107,76,70,84,51,0,107,76,70,84,52,0,107,76,70,84,53,0,107,76,70,84,54,0,107,76,70,84,55,0,107,78,88,84,51,0,107,78,88,84,52,0,107,78,88,84,53,0,107,78,88,84,54,0,107,78,88,84,55,0,107,80,82,86,51,0,107,80,82,86,52,0,107,80,82,86,53,0,107,80,82,86,54,0,107,80,82,86,55,0,107,82,73,84,51,0,107,82,73,84,52,0,107,82,73,84,53,0,107,82,73,84,54,0,107,82,73,84,55,0,107,85,80,0,107,85,80,51,0,107,85,80,52,0,107,85,80,53,0,107,85,80,54,0,107,85,80,55,0,107,97,50,0,107,98,49,0,107,98,51,0,107,99,50,0,107,112,53,0,107,112,65,68,68,0,107,112,67,77,65,0,107,112,68,73,86,0,107,112,68,79,84,0,107,112,77,85,76,0,107,112,83,85,66,0,107,112,90,82,79,0,107,120,73,78,0,107,120,79,85,84,0,114,109,120,120,0,114,118,0,115,109,120,120,0,120,109,0,120,114,0 }; // win32con|ANSI emulation for libuv on legacy console, @@ -2114,6 +2570,8 @@ static const int8_t vtpcon_terminfo[] = { // user7@, // user8@, // user9@, +// Se=\E[0 q, +// Ss=\E[%p1%d q, static const int8_t win32con_terminfo[] = { 26,1,52,0,15,0,15,0,125,1,106,2,119,105,110,51,50,99,111,110,124,65,78,83,73,32,101,109,117,108,97,116,105,111,110,32,102,111,114,32,108,105,98,117,118,32,111,110,32,108,101,103,97,99,121,32,99,111,110,115,111,108,101,0,0,1,0,0,0,0,0,0,0,0,0,0,0,1,1,0,-1,-1,8,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,8,0,64,0,-1,-1,0,0,2,0,-1,-1,-1,-1,4,0,11,0,15,0,19,0,-1,-1,30,0,47,0,51,0,-1,-1,55,0,-1,-1,-1,-1,57,0,-1,-1,61,0,-1,-1,-2,-1,-2,-1,-1,-1,-1,-1,-2,-1,-1,-1,65,0,70,0,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,79,0,84,0,-2,-1,-1,-1,-2,-1,89,0,94,0,-1,-1,-2,-1,107,0,-2,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-1,-1,113,0,-1,-1,-1,-1,-1,-1,115,0,-1,-1,120,0,-1,-1,-1,-1,-1,-1,-1,-1,124,0,-127,0,-121,0,-116,0,-111,0,-106,0,-101,0,-95,0,-89,0,-83,0,-77,0,-72,0,-1,-1,-67,0,-1,-1,-63,0,-58,0,-53,0,-1,-1,-1,-1,-1,-1,-49,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-45,0,-1,-1,-2,-1,-2,-1,-42,0,-2,-1,-1,-1,-2,-1,-33,0,-24,0,-1,-1,-15,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-6,0,-3,0,8,1,-2,-1,-2,-1,11,1,-1,-1,-1,-1,49,1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,51,1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,55,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,60,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,62,1,-1,-1,-1,-1,69,1,-1,-1,-1,-1,-1,-1,-1,-1,76,1,83,1,90,1,-1,-1,-1,-1,97,1,-1,-1,104,1,-1,-1,-1,-1,-1,-1,111,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,118,1,124,1,-126,1,-120,1,-114,1,-108,1,-102,1,-96,1,-90,1,-84,1,-78,1,-72,1,-66,1,-60,1,-54,1,-48,1,-42,1,-36,1,-30,1,-24,1,-18,1,-12,1,-6,1,0,2,6,2,12,2,18,2,24,2,30,2,-1,-1,36,2,42,2,48,2,54,2,60,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,66,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,-2,-1,-2,-1,-2,-1,71,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,80,2,90,2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-2,-1,100,2,7,0,13,0,27,91,72,27,91,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,27,91,66,0,27,91,72,0,8,0,27,91,67,0,27,91,65,0,27,91,49,109,0,27,55,27,91,63,52,55,104,0,27,91,55,109,0,27,91,55,109,0,27,91,48,109,0,27,91,50,74,27,91,63,52,55,108,27,56,0,27,91,50,55,109,0,8,0,27,91,51,126,0,27,91,66,0,27,91,91,65,0,27,91,50,49,126,0,27,91,91,66,0,27,91,91,67,0,27,91,91,68,0,27,91,91,69,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,91,49,126,0,27,91,50,126,0,27,91,68,0,27,91,54,126,0,27,91,53,126,0,27,91,67,0,27,91,65,0,13,10,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,65,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,27,91,48,37,63,37,112,49,37,116,59,55,37,59,37,63,37,112,51,37,116,59,55,37,59,37,63,37,112,54,37,116,59,49,37,59,109,0,9,0,27,91,71,0,27,91,52,126,0,26,0,27,91,51,59,50,126,0,27,91,52,59,50,126,0,27,91,49,59,50,126,0,27,91,50,59,50,126,0,27,91,49,59,50,68,0,27,91,54,59,50,126,0,27,91,53,59,50,126,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,50,53,126,0,27,91,50,54,126,0,27,91,50,56,126,0,27,91,50,57,126,0,27,91,51,49,126,0,27,91,51,50,126,0,27,91,51,51,126,0,27,91,51,52,126,0,27,91,50,51,36,0,27,91,50,52,36,0,27,91,49,49,94,0,27,91,49,50,94,0,27,91,49,51,94,0,27,91,49,52,94,0,27,91,49,53,94,0,27,91,49,55,94,0,27,91,49,56,94,0,27,91,49,57,94,0,27,91,50,48,94,0,27,91,50,49,94,0,27,91,50,51,94,0,27,91,50,52,94,0,27,91,50,53,94,0,27,91,50,54,94,0,27,91,50,56,94,0,27,91,50,57,94,0,27,91,51,49,94,0,27,91,51,50,94,0,27,91,51,51,94,0,27,91,51,52,94,0,27,91,50,51,64,0,27,91,50,52,64,0,27,91,49,75,0,27,91,51,57,59,52,57,109,0,27,91,51,37,112,49,37,100,109,0,27,91,52,37,112,49,37,100,109,0,27,91,49,48,109,0,0,0,0,0,2,0,4,0,22,0,0,0,6,0,0,0,3,0,27,91,48,32,113,0,27,91,37,112,49,37,100,32,113,0,83,101,0,83,115,0 }; @@ -2129,6 +2587,9 @@ static const int8_t win32con_terminfo[] = { // move_standout_mode, // no_pad_char, // prtr_silent, +// AX, +// XF, +// XT, // columns#80, // init_tabs#8, // lines#24, @@ -2317,6 +2778,92 @@ static const int8_t win32con_terminfo[] = { // user7=\E[6n, // user8=\E[?%[;0123456789]c, // user9=\E[c, +// BD=\E[?2004l, +// BE=\E[?2004h, +// Cr=\E]112^G, +// Cs=\E]12;%p1%s^G, +// E3=\E[3J, +// Ms=\E]52;%p1%s;%p2%s^G, +// PE=\E[201~, +// PS=\E[200~, +// RV=\E[>c, +// Se=\E[2 q, +// Ss=\E[%p1%d q, +// XM=\E[?1006;1000%?%p1%{1}%=%th%el%;, +// XR=\E[>0q, +// fd=\E[?1004l, +// fe=\E[?1004h, +// kDC3=\E[3;3~, +// kDC4=\E[3;4~, +// kDC5=\E[3;5~, +// kDC6=\E[3;6~, +// kDC7=\E[3;7~, +// kDN=\E[1;2B, +// kDN3=\E[1;3B, +// kDN4=\E[1;4B, +// kDN5=\E[1;5B, +// kDN6=\E[1;6B, +// kDN7=\E[1;7B, +// kEND3=\E[1;3F, +// kEND4=\E[1;4F, +// kEND5=\E[1;5F, +// kEND6=\E[1;6F, +// kEND7=\E[1;7F, +// kHOM3=\E[1;3H, +// kHOM4=\E[1;4H, +// kHOM5=\E[1;5H, +// kHOM6=\E[1;6H, +// kHOM7=\E[1;7H, +// kIC3=\E[2;3~, +// kIC4=\E[2;4~, +// kIC5=\E[2;5~, +// kIC6=\E[2;6~, +// kIC7=\E[2;7~, +// kLFT3=\E[1;3D, +// kLFT4=\E[1;4D, +// kLFT5=\E[1;5D, +// kLFT6=\E[1;6D, +// kLFT7=\E[1;7D, +// kNXT3=\E[6;3~, +// kNXT4=\E[6;4~, +// kNXT5=\E[6;5~, +// kNXT6=\E[6;6~, +// kNXT7=\E[6;7~, +// kPRV3=\E[5;3~, +// kPRV4=\E[5;4~, +// kPRV5=\E[5;5~, +// kPRV6=\E[5;6~, +// kPRV7=\E[5;7~, +// kRIT3=\E[1;3C, +// kRIT4=\E[1;4C, +// kRIT5=\E[1;5C, +// kRIT6=\E[1;6C, +// kRIT7=\E[1;7C, +// kUP=\E[1;2A, +// kUP3=\E[1;3A, +// kUP4=\E[1;4A, +// kUP5=\E[1;5A, +// kUP6=\E[1;6A, +// kUP7=\E[1;7A, +// ka2=\EOx, +// kb1=\EOt, +// kb3=\EOv, +// kc2=\EOr, +// kp5=\EOE, +// kpADD=\EOk, +// kpCMA=\EOl, +// kpDIV=\EOo, +// kpDOT=\EOn, +// kpMUL=\EOj, +// kpSUB=\EOm, +// kpZRO=\EOp, +// kxIN=\E[I, +// kxOUT=\E[O, +// rmxx=\E[29m, +// rv=\E\[41;[1-6][0-9][0-9];0c, +// smxx=\E[9m, +// xm=\E[<%i%p3%d;%p1%d;%p2%d;%?%p4%tM%em%;, +// xr=\EP>\|XTerm\([1-9][0-9]+\)\E\\, static const int8_t xterm_256colour_terminfo[] = { 30,2,37,0,38,0,15,0,-99,1,90,6,120,116,101,114,109,45,50,53,54,99,111,108,111,114,124,120,116,101,114,109,32,119,105,116,104,32,50,53,54,32,99,111,108,111,114,115,0,0,1,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,1,0,0,1,0,1,1,0,0,0,0,0,0,0,0,1,0,80,0,0,0,8,0,0,0,24,0,0,0,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,0,1,0,0,0,0,1,0,0,0,4,0,6,0,8,0,25,0,30,0,38,0,42,0,46,0,-1,-1,57,0,74,0,76,0,80,0,87,0,-1,-1,89,0,102,0,-1,-1,106,0,110,0,120,0,124,0,-1,-1,-1,-1,-128,0,-124,0,-119,0,-114,0,-1,-1,-96,0,-91,0,-86,0,-1,-1,-81,0,-76,0,-71,0,-66,0,-57,0,-53,0,-46,0,-1,-1,-28,0,-23,0,-17,0,-11,0,-1,-1,-1,-1,-1,-1,7,1,-1,-1,-1,-1,-1,-1,25,1,-1,-1,29,1,-1,-1,-1,-1,-1,-1,31,1,-1,-1,36,1,-1,-1,-1,-1,-1,-1,-1,-1,40,1,44,1,50,1,54,1,58,1,62,1,68,1,74,1,80,1,86,1,92,1,96,1,-1,-1,101,1,-1,-1,105,1,110,1,115,1,119,1,126,1,-1,-1,-123,1,-119,1,-111,1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-103,1,-94,1,-85,1,-1,-1,-82,1,-73,1,-64,1,-55,1,-46,1,-37,1,-28,1,-19,1,-10,1,-1,1,-1,-1,-1,-1,-1,-1,8,2,12,2,17,2,22,2,42,2,51,2,-1,-1,-1,-1,69,2,72,2,83,2,86,2,88,2,91,2,-72,2,-1,-1,-69,2,-1,-1,-1,-1,-1,-1,-1,-1,-67,2,-63,2,-59,2,-55,2,-51,2,-1,-1,-1,-1,-47,2,-1,-1,6,3,-1,-1,-1,-1,10,3,16,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,22,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,26,3,30,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,34,3,-1,-1,-1,-1,41,3,-1,-1,-1,-1,-1,-1,-1,-1,48,3,55,3,62,3,-1,-1,-1,-1,69,3,-1,-1,76,3,-1,-1,-1,-1,-1,-1,83,3,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,90,3,96,3,102,3,109,3,116,3,123,3,-126,3,-118,3,-110,3,-102,3,-94,3,-86,3,-78,3,-70,3,-62,3,-55,3,-48,3,-41,3,-34,3,-26,3,-18,3,-10,3,-2,3,6,4,14,4,22,4,30,4,37,4,44,4,51,4,58,4,66,4,74,4,82,4,90,4,98,4,106,4,114,4,122,4,-127,4,-120,4,-113,4,-106,4,-98,4,-90,4,-82,4,-74,4,-66,4,-58,4,-50,4,-42,4,-35,4,-28,4,-21,4,-16,4,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-9,4,2,5,7,5,26,5,30,5,39,5,46,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-116,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-111,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-105,5,-88,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-70,5,-1,-1,-1,-1,-1,-1,-66,5,-3,5,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,61,6,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,84,6,87,6,27,91,90,0,7,0,13,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,114,0,27,91,51,103,0,27,91,72,27,91,50,74,0,27,91,75,0,27,91,74,0,27,91,37,105,37,112,49,37,100,71,0,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,72,0,10,0,27,91,72,0,27,91,63,50,53,108,0,8,0,27,91,63,49,50,108,27,91,63,50,53,104,0,27,91,67,0,27,91,65,0,27,91,63,49,50,59,50,53,104,0,27,91,80,0,27,91,77,0,27,40,48,0,27,91,53,109,0,27,91,49,109,0,27,91,63,49,48,52,57,104,27,91,50,50,59,48,59,48,116,0,27,91,50,109,0,27,91,52,104,0,27,91,56,109,0,27,91,55,109,0,27,91,55,109,0,27,91,52,109,0,27,91,37,112,49,37,100,88,0,27,40,66,0,27,40,66,27,91,109,0,27,91,63,49,48,52,57,108,27,91,50,51,59,48,59,48,116,0,27,91,52,108,0,27,91,50,55,109,0,27,91,50,52,109,0,27,91,63,53,104,36,60,49,48,48,47,62,27,91,63,53,108,0,27,91,33,112,27,91,63,51,59,52,108,27,91,52,108,27,62,0,27,91,76,0,8,0,27,91,51,126,0,27,79,66,0,27,79,80,0,27,91,50,49,126,0,27,79,81,0,27,79,82,0,27,79,83,0,27,91,49,53,126,0,27,91,49,55,126,0,27,91,49,56,126,0,27,91,49,57,126,0,27,91,50,48,126,0,27,79,72,0,27,91,50,126,0,27,79,68,0,27,91,54,126,0,27,91,53,126,0,27,79,67,0,27,91,49,59,50,66,0,27,91,49,59,50,65,0,27,79,65,0,27,91,63,49,108,27,62,0,27,91,63,49,104,27,61,0,27,91,63,49,48,51,52,108,0,27,91,63,49,48,51,52,104,0,27,69,0,27,91,37,112,49,37,100,80,0,27,91,37,112,49,37,100,77,0,27,91,37,112,49,37,100,66,0,27,91,37,112,49,37,100,64,0,27,91,37,112,49,37,100,83,0,27,91,37,112,49,37,100,76,0,27,91,37,112,49,37,100,68,0,27,91,37,112,49,37,100,67,0,27,91,37,112,49,37,100,84,0,27,91,37,112,49,37,100,65,0,27,91,105,0,27,91,52,105,0,27,91,53,105,0,37,112,49,37,99,27,91,37,112,50,37,123,49,125,37,45,37,100,98,0,27,99,27,93,49,48,52,7,0,27,91,33,112,27,91,63,51,59,52,108,27,91,52,108,27,62,0,27,56,0,27,91,37,105,37,112,49,37,100,100,0,27,55,0,10,0,27,77,0,37,63,37,112,57,37,116,27,40,48,37,101,27,40,66,37,59,27,91,48,37,63,37,112,54,37,116,59,49,37,59,37,63,37,112,53,37,116,59,50,37,59,37,63,37,112,50,37,116,59,52,37,59,37,63,37,112,49,37,112,51,37,124,37,116,59,55,37,59,37,63,37,112,52,37,116,59,53,37,59,37,63,37,112,55,37,116,59,56,37,59,109,0,27,72,0,9,0,27,79,119,0,27,79,121,0,27,79,117,0,27,79,113,0,27,79,115,0,96,96,97,97,102,102,103,103,105,105,106,106,107,107,108,108,109,109,110,110,111,111,112,112,113,113,114,114,115,115,116,116,117,117,118,118,119,119,120,120,121,121,122,122,123,123,124,124,125,125,126,126,0,27,91,90,0,27,91,63,55,104,0,27,91,63,55,108,0,27,79,69,0,27,79,70,0,27,79,77,0,27,91,51,59,50,126,0,27,91,49,59,50,70,0,27,91,49,59,50,72,0,27,91,50,59,50,126,0,27,91,49,59,50,68,0,27,91,54,59,50,126,0,27,91,53,59,50,126,0,27,91,49,59,50,67,0,27,91,50,51,126,0,27,91,50,52,126,0,27,91,49,59,50,80,0,27,91,49,59,50,81,0,27,91,49,59,50,82,0,27,91,49,59,50,83,0,27,91,49,53,59,50,126,0,27,91,49,55,59,50,126,0,27,91,49,56,59,50,126,0,27,91,49,57,59,50,126,0,27,91,50,48,59,50,126,0,27,91,50,49,59,50,126,0,27,91,50,51,59,50,126,0,27,91,50,52,59,50,126,0,27,91,49,59,53,80,0,27,91,49,59,53,81,0,27,91,49,59,53,82,0,27,91,49,59,53,83,0,27,91,49,53,59,53,126,0,27,91,49,55,59,53,126,0,27,91,49,56,59,53,126,0,27,91,49,57,59,53,126,0,27,91,50,48,59,53,126,0,27,91,50,49,59,53,126,0,27,91,50,51,59,53,126,0,27,91,50,52,59,53,126,0,27,91,49,59,54,80,0,27,91,49,59,54,81,0,27,91,49,59,54,82,0,27,91,49,59,54,83,0,27,91,49,53,59,54,126,0,27,91,49,55,59,54,126,0,27,91,49,56,59,54,126,0,27,91,49,57,59,54,126,0,27,91,50,48,59,54,126,0,27,91,50,49,59,54,126,0,27,91,50,51,59,54,126,0,27,91,50,52,59,54,126,0,27,91,49,59,51,80,0,27,91,49,59,51,81,0,27,91,49,59,51,82,0,27,91,49,59,51,83,0,27,91,49,53,59,51,126,0,27,91,49,55,59,51,126,0,27,91,49,56,59,51,126,0,27,91,49,57,59,51,126,0,27,91,50,48,59,51,126,0,27,91,50,49,59,51,126,0,27,91,50,51,59,51,126,0,27,91,50,52,59,51,126,0,27,91,49,59,52,80,0,27,91,49,59,52,81,0,27,91,49,59,52,82,0,27,91,49,75,0,27,91,63,54,57,108,0,27,91,37,105,37,100,59,37,100,82,0,27,91,54,110,0,27,91,63,37,91,59,48,49,50,51,52,53,54,55,56,57,93,99,0,27,91,99,0,27,91,51,57,59,52,57,109,0,27,93,49,48,52,7,0,27,93,52,59,37,112,49,37,100,59,114,103,98,58,37,112,50,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,51,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,47,37,112,52,37,123,50,53,53,125,37,42,37,123,49,48,48,48,125,37,47,37,50,46,50,88,27,92,0,27,91,51,109,0,27,91,50,51,109,0,27,91,63,54,57,104,27,91,37,105,37,112,49,37,100,115,0,27,91,63,54,57,104,27,91,37,105,59,37,112,49,37,100,115,0,27,91,60,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,51,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,57,37,112,49,37,123,56,125,37,45,37,100,37,101,51,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,37,63,37,112,49,37,123,56,125,37,60,37,116,52,37,112,49,37,100,37,101,37,112,49,37,123,49,54,125,37,60,37,116,49,48,37,112,49,37,123,56,125,37,45,37,100,37,101,52,56,59,53,59,37,112,49,37,100,37,59,109,0,27,91,63,54,57,104,27,91,37,105,37,112,49,37,100,59,37,112,50,37,100,115,0,27,108,0,27,109,0,3,0,0,0,86,0,-81,0,83,4,1,1,1,0,0,0,9,0,18,0,25,0,37,0,42,0,60,0,67,0,74,0,79,0,85,0,95,0,127,0,-123,0,-114,0,-105,0,-98,0,-91,0,-84,0,-77,0,-70,0,-63,0,-56,0,-49,0,-42,0,-35,0,-28,0,-21,0,-14,0,-7,0,0,1,7,1,14,1,21,1,28,1,35,1,42,1,49,1,56,1,63,1,70,1,77,1,84,1,91,1,98,1,105,1,112,1,119,1,126,1,-123,1,-116,1,-109,1,-102,1,-95,1,-88,1,-81,1,-74,1,-67,1,-60,1,-53,1,-46,1,-39,1,-32,1,-25,1,-18,1,-11,1,-4,1,3,2,7,2,11,2,15,2,19,2,23,2,27,2,31,2,35,2,39,2,43,2,47,2,51,2,55,2,59,2,65,2,90,2,95,2,-124,2,0,0,3,0,6,0,9,0,12,0,15,0,18,0,21,0,24,0,27,0,30,0,33,0,36,0,39,0,42,0,45,0,48,0,51,0,54,0,59,0,64,0,69,0,74,0,79,0,83,0,88,0,93,0,98,0,103,0,108,0,114,0,120,0,126,0,-124,0,-118,0,-112,0,-106,0,-100,0,-94,0,-88,0,-83,0,-78,0,-73,0,-68,0,-63,0,-57,0,-51,0,-45,0,-39,0,-33,0,-27,0,-21,0,-15,0,-9,0,-3,0,3,1,9,1,15,1,21,1,27,1,33,1,39,1,45,1,51,1,57,1,61,1,66,1,71,1,76,1,81,1,86,1,90,1,94,1,98,1,102,1,106,1,112,1,118,1,124,1,-126,1,-120,1,-114,1,-108,1,-103,1,-97,1,-92,1,-89,1,-84,1,-81,1,27,91,63,50,48,48,52,108,0,27,91,63,50,48,48,52,104,0,27,93,49,49,50,7,0,27,93,49,50,59,37,112,49,37,115,7,0,27,91,51,74,0,27,93,53,50,59,37,112,49,37,115,59,37,112,50,37,115,7,0,27,91,50,48,49,126,0,27,91,50,48,48,126,0,27,91,62,99,0,27,91,50,32,113,0,27,91,37,112,49,37,100,32,113,0,27,91,63,49,48,48,54,59,49,48,48,48,37,63,37,112,49,37,123,49,125,37,61,37,116,104,37,101,108,37,59,0,27,91,62,48,113,0,27,91,63,49,48,48,52,108,0,27,91,63,49,48,48,52,104,0,27,91,51,59,51,126,0,27,91,51,59,52,126,0,27,91,51,59,53,126,0,27,91,51,59,54,126,0,27,91,51,59,55,126,0,27,91,49,59,50,66,0,27,91,49,59,51,66,0,27,91,49,59,52,66,0,27,91,49,59,53,66,0,27,91,49,59,54,66,0,27,91,49,59,55,66,0,27,91,49,59,51,70,0,27,91,49,59,52,70,0,27,91,49,59,53,70,0,27,91,49,59,54,70,0,27,91,49,59,55,70,0,27,91,49,59,51,72,0,27,91,49,59,52,72,0,27,91,49,59,53,72,0,27,91,49,59,54,72,0,27,91,49,59,55,72,0,27,91,50,59,51,126,0,27,91,50,59,52,126,0,27,91,50,59,53,126,0,27,91,50,59,54,126,0,27,91,50,59,55,126,0,27,91,49,59,51,68,0,27,91,49,59,52,68,0,27,91,49,59,53,68,0,27,91,49,59,54,68,0,27,91,49,59,55,68,0,27,91,54,59,51,126,0,27,91,54,59,52,126,0,27,91,54,59,53,126,0,27,91,54,59,54,126,0,27,91,54,59,55,126,0,27,91,53,59,51,126,0,27,91,53,59,52,126,0,27,91,53,59,53,126,0,27,91,53,59,54,126,0,27,91,53,59,55,126,0,27,91,49,59,51,67,0,27,91,49,59,52,67,0,27,91,49,59,53,67,0,27,91,49,59,54,67,0,27,91,49,59,55,67,0,27,91,49,59,50,65,0,27,91,49,59,51,65,0,27,91,49,59,52,65,0,27,91,49,59,53,65,0,27,91,49,59,54,65,0,27,91,49,59,55,65,0,27,79,120,0,27,79,116,0,27,79,118,0,27,79,114,0,27,79,69,0,27,79,107,0,27,79,108,0,27,79,111,0,27,79,110,0,27,79,106,0,27,79,109,0,27,79,112,0,27,91,73,0,27,91,79,0,27,91,50,57,109,0,27,92,91,52,49,59,91,49,45,54,93,91,48,45,57,93,91,48,45,57,93,59,48,99,0,27,91,57,109,0,27,91,60,37,105,37,112,51,37,100,59,37,112,49,37,100,59,37,112,50,37,100,59,37,63,37,112,52,37,116,77,37,101,109,37,59,0,27,80,62,92,124,88,84,101,114,109,92,40,91,49,45,57,93,91,48,45,57,93,43,92,41,27,92,92,0,65,88,0,88,70,0,88,84,0,66,68,0,66,69,0,67,114,0,67,115,0,69,51,0,77,115,0,80,69,0,80,83,0,82,86,0,83,101,0,83,115,0,88,77,0,88,82,0,102,100,0,102,101,0,107,68,67,51,0,107,68,67,52,0,107,68,67,53,0,107,68,67,54,0,107,68,67,55,0,107,68,78,0,107,68,78,51,0,107,68,78,52,0,107,68,78,53,0,107,68,78,54,0,107,68,78,55,0,107,69,78,68,51,0,107,69,78,68,52,0,107,69,78,68,53,0,107,69,78,68,54,0,107,69,78,68,55,0,107,72,79,77,51,0,107,72,79,77,52,0,107,72,79,77,53,0,107,72,79,77,54,0,107,72,79,77,55,0,107,73,67,51,0,107,73,67,52,0,107,73,67,53,0,107,73,67,54,0,107,73,67,55,0,107,76,70,84,51,0,107,76,70,84,52,0,107,76,70,84,53,0,107,76,70,84,54,0,107,76,70,84,55,0,107,78,88,84,51,0,107,78,88,84,52,0,107,78,88,84,53,0,107,78,88,84,54,0,107,78,88,84,55,0,107,80,82,86,51,0,107,80,82,86,52,0,107,80,82,86,53,0,107,80,82,86,54,0,107,80,82,86,55,0,107,82,73,84,51,0,107,82,73,84,52,0,107,82,73,84,53,0,107,82,73,84,54,0,107,82,73,84,55,0,107,85,80,0,107,85,80,51,0,107,85,80,52,0,107,85,80,53,0,107,85,80,54,0,107,85,80,55,0,107,97,50,0,107,98,49,0,107,98,51,0,107,99,50,0,107,112,53,0,107,112,65,68,68,0,107,112,67,77,65,0,107,112,68,73,86,0,107,112,68,79,84,0,107,112,77,85,76,0,107,112,83,85,66,0,107,112,90,82,79,0,107,120,73,78,0,107,120,79,85,84,0,114,109,120,120,0,114,118,0,115,109,120,120,0,120,109,0,120,114,0 }; diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 7fae34d33f..2a9530defb 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -23,6 +23,7 @@ #include "nvim/globals.h" #include "nvim/grid.h" #include "nvim/grid_defs.h" +#include "nvim/highlight.h" #include "nvim/highlight_defs.h" #include "nvim/log.h" #include "nvim/macros_defs.h" @@ -165,6 +166,15 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term, bool *rgb) tui->seen_error_exit = 0; tui->loop = &main_loop; tui->url = -1; + // Because setting the default colors is delayed until after startup to avoid + // flickering with the default colorscheme background, any flush that happens + // during startup in turn would result in clearing invalidated regions with + // uninitialized attrs(black). Instead initialize clear_attrs with current + // terminal background so that it is at least not perceived as flickering, even + // though it may be different from the colorscheme that is set during startup. + tui->clear_attrs.rgb_bg_color = normal_bg; + tui->clear_attrs.cterm_bg_color = (int16_t)cterm_normal_bg_color; + kv_init(tui->invalid_regions); kv_init(tui->urlbuf); signal_watcher_init(tui->loop, &tui->winch_handle, tui); @@ -189,36 +199,6 @@ void tui_start(TUIData **tui_p, int *width, int *height, char **term, bool *rgb) *rgb = tui->rgb; } -void tui_set_key_encoding(TUIData *tui) - FUNC_ATTR_NONNULL_ALL -{ - switch (tui->input.key_encoding) { - case kKeyEncodingKitty: - out(tui, S_LEN("\x1b[>1u")); - break; - case kKeyEncodingXterm: - out(tui, S_LEN("\x1b[>4;2m")); - break; - case kKeyEncodingLegacy: - break; - } -} - -static void tui_reset_key_encoding(TUIData *tui) - FUNC_ATTR_NONNULL_ALL -{ - switch (tui->input.key_encoding) { - case kKeyEncodingKitty: - out(tui, S_LEN("\x1b[<1u")); - break; - case kKeyEncodingXterm: - out(tui, S_LEN("\x1b[>4;0m")); - break; - case kKeyEncodingLegacy: - break; - } -} - /// Request the terminal's mode (DECRQM). /// /// @see handle_modereport @@ -255,6 +235,26 @@ void tui_handle_term_mode(TUIData *tui, TermMode mode, TermModeState state) } } +/// Query the terminal emulator to see if it supports extended underline. +static void tui_query_extended_underline(TUIData *tui) +{ + // Try to set an undercurl using an SGR sequence, followed by a DECRQSS SGR query. + // Reset attributes first, as other code may have set attributes. + out(tui, S_LEN("\x1b[0m\x1b[4:3m\x1bP$qm\x1b\\")); + tui->print_attr_id = -1; +} + +void tui_enable_extended_underline(TUIData *tui) +{ + if (tui->unibi_ext.set_underline_style == -1) { + tui->unibi_ext.set_underline_style = (int)unibi_add_ext_str(tui->ut, "ext.set_underline_style", + "\x1b[4:%p1%dm"); + } + // Only support colon syntax. #9270 + tui->unibi_ext.set_underline_color = (int)unibi_add_ext_str(tui->ut, "ext.set_underline_color", + "\x1b[58:2::%p1%d:%p2%d:%p3%dm"); +} + /// Query the terminal emulator to see if it supports Kitty's keyboard protocol. /// /// Write CSI ? u followed by a primary device attributes request (CSI c). If @@ -270,6 +270,36 @@ static void tui_query_kitty_keyboard(TUIData *tui) out(tui, S_LEN("\x1b[?u\x1b[c")); } +void tui_set_key_encoding(TUIData *tui) + FUNC_ATTR_NONNULL_ALL +{ + switch (tui->input.key_encoding) { + case kKeyEncodingKitty: + out(tui, S_LEN("\x1b[>1u")); + break; + case kKeyEncodingXterm: + out(tui, S_LEN("\x1b[>4;2m")); + break; + case kKeyEncodingLegacy: + break; + } +} + +static void tui_reset_key_encoding(TUIData *tui) + FUNC_ATTR_NONNULL_ALL +{ + switch (tui->input.key_encoding) { + case kKeyEncodingKitty: + out(tui, S_LEN("\x1b[<1u")); + break; + case kKeyEncodingXterm: + out(tui, S_LEN("\x1b[>4;0m")); + break; + case kKeyEncodingLegacy: + break; + } +} + /// Enable the alternate screen and emit other control sequences to start the TUI. /// /// This is also called when the TUI is resumed after being suspended. We reinitialize all state @@ -306,6 +336,7 @@ static void terminfo_start(TUIData *tui) tui->unibi_ext.reset_scroll_region = -1; tui->unibi_ext.set_cursor_style = -1; tui->unibi_ext.reset_cursor_style = -1; + tui->unibi_ext.set_underline_style = -1; tui->unibi_ext.set_underline_color = -1; tui->unibi_ext.sync = -1; tui->out_fd = STDOUT_FILENO; @@ -347,12 +378,16 @@ static void terminfo_start(TUIData *tui) const char *konsolev_env = os_getenv("KONSOLE_VERSION"); int konsolev = konsolev_env ? (int)strtol(konsolev_env, NULL, 10) : (konsole ? 1 : 0); + bool wezterm = strequal(termprg, "WezTerm"); + const char *weztermv = wezterm ? os_getenv("TERM_PROGRAM_VERSION") : NULL; + bool screen = terminfo_is_term_family(term, "screen"); + bool tmux = terminfo_is_term_family(term, "tmux") || !!os_getenv("TMUX"); // truecolor support must be checked before patching/augmenting terminfo tui->rgb = term_has_truecolor(tui, colorterm); patch_terminfo_bugs(tui, term, colorterm, vtev, konsolev, iterm_env, nsterm); - augment_terminfo(tui, term, vtev, konsolev, iterm_env, nsterm); + augment_terminfo(tui, term, vtev, konsolev, weztermv, iterm_env, nsterm); tui->can_change_scroll_region = !!unibi_get_str(tui->ut, unibi_change_scroll_region); tui->can_set_lr_margin = @@ -385,8 +420,18 @@ static void terminfo_start(TUIData *tui) // Query support for mode 2026 (Synchronized Output). Some terminals also // support an older DCS sequence for synchronized output, but we will only use - // mode 2026 - tui_request_term_mode(tui, kTermModeSynchronizedOutput); + // mode 2026. + // Some terminals (such as Terminal.app) do not support DECRQM, so skip the query. + if (!nsterm) { + tui_request_term_mode(tui, kTermModeSynchronizedOutput); + } + + // Don't use DECRQSS in screen or tmux, as they behave strangely when receiving it. + // Terminal.app also doesn't support DECRQSS. + if (tui->unibi_ext.set_underline_style == -1 && !(screen || tmux || nsterm)) { + // Query the terminal to see if it supports extended underline. + tui_query_extended_underline(tui); + } // Query the terminal to see if it supports Kitty's keyboard protocol tui_query_kitty_keyboard(tui); @@ -457,10 +502,6 @@ static void terminfo_stop(TUIData *tui) // Disable focus reporting unibi_out_ext(tui, tui->unibi_ext.disable_focus_reporting); - // Disable synchronized output - UNIBI_SET_NUM_VAR(tui->params[0], 0); - unibi_out_ext(tui, tui->unibi_ext.sync); - flush_buf(tui); uv_tty_reset_mode(); uv_close((uv_handle_t *)&tui->output_handle, NULL); @@ -932,17 +973,17 @@ static void print_spaces(TUIData *tui, int width) } } -/// Move cursor to the position given by `row` and `col` and print the character in `cell`. -/// This allows the grid and the host terminal to assume different widths of ambiguous-width chars. +/// Move cursor to the position given by `row` and `col` and print the char in `cell`. +/// Allows grid and host terminal to assume different widths of ambiguous-width chars. /// -/// @param is_doublewidth whether the character is double-width on the grid. -/// If true and the character is ambiguous-width, clear two cells. +/// @param is_doublewidth whether the char is double-width on the grid. +/// If true and the char is ambiguous-width, clear two cells. static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool is_doublewidth) { UGrid *grid = &tui->grid; if (grid->row == -1 && cell->data == NUL) { - // If cursor needs to repositioned and there is nothing to print, don't move cursor. + // If cursor needs repositioning and there is nothing to print, don't move cursor. return; } @@ -950,10 +991,14 @@ static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool char buf[MAX_SCHAR_SIZE]; schar_get(buf, cell->data); - bool is_ambiwidth = utf_ambiguous_width(utf_ptr2char(buf)); - if (is_ambiwidth && is_doublewidth) { + int c = utf_ptr2char(buf); + bool is_ambiwidth = utf_ambiguous_width(c); + if (is_doublewidth && (is_ambiwidth || utf_char2cells(c) == 1)) { + // If the server used setcellwidths() to treat a single-width char as double-width, + // it needs to be treated like an ambiguous-width char. + is_ambiwidth = true; // Clear the two screen cells. - // If the character is single-width in the host terminal it won't change the second cell. + // If the char is single-width in host terminal it won't change the second cell. update_attrs(tui, cell->attr); print_spaces(tui, 2); cursor_goto(tui, row, col); @@ -962,7 +1007,7 @@ static void print_cell_at_pos(TUIData *tui, int row, int col, UCell *cell, bool print_cell(tui, buf, cell->attr); if (is_ambiwidth) { - // Force repositioning cursor after printing an ambiguous-width character. + // Force repositioning cursor after printing an ambiguous-width char. grid->row = -1; } } @@ -1206,7 +1251,7 @@ static void tui_set_mode(TUIData *tui, ModeShape mode) // We interpret "inverse" as "default" (no termcode for "inverse"...). // Hopefully the user's default cursor color is inverse. unibi_out_ext(tui, tui->unibi_ext.reset_cursor_color); - } else { + } else if (!tui->want_invisible && aep.rgb_bg_color >= 0) { char hexbuf[8]; if (tui->set_cursor_color_as_str) { snprintf(hexbuf, 7 + 1, "#%06x", aep.rgb_bg_color); @@ -1643,7 +1688,7 @@ static void invalidate(TUIData *tui, int top, int bot, int left, int right) static void ensure_space_buf_size(TUIData *tui, size_t len) { if (len > tui->space_buf_len) { - tui->space_buf = xrealloc(tui->space_buf, len * sizeof *tui->space_buf); + tui->space_buf = xrealloc(tui->space_buf, len); memset(tui->space_buf + tui->space_buf_len, ' ', len - tui->space_buf_len); tui->space_buf_len = len; } @@ -2168,7 +2213,7 @@ static void patch_terminfo_bugs(TUIData *tui, const char *term, const char *colo /// This adds stuff that is not in standard terminfo as extended unibilium /// capabilities. static void augment_terminfo(TUIData *tui, const char *term, int vte_version, int konsolev, - bool iterm_env, bool nsterm) + const char *weztermv, bool iterm_env, bool nsterm) { unibi_term *ut = tui->ut; bool xterm = terminfo_is_term_family(term, "xterm") @@ -2327,16 +2372,12 @@ static void augment_terminfo(TUIData *tui, const char *term, int vte_version, in if (tui->unibi_ext.set_underline_style == -1) { int ext_bool_Su = unibi_find_ext_bool(ut, "Su"); // used by kitty if (vte_version >= 5102 || konsolev >= 221170 - || (ext_bool_Su != -1 - && unibi_get_ext_bool(ut, (size_t)ext_bool_Su))) { - tui->unibi_ext.set_underline_style = (int)unibi_add_ext_str(ut, "ext.set_underline_style", - "\x1b[4:%p1%dm"); + || (ext_bool_Su != -1 && unibi_get_ext_bool(ut, (size_t)ext_bool_Su)) + || (weztermv != NULL && strcmp(weztermv, "20210203-095643") > 0)) { + tui_enable_extended_underline(tui); } - } - if (tui->unibi_ext.set_underline_style != -1) { - // Only support colon syntax. #9270 - tui->unibi_ext.set_underline_color = (int)unibi_add_ext_str(ut, "ext.set_underline_color", - "\x1b[58:2::%p1%d:%p2%d:%p3%dm"); + } else { + tui_enable_extended_underline(tui); } if (!kitty && (vte_version == 0 || vte_version >= 5400)) { diff --git a/src/nvim/ui.c b/src/nvim/ui.c index bddcf98b53..9bb66b886e 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -71,8 +71,6 @@ static bool has_mouse = false; static int pending_has_mouse = -1; static bool pending_default_colors = false; -static Array call_buf = ARRAY_DICT_INIT; - #ifdef NVIM_LOG_DEBUG static size_t uilog_seen = 0; static const char *uilog_last_event = NULL; @@ -128,14 +126,11 @@ void ui_init(void) default_grid.handle = 1; msg_grid_adj.target = &default_grid; ui_comp_init(); - kv_ensure_space(call_buf, 16); } #ifdef EXITFREE void ui_free_all_mem(void) { - kv_destroy(call_buf); - UIEventCallback *event_cb; map_foreach_value(&ui_event_cbs, event_cb, { free_ui_event_callback(event_cb); @@ -194,23 +189,12 @@ void ui_refresh(void) abort(); } - if (!ui_active()) { - return; - } - - if (updating_screen) { - ui_schedule_refresh(); - return; - } - int width = INT_MAX; int height = INT_MAX; bool ext_widgets[kUIExtCount]; - for (UIExtension i = 0; (int)i < kUIExtCount; i++) { - ext_widgets[i] = true; - } - bool inclusive = ui_override(); + memset(ext_widgets, ui_active(), ARRAY_SIZE(ext_widgets)); + for (size_t i = 0; i < ui_count; i++) { RemoteUI *ui = uis[i]; width = MIN(ui->width, width); @@ -227,13 +211,29 @@ void ui_refresh(void) if (i < kUIGlobalCount) { ext_widgets[i] |= ui_cb_ext[i]; } + // Set 'cmdheight' to zero for all tabpages when ext_messages becomes active. + if (i == kUIMessages && !ui_ext[i] && ext_widgets[i]) { + set_option_value(kOptCmdheight, NUMBER_OPTVAL(0), 0); + command_height(); + FOR_ALL_TABS(tp) { + tp->tp_ch_used = 0; + } + } ui_ext[i] = ext_widgets[i]; if (i < kUIGlobalCount) { - ui_call_option_set(cstr_as_string(ui_ext_names[i]), - BOOLEAN_OBJ(ext_widgets[i])); + ui_call_option_set(cstr_as_string(ui_ext_names[i]), BOOLEAN_OBJ(ext_widgets[i])); } } + if (!ui_active()) { + return; + } + + if (updating_screen) { + ui_schedule_refresh(); + return; + } + ui_default_colors_set(); int save_p_lz = p_lz; @@ -241,10 +241,6 @@ void ui_refresh(void) screen_resize(width, height); p_lz = save_p_lz; - if (ext_widgets[kUIMessages]) { - set_option_value(kOptCmdheight, NUMBER_OPTVAL(0), 0); - command_height(); - } ui_mode_info_set(); pending_mode_update = true; ui_cursor_shape(); @@ -624,7 +620,7 @@ void ui_check_mouse(void) /// Check if current mode has changed. /// /// May update the shape of the cursor. -void ui_cursor_shape(void) +void ui_cursor_shape_no_check_conceal(void) { if (!full_screen) { return; @@ -635,6 +631,15 @@ void ui_cursor_shape(void) ui_mode_idx = new_mode_idx; pending_mode_update = true; } +} + +/// Check if current mode has changed. +/// +/// May update the shape of the cursor. +/// With concealing on, may conceal or unconceal the cursor line. +void ui_cursor_shape(void) +{ + ui_cursor_shape_no_check_conceal(); conceal_check_cursor_line(); } @@ -710,11 +715,14 @@ void ui_call_event(char *name, Array args) map_foreach_value(&ui_event_cbs, event_cb, { Error err = ERROR_INIT; Object res = nlua_call_ref(event_cb->cb, name, args, kRetNilBool, NULL, &err); + // TODO(bfredl/luukvbaal): should this be documented or reconsidered? + // Why does truthy return from Lua callback mean remote UI should not receive + // the event. if (LUARET_TRUTHY(res)) { handled = true; } if (ERROR_SET(&err)) { - ELOG("Error while executing ui_comp_event callback: %s", err.msg); + ELOG("Error executing UI event callback: %s", err.msg); } api_clear_error(&err); }) diff --git a/src/nvim/ui.h b/src/nvim/ui.h index 52b1334b15..8718c7b506 100644 --- a/src/nvim/ui.h +++ b/src/nvim/ui.h @@ -14,6 +14,7 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ui.h.generated.h" # include "ui_events_call.h.generated.h" +EXTERN Array noargs INIT(= ARRAY_DICT_INIT); #endif // uncrustify:on diff --git a/src/nvim/ui_defs.h b/src/nvim/ui_defs.h index 4d73cc2321..bbc1655252 100644 --- a/src/nvim/ui_defs.h +++ b/src/nvim/ui_defs.h @@ -63,7 +63,6 @@ typedef struct { PackerBuffer packer; const char *cur_event; ///< name of current event (might get multiple arglists) - Array call_buf; ///< buffer for constructing a single arg list (max 16 elements!) // We start packing the two outermost msgpack arrays before knowing the total // number of elements. Thus track the location where array size will need diff --git a/src/nvim/undo.c b/src/nvim/undo.c index e9170ba858..ba720c9f6a 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -477,7 +477,7 @@ int u_savecommon(buf_T *buf, linenr_T top, linenr_T bot, linenr_T newbot, bool r uhp->uh_entry = NULL; uhp->uh_getbot_entry = NULL; uhp->uh_cursor = curwin->w_cursor; // save cursor pos. for undo - if (virtual_active() && curwin->w_cursor.coladd > 0) { + if (virtual_active(curwin) && curwin->w_cursor.coladd > 0) { uhp->uh_cursor_vcol = getviscol(); } else { uhp->uh_cursor_vcol = -1; @@ -2488,8 +2488,8 @@ static void u_undoredo(bool undo, bool do_buf_event) if (curwin->w_cursor.lnum <= curbuf->b_ml.ml_line_count) { if (curhead->uh_cursor.lnum == curwin->w_cursor.lnum) { curwin->w_cursor.col = curhead->uh_cursor.col; - if (virtual_active() && curhead->uh_cursor_vcol >= 0) { - coladvance(curhead->uh_cursor_vcol); + if (virtual_active(curwin) && curhead->uh_cursor_vcol >= 0) { + coladvance(curwin, curhead->uh_cursor_vcol); } else { curwin->w_cursor.coladd = 0; } @@ -2506,7 +2506,7 @@ static void u_undoredo(bool undo, bool do_buf_event) } // Make sure the cursor is on an existing line and column. - check_cursor(); + check_cursor(curwin); // Remember where we are for "g-" and ":earlier 10s". curbuf->b_u_seq_cur = curhead->uh_seq; @@ -3073,7 +3073,7 @@ void u_undoline(void) } curwin->w_cursor.col = t; curwin->w_cursor.lnum = curbuf->b_u_line_lnum; - check_cursor_col(); + check_cursor_col(curwin); } /// Allocate memory and copy curbuf line into it. diff --git a/src/nvim/usercmd.c b/src/nvim/usercmd.c index 8d41edec8a..e3d9dc5f54 100644 --- a/src/nvim/usercmd.c +++ b/src/nvim/usercmd.c @@ -1724,7 +1724,7 @@ int do_ucmd(exarg_T *eap, bool preview) save_current_sctx = current_sctx; current_sctx.sc_sid = cmd->uc_script_ctx.sc_sid; } - do_cmdline(buf, eap->getline, eap->cookie, + do_cmdline(buf, eap->ea_getline, eap->cookie, DOCMD_VERBOSE|DOCMD_NOWAIT|DOCMD_KEYTYPED); // Careful: Do not use "cmd" here, it may have become invalid if a user diff --git a/src/nvim/version.c b/src/nvim/version.c index 038c9701bf..c392362bf4 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -32,7 +32,9 @@ #include "nvim/option_vars.h" #include "nvim/os/os.h" #include "nvim/strings.h" +#include "nvim/ui.h" #include "nvim/version.h" +#include "nvim/window.h" // for ":version", ":intro", and "nvim --version" #ifndef NVIM_VERSION_MEDIUM @@ -1665,7 +1667,7 @@ static const int included_patches[] = { 818, 817, 816, - // 815, + 815, 814, 813, 812, @@ -2710,15 +2712,15 @@ void list_version(void) : "\nRun \":verbose version\" for more info")); } -/// Show the intro message when not editing a file. -void maybe_intro_message(void) +/// Whether it still is not too late to show an intro message +bool may_show_intro(void) { - if (buf_is_empty(curbuf) - && (curbuf->b_fname == NULL) - && (firstwin->w_next == NULL) - && (vim_strchr(p_shm, SHM_INTRO) == NULL)) { - intro_message(false); - } + return (buf_is_empty(curbuf) + && (curbuf->b_fname == NULL) + && (curbuf->handle == 1) + && (curwin->handle == LOWEST_WIN_ID) + && one_window(curwin) + && (vim_strchr(p_shm, SHM_INTRO) == NULL)); } /// Give an introductory message about Vim. @@ -2726,7 +2728,7 @@ void maybe_intro_message(void) /// Or with the ":intro" command (for Sven :-). /// /// @param colon true for ":intro" -void intro_message(int colon) +void intro_message(bool colon) { static char *(lines[]) = { N_(NVIM_VERSION_LONG), @@ -2760,11 +2762,6 @@ void intro_message(int colon) blanklines = 0; } - // Show the sponsor and register message one out of four times, the Uganda - // message two out of four times. - int sponsor = (int)time(NULL); - sponsor = ((sponsor & 2) == 0) - ((sponsor & 4) == 0); - // start displaying the message lines after half of the blank lines int row = blanklines / 2; @@ -2782,16 +2779,6 @@ void intro_message(int colon) 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!") - : N_("Become a registered Vim user!"); - } else if (strstr(p, "iccf") != NULL) { - p = sponsor < 0 - ? N_("type :help sponsor<Enter> for information ") - : N_("type :help register<Enter> for information "); - } } if (mesg == NULL) { @@ -2803,7 +2790,7 @@ void intro_message(int colon) } if (*mesg != NUL) { - do_intro_line(row, mesg, 0); + do_intro_line(row, mesg, colon); } row++; @@ -2814,7 +2801,7 @@ void intro_message(int colon) } } -static void do_intro_line(int row, char *mesg, int attr) +static void do_intro_line(int row, char *mesg, bool colon) { int l; @@ -2827,7 +2814,12 @@ static void do_intro_line(int row, char *mesg, int attr) col = 0; } - grid_line_start(&default_grid, row); + ScreenGrid *grid = &default_grid; + if (!colon && ui_has(kUIMultigrid)) { + grid = &firstwin->w_grid; + } + + grid_line_start(grid, row); // Split up in parts to highlight <> items differently. for (char *p = mesg; *p != NUL; p += l) { for (l = 0; @@ -2836,7 +2828,7 @@ static void do_intro_line(int row, char *mesg, int attr) l += utfc_ptr2len(p + l) - 1; } assert(row <= INT_MAX && col <= INT_MAX); - col += grid_line_puts(col, p, l, *p == '<' ? HL_ATTR(HLF_8) : attr); + col += grid_line_puts(col, p, l, *p == '<' ? HL_ATTR(HLF_8) : 0); } grid_line_flush(); } diff --git a/src/nvim/vvars.lua b/src/nvim/vvars.lua index 37cb70c725..2f43f8b32b 100644 --- a/src/nvim/vvars.lua +++ b/src/nvim/vvars.lua @@ -64,9 +64,10 @@ M.vars = { }, completed_item = { desc = [=[ - Dictionary containing the most recent |complete-items| after - |CompleteDone|. Empty if the completion failed, or after - leaving and re-entering insert mode. + Dictionary containing the |complete-items| for the most + recently completed word after |CompleteDone|. Empty if the + completion failed, or after leaving and re-entering insert + mode. Note: Plugins can modify the value to emulate the builtin |CompleteDone| event behavior. ]=], @@ -214,6 +215,7 @@ M.vars = { changed_window Is |v:true| if the event fired while changing window (or tab) on |DirChanged|. status Job status or exit code, -1 means "unknown". |TermClose| + reason Reason for completion being done. |CompleteDone| ]=], }, exception = { diff --git a/src/nvim/window.c b/src/nvim/window.c index e2c4524eaa..1a6c3f7263 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -133,6 +133,35 @@ static void log_frame_layout(frame_T *frame) } #endif +/// Check if the current window is allowed to move to a different buffer. +/// +/// @return If the window has 'winfixbuf', or this function will return false. +bool check_can_set_curbuf_disabled(void) +{ + if (curwin->w_p_wfb) { + emsg(_(e_winfixbuf_cannot_go_to_buffer)); + return false; + } + + return true; +} + +/// Check if the current window is allowed to move to a different buffer. +/// +/// @param forceit If true, do not error. If false and 'winfixbuf' is enabled, error. +/// +/// @return If the window has 'winfixbuf', then forceit must be true +/// or this function will return false. +bool check_can_set_curbuf_forceit(int forceit) +{ + if (!forceit && curwin->w_p_wfb) { + emsg(_(e_winfixbuf_cannot_go_to_buffer)); + return false; + } + + return true; +} + /// @return the current window, unless in the cmdline window and "prevwin" is /// set, then return "prevwin". win_T *prevwin_curwin(void) @@ -455,9 +484,14 @@ newwindow: case 'H': case 'L': CHECK_CMDWIN; - win_totop(Prenum, - ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0) - | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT)); + if (one_window(curwin)) { + beep_flush(); + } else { + const int dir = ((nchar == 'H' || nchar == 'L') ? WSP_VERT : 0) + | ((nchar == 'H' || nchar == 'K') ? WSP_TOP : WSP_BOT); + + win_splitmove(curwin, Prenum, dir); + } break; // make all windows the same width and/or height @@ -592,7 +626,7 @@ wingotofile: ptr = xmemdupz(ptr, len); find_pattern_in_path(ptr, 0, len, true, Prenum == 0, - type, Prenum1, ACTION_SPLIT, 1, MAXLNUM); + type, Prenum1, ACTION_SPLIT, 1, MAXLNUM, false); xfree(ptr); curwin->w_set_curswant = true; break; @@ -701,16 +735,13 @@ static void cmd_with_count(char *cmd, char *bufp, size_t bufsize, int64_t Prenum } } -void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err) +void win_set_buf(win_T *win, buf_T *buf, Error *err) FUNC_ATTR_NONNULL_ALL { tabpage_T *tab = win_find_tabpage(win); // no redrawing and don't set the window title RedrawingDisabled++; - if (noautocmd) { - block_autocmds(); - } switchwin_T switchwin; if (switch_win_noblock(&switchwin, win, tab, true) == FAIL) { @@ -718,10 +749,23 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err) kErrorTypeException, "Failed to switch to window %d", win->handle); + goto cleanup; } try_start(); + + const int save_acd = p_acd; + if (!switchwin.sw_same_win) { + // Temporarily disable 'autochdir' when setting buffer in another window. + p_acd = false; + } + int result = do_buffer(DOBUF_GOTO, DOBUF_FIRST, FORWARD, buf->b_fnum, 0); + + if (!switchwin.sw_same_win) { + p_acd = save_acd; + } + if (!try_end(err) && result == FAIL) { api_set_error(err, kErrorTypeException, @@ -729,14 +773,12 @@ void win_set_buf(win_T *win, buf_T *buf, bool noautocmd, Error *err) buf->handle); } - // If window is not current, state logic will not validate its cursor. - // So do it now. - validate_cursor(); + // If window is not current, state logic will not validate its cursor. So do it now. + // Still needed if do_buffer returns FAIL (e.g: autocmds abort script after buffer was set). + validate_cursor(curwin); +cleanup: restore_win_noblock(&switchwin, true); - if (noautocmd) { - unblock_autocmds(); - } RedrawingDisabled--; } @@ -785,7 +827,8 @@ void ui_ext_win_position(win_T *wp, bool validate) row += row_off; col += col_off; if (c.bufpos.lnum >= 0) { - pos_T pos = { c.bufpos.lnum + 1, c.bufpos.col, 0 }; + int lnum = MIN(c.bufpos.lnum + 1, win->w_buffer->b_ml.ml_line_count); + pos_T pos = { lnum, c.bufpos.col, 0 }; int trow, tcol, tcolc, tcole; textpos2screenpos(win, &pos, &trow, &tcol, &tcolc, &tcole, true); row += trow - 1; @@ -903,19 +946,35 @@ void ui_ext_win_viewport(win_T *wp) } } -/// If "split_disallowed" is set give an error and return FAIL. +/// If "split_disallowed" is set, or "wp"'s buffer is closing, give an error and return FAIL. /// Otherwise return OK. -static int check_split_disallowed(void) +int check_split_disallowed(const win_T *wp) + FUNC_ATTR_NONNULL_ALL +{ + Error err = ERROR_INIT; + const bool ok = check_split_disallowed_err(wp, &err); + if (ERROR_SET(&err)) { + emsg(_(err.msg)); + api_clear_error(&err); + } + return ok ? OK : FAIL; +} + +/// Like `check_split_disallowed`, but set `err` to the (untranslated) error message on failure and +/// return false. Otherwise return true. +/// @see check_split_disallowed +bool check_split_disallowed_err(const win_T *wp, Error *err) + FUNC_ATTR_NONNULL_ALL { if (split_disallowed > 0) { - emsg(_("E242: Can't split a window while closing another")); - return FAIL; + api_set_error(err, kErrorTypeException, "E242: Can't split a window while closing another"); + return false; } - if (curwin->w_buffer->b_locked_split) { - emsg(_(e_cannot_split_window_when_closing_buffer)); - return FAIL; + if (wp->w_buffer->b_locked_split) { + api_set_error(err, kErrorTypeException, "%s", e_cannot_split_window_when_closing_buffer); + return false; } - return OK; + return true; } // split the current window, implements CTRL-W s and :split @@ -934,7 +993,7 @@ static int check_split_disallowed(void) // return FAIL for failure, OK otherwise int win_split(int size, int flags) { - if (check_split_disallowed() == FAIL) { + if (check_split_disallowed(curwin) == FAIL) { return FAIL; } @@ -958,14 +1017,19 @@ int win_split(int size, int flags) clear_snapshot(curtab, SNAP_HELP_IDX); } - return win_split_ins(size, flags, NULL, 0) == NULL ? FAIL : OK; + return win_split_ins(size, flags, NULL, 0, NULL) == NULL ? FAIL : OK; } /// When "new_wp" is NULL: split the current window in two. /// When "new_wp" is not NULL: insert this window at the far /// top/left/right/bottom. +/// When "to_flatten" is not NULL: flatten this frame before reorganising frames; +/// remains unflattened on failure. +/// +/// On failure, if "new_wp" was not NULL, no changes will have been made to the +/// window layout or sizes. /// @return NULL for failure, or pointer to new window -win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) +win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir, frame_T *to_flatten) { win_T *wp = new_wp; @@ -986,13 +1050,12 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) int need_status = 0; int new_size = size; - bool new_in_layout = (new_wp == NULL || new_wp->w_floating); bool vertical = flags & WSP_VERT; bool toplevel = flags & (WSP_TOP | WSP_BOT); // add a status line when p_ls == 1 and splitting the first window - if (one_nonfloat() && p_ls == 1 && oldwin->w_status_height == 0) { - if (oldwin->w_height <= p_wmh && new_in_layout) { + if (one_window(firstwin) && p_ls == 1 && oldwin->w_status_height == 0) { + if (oldwin->w_height <= p_wmh) { emsg(_(e_noroom)); return NULL; } @@ -1041,7 +1104,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) available = oldwin->w_frame->fr_width; needed += minwidth; } - if (available < needed && new_in_layout) { + if (available < needed) { emsg(_(e_noroom)); return NULL; } @@ -1121,7 +1184,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) available = oldwin->w_frame->fr_height; needed += minheight; } - if (available < needed && new_in_layout) { + if (available < needed) { emsg(_(e_noroom)); return NULL; } @@ -1191,13 +1254,13 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) if (new_wp == NULL) { wp = win_alloc(oldwin, false); } else { - win_append(oldwin, wp); + win_append(oldwin, wp, NULL); } } else { if (new_wp == NULL) { wp = win_alloc(oldwin->w_prev, false); } else { - win_append(oldwin->w_prev, wp); + win_append(oldwin->w_prev, wp, NULL); } } @@ -1211,13 +1274,37 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) // make the contents of the new window the same as the current one win_init(wp, curwin, flags); } else if (wp->w_floating) { - new_frame(wp); + ui_comp_remove_grid(&wp->w_grid_alloc); + if (ui_has(kUIMultigrid)) { + wp->w_pos_changed = true; + } else { + // No longer a float, a non-multigrid UI shouldn't draw it as such + ui_call_win_hide(wp->w_grid_alloc.handle); + win_free_grid(wp, true); + } + + // External windows are independent of tabpages, and may have been the curwin of others. + if (wp->w_config.external) { + FOR_ALL_TABS(tp) { + if (tp != curtab && tp->tp_curwin == wp) { + tp->tp_curwin = tp->tp_firstwin; + } + } + } + wp->w_floating = false; + new_frame(wp); + // non-floating window doesn't store float config or have a border. wp->w_config = WIN_CONFIG_INIT; CLEAR_FIELD(wp->w_border_adj); } + // Going to reorganize frames now, make sure they're flat. + if (to_flatten != NULL) { + frame_flatten(to_flatten); + } + bool before; frame_T *curfrp; @@ -1453,7 +1540,7 @@ win_T *win_split_ins(int size, int flags, win_T *new_wp, int dir) if (!(flags & WSP_NOENTER)) { // make the new window the current window - win_enter_ext(wp, WEE_TRIGGER_NEW_AUTOCMDS | WEE_TRIGGER_ENTER_AUTOCMDS + win_enter_ext(wp, (new_wp == NULL ? WEE_TRIGGER_NEW_AUTOCMDS : 0) | WEE_TRIGGER_ENTER_AUTOCMDS | WEE_TRIGGER_LEAVE_AUTOCMDS); } if (vertical) { @@ -1690,7 +1777,7 @@ static void win_exchange(int Prenum) return; } - if (firstwin == curwin && lastwin_nofloating() == curwin) { + if (one_window(curwin)) { // just one window beep_flush(); return; @@ -1732,13 +1819,13 @@ static void win_exchange(int Prenum) if (wp->w_prev != curwin) { win_remove(curwin, NULL); frame_remove(curwin->w_frame); - win_append(wp->w_prev, curwin); + win_append(wp->w_prev, curwin, NULL); frame_insert(frp, curwin->w_frame); } if (wp != wp2) { win_remove(wp, NULL); frame_remove(wp->w_frame); - win_append(wp2, wp); + win_append(wp2, wp, NULL); if (frp2 == NULL) { frame_insert(wp->w_frame->fr_parent->fr_child, wp->w_frame); } else { @@ -1782,7 +1869,7 @@ static void win_rotate(bool upwards, int count) return; } - if (count <= 0 || (firstwin == curwin && lastwin_nofloating() == curwin)) { + if (count <= 0 || one_window(curwin)) { // nothing to do beep_flush(); return; @@ -1812,7 +1899,7 @@ static void win_rotate(bool upwards, int count) // find last frame and append removed window/frame after it for (; frp->fr_next != NULL; frp = frp->fr_next) {} - win_append(frp->fr_win, wp1); + win_append(frp->fr_win, wp1, NULL); frame_append(frp, wp1->w_frame); wp2 = frp->fr_win; // previously last window @@ -1827,7 +1914,7 @@ static void win_rotate(bool upwards, int count) assert(frp->fr_parent->fr_child); // append the removed window/frame before the first in the list - win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1); + win_append(frp->fr_parent->fr_child->fr_win->w_prev, wp1, NULL); frame_insert(frp->fr_parent->fr_child, frp); } @@ -1856,48 +1943,59 @@ static void win_rotate(bool upwards, int count) redraw_all_later(UPD_NOT_VALID); } -// Move the current window to the very top/bottom/left/right of the screen. -static void win_totop(int size, int flags) +/// Move "wp" into a new split in a given direction, possibly relative to the +/// current window. +/// "wp" must be valid in the current tabpage. +/// Returns FAIL for failure, OK otherwise. +int win_splitmove(win_T *wp, int size, int flags) { int dir = 0; - int height = curwin->w_height; + int height = wp->w_height; - if (firstwin == curwin && lastwin_nofloating() == curwin) { - beep_flush(); - return; + if (one_window(wp)) { + return OK; // nothing to do } - if (is_aucmd_win(curwin)) { - return; + if (is_aucmd_win(wp) || check_split_disallowed(wp) == FAIL) { + return FAIL; } - if (check_split_disallowed() == FAIL) { - return; + + frame_T *unflat_altfr = NULL; + if (wp->w_floating) { + win_remove(wp, NULL); + } else { + // Remove the window and frame from the tree of frames. Don't flatten any + // frames yet so we can restore things if win_split_ins fails. + winframe_remove(wp, &dir, NULL, &unflat_altfr); + assert(unflat_altfr != NULL); + win_remove(wp, NULL); + last_status(false); // may need to remove last status line + win_comp_pos(); // recompute window positions } - if (curwin->w_floating) { - ui_comp_remove_grid(&curwin->w_grid_alloc); - if (ui_has(kUIMultigrid)) { - curwin->w_pos_changed = true; - } else { - // No longer a float, a non-multigrid UI shouldn't draw it as such - ui_call_win_hide(curwin->w_grid_alloc.handle); - win_free_grid(curwin, true); + // Split a window on the desired side and put "wp" there. + if (win_split_ins(size, flags, wp, dir, unflat_altfr) == NULL) { + if (!wp->w_floating) { + assert(unflat_altfr != NULL); + // win_split_ins doesn't change sizes or layout if it fails to insert an + // existing window, so just undo winframe_remove. + winframe_restore(wp, dir, unflat_altfr); } - } else { - // Remove the window and frame from the tree of frames. - winframe_remove(curwin, &dir, NULL); + win_append(wp->w_prev, wp, NULL); + return FAIL; } - win_remove(curwin, NULL); - last_status(false); // may need to remove last status line - win_comp_pos(); // recompute window positions - // Split a window on the desired side and put the window there. - win_split_ins(size, flags, curwin, dir); - if (!(flags & WSP_VERT)) { - win_setheight(height); + // If splitting horizontally, try to preserve height. + // Note that win_split_ins autocommands may have immediately closed "wp", or made it floating! + if (size == 0 && !(flags & WSP_VERT) && win_valid(wp) && !wp->w_floating) { + win_setheight_win(height, wp); if (p_ea) { - win_equal(curwin, true, 'v'); + // Equalize windows. Note that win_split_ins autocommands may have + // made a window other than "wp" current. + win_equal(curwin, curwin == wp, 'v'); } } + + return OK; } // Move window "win1" to below/right of "win2" and make "win1" the current @@ -1955,7 +2053,7 @@ void win_move_after(win_T *win1, win_T *win2) } win_remove(win1, NULL); frame_remove(win1->w_frame); - win_append(win2, win1); + win_append(win2, win1, NULL); frame_append(win2->w_frame, win1->w_frame); win_comp_pos(); // recompute w_winrow for all windows @@ -2369,6 +2467,7 @@ void win_init_empty(win_T *wp) wp->w_topline = 1; wp->w_topfill = 0; wp->w_botline = 2; + wp->w_valid = 0; wp->w_s = &wp->w_buffer->b_s; } @@ -2434,37 +2533,13 @@ bool last_window(win_T *win) 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 (!wp->w_floating) { - if (seen_one) { - return false; - } - seen_one = true; - } - } - return true; -} - -/// Like ONE_WINDOW but only considers non-floating windows -bool one_nonfloat(void) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT -{ - return firstwin->w_next == NULL || firstwin->w_next->w_floating; -} - -/// if wp is the last non-floating window /// -/// always false for a floating window -bool last_nonfloat(win_T *wp) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT +/// This should be used in place of ONE_WINDOW when necessary, +/// with "firstwin" or the affected window as argument depending on the situation. +bool one_window(win_T *win) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT { - return wp != NULL && firstwin == wp && !(wp->w_next && !wp->w_floating); + assert(!firstwin->w_floating); + return firstwin == win && (win->w_next == NULL || win->w_next->w_floating); } /// Check if floating windows in the current tab can be closed. @@ -2509,7 +2584,7 @@ bool can_close_in_cmdwin(win_T *win, Error *err) /// @param prev_curtab previous tabpage that will be closed if "win" is the /// last window in the tabpage /// -/// @return true when the window was closed already. +/// @return false if there are other windows and nothing is done, true otherwise. static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev_curtab) FUNC_ATTR_NONNULL_ARG(1) { @@ -2533,10 +2608,6 @@ static bool close_last_window_tabpage(win_T *win, bool free_buf, tabpage_T *prev // that below. goto_tabpage_tp(alt_tabpage(), false, true); - // save index for tabclosed event - 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. if (valid_tabpage(prev_curtab) && prev_curtab->tp_firstwin == win) { @@ -2630,6 +2701,9 @@ int win_close(win_T *win, bool free_buf, bool force) return FAIL; } } + if (!win_valid_any_tab(win)) { + return FAIL; // window already closed by autocommands + } } else { emsg(e_floatonly); return FAIL; @@ -2714,10 +2788,8 @@ int win_close(win_T *win, bool free_buf, bool force) win_close_buffer(win, free_buf ? DOBUF_UNLOAD : 0, true); - if (only_one_window() && win_valid(win) && win->w_buffer == NULL - && (last_window(win) || curtab != prev_curtab - || close_last_window_tabpage(win, free_buf, prev_curtab)) - && !win->w_floating) { + if (win_valid(win) && win->w_buffer == NULL + && !win->w_floating && last_window(win)) { // Autocommands have closed all windows, quit now. Restore // curwin->w_buffer, otherwise writing ShaDa file may fail. if (curwin->w_buffer == NULL) { @@ -2729,10 +2801,7 @@ int win_close(win_T *win, bool free_buf, bool force) if (curtab != prev_curtab && win_valid_any_tab(win) && win->w_buffer == NULL) { // Need to close the window anyway, since the buffer is NULL. - // Don't trigger autocmds with a NULL buffer. - block_autocmds(); win_close_othertab(win, false, prev_curtab); - unblock_autocmds(); return FAIL; } @@ -2759,13 +2828,10 @@ int win_close(win_T *win, bool free_buf, bool force) ui_comp_remove_grid(&win->w_grid_alloc); assert(first_tabpage != NULL); // suppress clang "Dereference of NULL pointer" if (win->w_config.external) { - for (tabpage_T *tp = first_tabpage; tp != NULL; tp = tp->tp_next) { - if (tp == curtab) { - continue; - } - if (tp->tp_curwin == win) { + FOR_ALL_TABS(tp) { + if (tp != curtab && tp->tp_curwin == win) { // NB: an autocmd can still abort the closing of this window, - // bur carring out this change anyway shouldn't be a catastrophe. + // but carrying out this change anyway shouldn't be a catastrophe. tp->tp_curwin = tp->tp_firstwin; } } @@ -2805,7 +2871,8 @@ int win_close(win_T *win, bool free_buf, bool force) if (wp == curwin) { break; } - if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer)) { + if (!wp->w_p_pvw && !bt_quickfix(wp->w_buffer) + && !(wp->w_floating && !wp->w_config.focusable)) { curwin = wp; break; } @@ -2816,7 +2883,7 @@ int win_close(win_T *win, bool free_buf, bool force) // The cursor position may be invalid if the buffer changed after last // using the window. - check_cursor(); + check_cursor(curwin); } if (!was_floating) { @@ -2906,10 +2973,14 @@ void win_close_othertab(win_T *win, int free_buf, tabpage_T *tp) } // Fire WinClosed just before starting to free window-related resources. - do_autocmd_winclosed(win); - // autocmd may have freed the window already. - if (!win_valid_any_tab(win)) { - return; + // If the buffer is NULL, it isn't safe to trigger autocommands, + // and win_close() should have already triggered WinClosed. + if (win->w_buffer != NULL) { + do_autocmd_winclosed(win); + // autocmd may have freed the window already. + if (!win_valid_any_tab(win)) { + return; + } } if (win->w_buffer != NULL) { @@ -3006,24 +3077,11 @@ static win_T *win_free_mem(win_T *win, int *dirp, tabpage_T *tp) if (!win->w_floating) { // Remove the window and its frame from the tree of frames. frame_T *frp = win->w_frame; - wp = winframe_remove(win, dirp, tp); + wp = winframe_remove(win, dirp, tp, NULL); xfree(frp); } else { *dirp = 'h'; // Dummy value. - if (tp == NULL) { - if (win_valid(prevwin) && prevwin != win) { - wp = prevwin; - } else { - wp = firstwin; - } - } else { - assert(tp != curtab); - if (tabpage_win_valid(tp, tp->tp_prevwin) && tp->tp_prevwin != win) { - wp = tp->tp_prevwin; - } else { - wp = tp->tp_firstwin; - } - } + wp = win_float_find_altwin(win, tp); } win_free(win, tp); @@ -3087,9 +3145,64 @@ void win_free_all(void) /// /// @param dirp set to 'v' or 'h' for direction if 'ea' /// @param tp tab page "win" is in, NULL for current +/// @param unflat_altfr if not NULL, set to pointer of frame that got +/// the space, and it is not flattened /// /// @return a pointer to the window that got the freed up space. -win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp) +win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp, frame_T **unflat_altfr) + FUNC_ATTR_NONNULL_ARG(1, 2) +{ + frame_T *altfr; + win_T *wp = winframe_find_altwin(win, dirp, tp, &altfr); + if (wp == NULL) { + return NULL; + } + + frame_T *frp_close = win->w_frame; + + // Save the position of the containing frame (which will also contain the + // altframe) before we remove anything, to recompute window positions later. + const win_T *const topleft = frame2win(frp_close->fr_parent); + int row = topleft->w_winrow; + int col = topleft->w_wincol; + + // Remove this frame from the list of frames. + frame_remove(frp_close); + + if (*dirp == 'v') { + frame_new_height(altfr, altfr->fr_height + frp_close->fr_height, + altfr == frp_close->fr_next, false); + } else { + assert(*dirp == 'h'); + frame_new_width(altfr, altfr->fr_width + frp_close->fr_width, + altfr == frp_close->fr_next, false); + } + + // If the altframe wasn't adjacent and left/above, resizing it will have + // changed window positions within the parent frame. Recompute them. + if (altfr != frp_close->fr_prev) { + frame_comp_pos(frp_close->fr_parent, &row, &col); + } + + if (unflat_altfr == NULL) { + frame_flatten(altfr); + } else { + *unflat_altfr = altfr; + } + + return wp; +} + +/// Find the window that will get the freed space from a call to `winframe_remove`. +/// Makes no changes to the window layout. +/// +/// @param dirp set to 'v' or 'h' for the direction where "altfr" will be resized +/// to fill the space +/// @param tp tab page "win" is in, NULL for current +/// @param altfr if not NULL, set to pointer of frame that will get the space +/// +/// @return a pointer to the window that will get the freed up space. +win_T *winframe_find_altwin(win_T *win, int *dirp, tabpage_T *tp, frame_T **altfr) FUNC_ATTR_NONNULL_ARG(1, 2) { assert(tp == NULL || tp != curtab); @@ -3101,13 +3214,10 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp) frame_T *frp_close = win->w_frame; - // Remove the window from its frame. + // Find the window and frame that gets the space. frame_T *frp2 = win_altframe(win, tp); win_T *wp = frame2win(frp2); - // Remove this frame from the list of frames. - frame_remove(frp_close); - if (frp_close->fr_parent->fr_layout == FR_COL) { // When 'winfixheight' is set, try to find another frame in the column // (as close to the closed frame as possible) to distribute the height @@ -3134,8 +3244,6 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp) } } } - frame_new_height(frp2, frp2->fr_height + frp_close->fr_height, - frp2 == frp_close->fr_next, false); *dirp = 'v'; } else { // When 'winfixwidth' is set, try to find another frame in the column @@ -3163,70 +3271,123 @@ win_T *winframe_remove(win_T *win, int *dirp, tabpage_T *tp) } } } - frame_new_width(frp2, frp2->fr_width + frp_close->fr_width, - frp2 == frp_close->fr_next, false); *dirp = 'h'; } - // If rows/columns go to a window below/right its positions need to be - // updated. Can only be done after the sizes have been updated. - if (frp2 == frp_close->fr_next) { - int row = win->w_winrow; - int col = win->w_wincol; + assert(wp != win && frp2 != frp_close); + if (altfr != NULL) { + *altfr = frp2; + } + + return wp; +} - frame_comp_pos(frp2, &row, &col); +/// Flatten "frp" into its parent frame if it's the only child, also merging its +/// list with the grandparent if they share the same layout. +/// Frees "frp" if flattened; also "frp->fr_parent" if it has the same layout. +static void frame_flatten(frame_T *frp) + FUNC_ATTR_NONNULL_ALL +{ + if (frp->fr_next != NULL || frp->fr_prev != NULL) { + return; } - if (frp2->fr_next == NULL && frp2->fr_prev == NULL) { - // There is no other frame in this list, move its info to the parent - // and remove it. - frp2->fr_parent->fr_layout = frp2->fr_layout; - frp2->fr_parent->fr_child = frp2->fr_child; - frame_T *frp; - FOR_ALL_FRAMES(frp, frp2->fr_child) { - frp->fr_parent = frp2->fr_parent; - } - frp2->fr_parent->fr_win = frp2->fr_win; - if (frp2->fr_win != NULL) { - frp2->fr_win->w_frame = frp2->fr_parent; + // There is no other frame in this list, move its info to the parent + // and remove it. + frp->fr_parent->fr_layout = frp->fr_layout; + frp->fr_parent->fr_child = frp->fr_child; + frame_T *frp2; + FOR_ALL_FRAMES(frp2, frp->fr_child) { + frp2->fr_parent = frp->fr_parent; + } + frp->fr_parent->fr_win = frp->fr_win; + if (frp->fr_win != NULL) { + frp->fr_win->w_frame = frp->fr_parent; + } + frp2 = frp->fr_parent; + if (topframe->fr_child == frp) { + topframe->fr_child = frp2; + } + xfree(frp); + + frp = frp2->fr_parent; + if (frp != NULL && frp->fr_layout == frp2->fr_layout) { + // The frame above the parent has the same layout, have to merge + // the frames into this list. + if (frp->fr_child == frp2) { + frp->fr_child = frp2->fr_child; + } + assert(frp2->fr_child); + frp2->fr_child->fr_prev = frp2->fr_prev; + if (frp2->fr_prev != NULL) { + frp2->fr_prev->fr_next = frp2->fr_child; + } + for (frame_T *frp3 = frp2->fr_child;; frp3 = frp3->fr_next) { + frp3->fr_parent = frp; + if (frp3->fr_next == NULL) { + frp3->fr_next = frp2->fr_next; + if (frp2->fr_next != NULL) { + frp2->fr_next->fr_prev = frp3; + } + break; + } } - frp = frp2->fr_parent; if (topframe->fr_child == frp2) { topframe->fr_child = frp; } xfree(frp2); + } +} - frp2 = frp->fr_parent; - if (frp2 != NULL && frp2->fr_layout == frp->fr_layout) { - // The frame above the parent has the same layout, have to merge - // the frames into this list. - if (frp2->fr_child == frp) { - frp2->fr_child = frp->fr_child; - } - assert(frp->fr_child); - frp->fr_child->fr_prev = frp->fr_prev; - if (frp->fr_prev != NULL) { - frp->fr_prev->fr_next = frp->fr_child; - } - frame_T *frp3; - for (frp3 = frp->fr_child;; frp3 = frp3->fr_next) { - frp3->fr_parent = frp2; - if (frp3->fr_next == NULL) { - frp3->fr_next = frp->fr_next; - if (frp->fr_next != NULL) { - frp->fr_next->fr_prev = frp3; - } - break; - } - } - if (topframe->fr_child == frp) { - topframe->fr_child = frp2; - } - xfree(frp); +/// Undo changes from a prior call to winframe_remove, also restoring lost +/// vertical separators and statuslines, and changed window positions for +/// windows within "unflat_altfr". +/// Caller must ensure no other changes were made to the layout or window sizes! +void winframe_restore(win_T *wp, int dir, frame_T *unflat_altfr) + FUNC_ATTR_NONNULL_ALL +{ + frame_T *frp = wp->w_frame; + + // Put "wp"'s frame back where it was. + if (frp->fr_prev != NULL) { + frame_append(frp->fr_prev, frp); + } else { + frame_insert(frp->fr_next, frp); + } + + // Vertical separators to the left may have been lost. Restore them. + if (wp->w_vsep_width == 0 && frp->fr_parent->fr_layout == FR_ROW && frp->fr_prev != NULL) { + frame_add_vsep(frp->fr_prev); + } + + // Statuslines or horizontal separators above may have been lost. Restore them. + if (frp->fr_parent->fr_layout == FR_COL && frp->fr_prev != NULL) { + if (global_stl_height() == 0 && wp->w_status_height == 0) { + frame_add_statusline(frp->fr_prev); + } else if (wp->w_hsep_height == 0) { + frame_add_hsep(frp->fr_prev); } } - return wp; + // Restore the lost room that was redistributed to the altframe. Also + // adjusts window sizes to fit restored statuslines/separators, if needed. + if (dir == 'v') { + frame_new_height(unflat_altfr, unflat_altfr->fr_height - frp->fr_height, + unflat_altfr == frp->fr_next, false); + } else if (dir == 'h') { + frame_new_width(unflat_altfr, unflat_altfr->fr_width - frp->fr_width, + unflat_altfr == frp->fr_next, false); + } + + // Recompute window positions within the parent frame to restore them. + // Positions were unchanged if the altframe was adjacent and left/above. + if (unflat_altfr != frp->fr_prev) { + const win_T *const topleft = frame2win(frp->fr_parent); + int row = topleft->w_winrow; + int col = topleft->w_wincol; + + frame_comp_pos(frp->fr_parent, &row, &col); + } } /// If 'splitbelow' or 'splitright' is set, the space goes above or to the left @@ -3792,7 +3953,7 @@ void close_others(int message, int forceit) return; } - if (one_nonfloat() && !lastwin->w_floating) { + if (one_window(firstwin) && !lastwin->w_floating) { if (message && !autocmd_busy) { msg(_(m_onlyone), 0); @@ -4331,7 +4492,7 @@ static void tabpage_check_windows(tabpage_T *old_curtab) if (wp->w_floating) { if (wp->w_config.external) { win_remove(wp, old_curtab); - win_append(lastwin_nofloating(), wp); + win_append(lastwin_nofloating(), wp, NULL); } else { ui_comp_remove_grid(&wp->w_grid_alloc); } @@ -4767,19 +4928,15 @@ static void win_enter_ext(win_T *const wp, const int flags) if (wp->w_buffer != curbuf) { buf_copy_options(wp->w_buffer, BCO_ENTER | BCO_NOHELP); } - if (!curwin_invalid) { prevwin = curwin; // remember for CTRL-W p curwin->w_redr_status = true; - } else if (wp == prevwin) { - prevwin = NULL; // don't want it to be the new curwin } - curwin = wp; curbuf = wp->w_buffer; - check_cursor(); - if (!virtual_active()) { + check_cursor(curwin); + if (!virtual_active(curwin)) { curwin->w_cursor.coladd = 0; } if (*p_spk == 'c') { @@ -4790,7 +4947,7 @@ static void win_enter_ext(win_T *const wp, const int flags) win_fix_cursor(get_real_state() & (MODE_NORMAL|MODE_CMDLINE|MODE_TERMINAL)); } - fix_current_dir(); + win_fix_current_dir(); entering_window(curwin); // Careful: autocommands may close the window and make "wp" invalid @@ -4843,7 +5000,7 @@ static void win_enter_ext(win_T *const wp, const int flags) } /// Used after making another window the current one: change directory if needed. -void fix_current_dir(void) +void win_fix_current_dir(void) { // New directory is either the local directory of the window, tab or NULL. char *new_dir = curwin->w_localdir ? curwin->w_localdir : curtab->tp_localdir; @@ -4971,7 +5128,14 @@ win_T *win_alloc(win_T *after, bool hidden) block_autocmds(); // link the window in the window list if (!hidden) { - win_append(after, new_wp); + tabpage_T *tp = NULL; + if (after) { + tp = win_find_tabpage(after); + if (tp == curtab) { + tp = NULL; + } + } + win_append(after, new_wp, tp); } new_wp->w_wincol = 0; @@ -5141,21 +5305,29 @@ void win_free_grid(win_T *wp, bool reinit) } } -// Append window "wp" in the window list after window "after". -void win_append(win_T *after, win_T *wp) +/// Append window "wp" in the window list after window "after". +/// +/// @param tp tab page "win" (and "after", if not NULL) is in, NULL for current +void win_append(win_T *after, win_T *wp, tabpage_T *tp) + FUNC_ATTR_NONNULL_ARG(2) { + assert(tp == NULL || tp != curtab); + + win_T **first = tp == NULL ? &firstwin : &tp->tp_firstwin; + win_T **last = tp == NULL ? &lastwin : &tp->tp_lastwin; + // after NULL is in front of the first - win_T *before = after == NULL ? firstwin : after->w_next; + win_T *before = after == NULL ? *first : after->w_next; wp->w_next = before; wp->w_prev = after; if (after == NULL) { - firstwin = wp; + *first = wp; } else { after->w_next = wp; } if (before == NULL) { - lastwin = wp; + *last = wp; } else { before->w_prev = wp; } @@ -5737,10 +5909,6 @@ static void frame_setheight(frame_T *curfrp, int height) if (curfrp->fr_parent == NULL) { // topframe: can only change the command line height - // Avoid doing so with external messages. - if (ui_has(kUIMessages)) { - return; - } if (height > ROWS_AVAIL) { // If height is greater than the available space, try to create space for // the frame by reducing 'cmdheight' if possible, while making sure @@ -6079,12 +6247,6 @@ const char *did_set_winminwidth(optset_T *args FUNC_ATTR_UNUSED) void win_drag_status_line(win_T *dragwin, int offset) { frame_T *fr = dragwin->w_frame; - - // Avoid changing command line height with external messages. - if (fr->fr_next == NULL && ui_has(kUIMessages)) { - return; - } - frame_T *curfr = fr; if (fr != topframe) { // more than one window fr = fr->fr_parent; @@ -6487,7 +6649,7 @@ void scroll_to_fraction(win_T *wp, int prev_height) } } else if (sline > 0) { while (sline > 0 && lnum > 1) { - hasFoldingWin(wp, lnum, &lnum, NULL, true, NULL); + hasFolding(wp, lnum, &lnum, NULL); if (lnum == 1) { // first line in buffer is folded line_size = 1; @@ -6507,7 +6669,7 @@ void scroll_to_fraction(win_T *wp, int prev_height) if (sline < 0) { // Line we want at top would go off top of screen. Use next // line instead. - hasFoldingWin(wp, lnum, NULL, &lnum, true, NULL); + hasFolding(wp, lnum, NULL, &lnum); lnum++; wp->w_wrow -= line_size + sline; } else if (sline > 0) { @@ -6548,7 +6710,7 @@ void win_set_inner_size(win_T *wp, bool valid_cursor) if (wp == curwin && *p_spk == 'c') { // w_wrow needs to be valid. When setting 'laststatus' this may // call win_new_height() recursively. - validate_cursor(); + validate_cursor(curwin); } if (wp->w_height_inner != prev_height) { return; // Recursive call already changed the size, bail out. @@ -6590,6 +6752,13 @@ void win_set_inner_size(win_T *wp, bool valid_cursor) wp->w_width_outer = (wp->w_width_inner + win_border_width(wp)); wp->w_winrow_off = wp->w_border_adj[0] + wp->w_winbar_height; wp->w_wincol_off = wp->w_border_adj[3]; + + if (ui_has(kUIMultigrid)) { + ui_call_win_viewport_margins(wp->w_grid_alloc.handle, wp->handle, + wp->w_winrow_off, wp->w_border_adj[2], + wp->w_wincol_off, wp->w_border_adj[1]); + } + wp->w_redr_status = true; } @@ -7058,7 +7227,7 @@ int global_stl_height(void) /// @param morewin pretend there are two or more windows if true. int last_stl_height(bool morewin) { - return (p_ls > 1 || (p_ls == 1 && (morewin || !one_nonfloat()))) ? STATUS_HEIGHT : 0; + return (p_ls > 1 || (p_ls == 1 && (morewin || !one_window(firstwin)))) ? STATUS_HEIGHT : 0; } /// Return the minimal number of rows that is needed on the screen to display diff --git a/src/nvim/winfloat.c b/src/nvim/winfloat.c index 8fe0315230..e3ca0ff139 100644 --- a/src/nvim/winfloat.c +++ b/src/nvim/winfloat.c @@ -6,7 +6,9 @@ #include "klib/kvec.h" #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" +#include "nvim/api/vim.h" #include "nvim/ascii_defs.h" +#include "nvim/autocmd.h" #include "nvim/buffer_defs.h" #include "nvim/drawscreen.h" #include "nvim/globals.h" @@ -17,6 +19,7 @@ #include "nvim/mouse.h" #include "nvim/move.h" #include "nvim/option.h" +#include "nvim/option_defs.h" #include "nvim/optionstr.h" #include "nvim/pos_defs.h" #include "nvim/strings.h" @@ -41,7 +44,24 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err) { if (wp == NULL) { - wp = win_alloc(last ? lastwin : lastwin_nofloating(), false); + tabpage_T *tp = NULL; + win_T *tp_last = last ? lastwin : lastwin_nofloating(); + if (fconfig.window != 0) { + assert(!last); + win_T *parent_wp = find_window_by_handle(fconfig.window, err); + if (!parent_wp) { + return NULL; + } + tp = win_find_tabpage(parent_wp); + if (!tp) { + return NULL; + } + tp_last = tp->tp_lastwin; + while (tp_last->w_floating && tp_last->w_prev) { + tp_last = tp_last->w_prev; + } + } + wp = win_alloc(tp_last, false); win_init(wp, curwin, 0); } else { assert(!last); @@ -55,13 +75,26 @@ win_T *win_new_float(win_T *wp, bool last, WinConfig fconfig, Error *err) api_set_error(err, kErrorTypeException, "Cannot change window from different tabpage into float"); return NULL; + } else if (cmdwin_win != NULL && !cmdwin_win->w_floating) { + // cmdwin can't become the only non-float. Check for others. + bool other_nonfloat = false; + for (win_T *wp2 = firstwin; wp2 != NULL && !wp2->w_floating; wp2 = wp2->w_next) { + if (wp2 != wp && wp2 != cmdwin_win) { + other_nonfloat = true; + break; + } + } + if (!other_nonfloat) { + api_set_error(err, kErrorTypeException, "%s", e_cmdwin); + return NULL; + } } int dir; - winframe_remove(wp, &dir, NULL); + winframe_remove(wp, &dir, NULL, NULL); XFREE_CLEAR(wp->w_frame); win_comp_pos(); // recompute window positions win_remove(wp, NULL); - win_append(lastwin_nofloating(), wp); + win_append(lastwin_nofloating(), wp, NULL); } wp->w_floating = true; wp->w_status_height = 0; @@ -208,7 +241,7 @@ void win_config_float(win_T *wp, WinConfig fconfig) row += row_off; col += col_off; if (wp->w_config.bufpos.lnum >= 0) { - pos_T pos = { wp->w_config.bufpos.lnum + 1, + pos_T pos = { MIN(wp->w_config.bufpos.lnum + 1, parent->w_buffer->b_ml.ml_line_count), wp->w_config.bufpos.col, 0 }; int trow, tcol, tcolc, tcole; textpos2screenpos(parent, &pos, &trow, &tcol, &tcolc, &tcole, true); @@ -306,3 +339,70 @@ win_T *win_float_find_preview(void) } return NULL; } + +/// Select an alternative window to `win` (assumed floating) in tabpage `tp`. +/// +/// Useful for finding a window to switch to if `win` is the current window, but is then closed or +/// moved to a different tabpage. +/// +/// @param tp `win`'s original tabpage, or NULL for current. +win_T *win_float_find_altwin(const win_T *win, const tabpage_T *tp) + FUNC_ATTR_NONNULL_ARG(1) +{ + if (tp == NULL) { + return (win_valid(prevwin) && prevwin != win) ? prevwin : firstwin; + } + + assert(tp != curtab); + return (tabpage_win_valid(tp, tp->tp_prevwin) && tp->tp_prevwin != win) ? tp->tp_prevwin + : tp->tp_firstwin; +} + +/// create a floating preview window. +/// +/// @param[in] bool enter floating window. +/// @param[in] bool create a new buffer for window. +/// +/// @return win_T +win_T *win_float_create(bool enter, bool new_buf) +{ + WinConfig config = WIN_CONFIG_INIT; + config.col = curwin->w_wcol; + config.row = curwin->w_wrow; + config.relative = kFloatRelativeEditor; + config.focusable = false; + config.anchor = 0; // NW + config.noautocmd = true; + config.hide = true; + config.style = kWinStyleMinimal; + Error err = ERROR_INIT; + + block_autocmds(); + win_T *wp = win_new_float(NULL, false, config, &err); + if (!wp) { + unblock_autocmds(); + return NULL; + } + + if (new_buf) { + Buffer b = nvim_create_buf(false, true, &err); + if (!b) { + win_remove(wp, NULL); + win_free(wp, NULL); + unblock_autocmds(); + return NULL; + } + buf_T *buf = find_buffer_by_handle(b, &err); + buf->b_p_bl = false; // unlist + set_option_direct_for(kOptBufhidden, STATIC_CSTR_AS_OPTVAL("wipe"), OPT_LOCAL, 0, kOptReqBuf, + buf); + win_set_buf(wp, buf, &err); + } + unblock_autocmds(); + wp->w_p_diff = false; + wp->w_float_is_info = true; + if (enter) { + win_enter(wp, false); + } + return wp; +} diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg index aaac6e4426..50cee638af 100644 --- a/src/uncrustify.cfg +++ b/src/uncrustify.cfg @@ -1,4 +1,4 @@ -# Uncrustify-0.78.1_f +# Uncrustify-0.79.0_f # # General options @@ -61,7 +61,7 @@ enable_digraphs = false # true/false processing_cmt_as_regex = false # true/false # Add or remove the UTF-8 BOM (recommend 'remove'). -utf8_bom = remove # ignore/add/remove/force/not_defined +utf8_bom = remove # ignore/add/remove/force # If the file contains bytes with values between 128 and 255, but is not # UTF-8, then output as UTF-8. @@ -76,238 +76,235 @@ utf8_force = false # true/false # Add or remove space around non-assignment symbolic operators ('+', '/', '%', # '<<', and so forth). -sp_arith = ignore # ignore/add/remove/force/not_defined +sp_arith = ignore # ignore/add/remove/force # Add or remove space around arithmetic operators '+' and '-'. # # Overrides sp_arith. -sp_arith_additive = force # ignore/add/remove/force/not_defined +sp_arith_additive = force # ignore/add/remove/force # Add or remove space around assignment operator '=', '+=', etc. -sp_assign = force # ignore/add/remove/force/not_defined +sp_assign = force # ignore/add/remove/force # Add or remove space around '=' in C++11 lambda capture specifications. # # Overrides sp_assign. -sp_cpp_lambda_assign = ignore # ignore/add/remove/force/not_defined +sp_cpp_lambda_assign = ignore # ignore/add/remove/force # Add or remove space after the capture specification of a C++11 lambda when # an argument list is present, as in '[] <here> (int x){ ... }'. -sp_cpp_lambda_square_paren = ignore # ignore/add/remove/force/not_defined +sp_cpp_lambda_square_paren = ignore # ignore/add/remove/force # Add or remove space after the capture specification of a C++11 lambda with # no argument list is present, as in '[] <here> { ... }'. -sp_cpp_lambda_square_brace = ignore # ignore/add/remove/force/not_defined +sp_cpp_lambda_square_brace = ignore # ignore/add/remove/force # Add or remove space after the opening parenthesis and before the closing # parenthesis of a argument list of a C++11 lambda, as in # '[]( <here> ){ ... }' # with an empty list. -sp_cpp_lambda_argument_list_empty = ignore # ignore/add/remove/force/not_defined +sp_cpp_lambda_argument_list_empty = ignore # ignore/add/remove/force # Add or remove space after the opening parenthesis and before the closing # parenthesis of a argument list of a C++11 lambda, as in # '[]( <here> int x <here> ){ ... }'. -sp_cpp_lambda_argument_list = ignore # ignore/add/remove/force/not_defined +sp_cpp_lambda_argument_list = ignore # ignore/add/remove/force # Add or remove space after the argument list of a C++11 lambda, as in # '[](int x) <here> { ... }'. -sp_cpp_lambda_paren_brace = ignore # ignore/add/remove/force/not_defined +sp_cpp_lambda_paren_brace = ignore # ignore/add/remove/force # Add or remove space between a lambda body and its call operator of an # immediately invoked lambda, as in '[]( ... ){ ... } <here> ( ... )'. -sp_cpp_lambda_fparen = ignore # ignore/add/remove/force/not_defined +sp_cpp_lambda_fparen = ignore # ignore/add/remove/force # Add or remove space around assignment operator '=' in a prototype. # # If set to ignore, use sp_assign. -sp_assign_default = ignore # ignore/add/remove/force/not_defined +sp_assign_default = ignore # ignore/add/remove/force # Add or remove space before assignment operator '=', '+=', etc. # # Overrides sp_assign. -sp_before_assign = ignore # ignore/add/remove/force/not_defined +sp_before_assign = ignore # ignore/add/remove/force # Add or remove space after assignment operator '=', '+=', etc. # # Overrides sp_assign. -sp_after_assign = ignore # ignore/add/remove/force/not_defined +sp_after_assign = ignore # ignore/add/remove/force # Add or remove space in 'enum {'. # # Default: add -sp_enum_brace = force # ignore/add/remove/force/not_defined +sp_enum_brace = force # ignore/add/remove/force # Add or remove space in 'NS_ENUM ('. -sp_enum_paren = ignore # ignore/add/remove/force/not_defined +sp_enum_paren = ignore # ignore/add/remove/force # Add or remove space around assignment '=' in enum. -sp_enum_assign = ignore # ignore/add/remove/force/not_defined +sp_enum_assign = ignore # ignore/add/remove/force # Add or remove space before assignment '=' in enum. # # Overrides sp_enum_assign. -sp_enum_before_assign = ignore # ignore/add/remove/force/not_defined +sp_enum_before_assign = ignore # ignore/add/remove/force # Add or remove space after assignment '=' in enum. # # Overrides sp_enum_assign. -sp_enum_after_assign = force # ignore/add/remove/force/not_defined +sp_enum_after_assign = force # ignore/add/remove/force # Add or remove space around assignment ':' in enum. -sp_enum_colon = ignore # ignore/add/remove/force/not_defined +sp_enum_colon = ignore # ignore/add/remove/force # Add or remove space around preprocessor '##' concatenation operator. # # Default: add -sp_pp_concat = remove # ignore/add/remove/force/not_defined +sp_pp_concat = remove # ignore/add/remove/force # Add or remove space after preprocessor '#' stringify operator. # Also affects the '#@' charizing operator. -sp_pp_stringify = remove # ignore/add/remove/force/not_defined +sp_pp_stringify = remove # ignore/add/remove/force # Add or remove space before preprocessor '#' stringify operator # as in '#define x(y) L#y'. -sp_before_pp_stringify = ignore # ignore/add/remove/force/not_defined +sp_before_pp_stringify = ignore # ignore/add/remove/force # Add or remove space around boolean operators '&&' and '||'. -sp_bool = force # ignore/add/remove/force/not_defined +sp_bool = force # ignore/add/remove/force # Add or remove space around compare operator '<', '>', '==', etc. -sp_compare = force # ignore/add/remove/force/not_defined +sp_compare = force # ignore/add/remove/force # Add or remove space inside '(' and ')'. -sp_inside_paren = remove # ignore/add/remove/force/not_defined +sp_inside_paren = remove # ignore/add/remove/force # Add or remove space between nested parentheses, i.e. '((' vs. ') )'. -sp_paren_paren = remove # ignore/add/remove/force/not_defined +sp_paren_paren = remove # ignore/add/remove/force # Add or remove space between back-to-back parentheses, i.e. ')(' vs. ') ('. -sp_cparen_oparen = remove # ignore/add/remove/force/not_defined - -# Whether to balance spaces inside nested parentheses. -sp_balance_nested_parens = false # true/false +sp_cparen_oparen = remove # ignore/add/remove/force # Add or remove space between ')' and '{'. -sp_paren_brace = ignore # ignore/add/remove/force/not_defined +sp_paren_brace = ignore # ignore/add/remove/force # Add or remove space between nested braces, i.e. '{{' vs. '{ {'. -sp_brace_brace = ignore # ignore/add/remove/force/not_defined +sp_brace_brace = ignore # ignore/add/remove/force # Add or remove space before pointer star '*'. -sp_before_ptr_star = force # ignore/add/remove/force/not_defined +sp_before_ptr_star = force # ignore/add/remove/force # Add or remove space before pointer star '*' that isn't followed by a # variable name. If set to ignore, sp_before_ptr_star is used instead. -sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force/not_defined +sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force # Add or remove space before pointer star '*' that is followed by a qualifier. # If set to ignore, sp_before_unnamed_ptr_star is used instead. -sp_before_qualifier_ptr_star = ignore # ignore/add/remove/force/not_defined +sp_before_qualifier_ptr_star = ignore # ignore/add/remove/force # Add or remove space before pointer star '*' that is followed by 'operator' keyword. # If set to ignore, sp_before_unnamed_ptr_star is used instead. -sp_before_operator_ptr_star = ignore # ignore/add/remove/force/not_defined +sp_before_operator_ptr_star = ignore # ignore/add/remove/force # Add or remove space before pointer star '*' that is followed by # a class scope (as in 'int *MyClass::method()') or namespace scope # (as in 'int *my_ns::func()'). # If set to ignore, sp_before_unnamed_ptr_star is used instead. -sp_before_scope_ptr_star = ignore # ignore/add/remove/force/not_defined +sp_before_scope_ptr_star = ignore # ignore/add/remove/force # Add or remove space before pointer star '*' that is followed by '::', # as in 'int *::func()'. # If set to ignore, sp_before_unnamed_ptr_star is used instead. -sp_before_global_scope_ptr_star = ignore # ignore/add/remove/force/not_defined +sp_before_global_scope_ptr_star = ignore # ignore/add/remove/force # Add or remove space between a qualifier and a pointer star '*' that isn't # followed by a variable name, as in '(char const *)'. If set to ignore, # sp_before_ptr_star is used instead. -sp_qualifier_unnamed_ptr_star = ignore # ignore/add/remove/force/not_defined +sp_qualifier_unnamed_ptr_star = ignore # ignore/add/remove/force # Add or remove space between pointer stars '*', as in 'int ***a;'. -sp_between_ptr_star = ignore # ignore/add/remove/force/not_defined +sp_between_ptr_star = ignore # ignore/add/remove/force # Add or remove space between pointer star '*' and reference '&', as in 'int *& a;'. -sp_between_ptr_ref = ignore # ignore/add/remove/force/not_defined +sp_between_ptr_ref = ignore # ignore/add/remove/force # Add or remove space after pointer star '*', if followed by a word. # # Overrides sp_type_func. -sp_after_ptr_star = remove # ignore/add/remove/force/not_defined +sp_after_ptr_star = remove # ignore/add/remove/force # Add or remove space after pointer caret '^', if followed by a word. -sp_after_ptr_block_caret = ignore # ignore/add/remove/force/not_defined +sp_after_ptr_block_caret = ignore # ignore/add/remove/force # Add or remove space after pointer star '*', if followed by a qualifier. -sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force/not_defined +sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force # Add or remove space after a pointer star '*', if followed by a function # prototype or function definition. # # Overrides sp_after_ptr_star and sp_type_func. -sp_after_ptr_star_func = remove # ignore/add/remove/force/not_defined +sp_after_ptr_star_func = remove # ignore/add/remove/force # Add or remove space after a pointer star '*' in the trailing return of a # function prototype or function definition. -sp_after_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined +sp_after_ptr_star_trailing = ignore # ignore/add/remove/force # Add or remove space between the pointer star '*' and the name of the variable # in a function pointer definition. -sp_ptr_star_func_var = ignore # ignore/add/remove/force/not_defined +sp_ptr_star_func_var = ignore # ignore/add/remove/force # Add or remove space between the pointer star '*' and the name of the type # in a function pointer type definition. -sp_ptr_star_func_type = ignore # ignore/add/remove/force/not_defined +sp_ptr_star_func_type = ignore # ignore/add/remove/force # Add or remove space after a pointer star '*', if followed by an open # parenthesis, as in 'void* (*)()'. -sp_ptr_star_paren = ignore # ignore/add/remove/force/not_defined +sp_ptr_star_paren = ignore # ignore/add/remove/force # Add or remove space before a pointer star '*', if followed by a function # prototype or function definition. If set to ignore, sp_before_ptr_star is # used instead. -sp_before_ptr_star_func = ignore # ignore/add/remove/force/not_defined +sp_before_ptr_star_func = ignore # ignore/add/remove/force # Add or remove space between a qualifier and a pointer star '*' followed by # the name of the function in a function prototype or definition, as in # 'char const *foo()`. If set to ignore, sp_before_ptr_star is used instead. -sp_qualifier_ptr_star_func = ignore # ignore/add/remove/force/not_defined +sp_qualifier_ptr_star_func = ignore # ignore/add/remove/force # Add or remove space before a pointer star '*' in the trailing return of a # function prototype or function definition. -sp_before_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined +sp_before_ptr_star_trailing = ignore # ignore/add/remove/force # Add or remove space between a qualifier and a pointer star '*' in the # trailing return of a function prototype or function definition, as in # 'auto foo() -> char const *'. -sp_qualifier_ptr_star_trailing = ignore # ignore/add/remove/force/not_defined +sp_qualifier_ptr_star_trailing = ignore # ignore/add/remove/force # Add or remove space before a reference sign '&'. -sp_before_byref = ignore # ignore/add/remove/force/not_defined +sp_before_byref = ignore # ignore/add/remove/force # Add or remove space before a reference sign '&' that isn't followed by a # variable name. If set to ignore, sp_before_byref is used instead. -sp_before_unnamed_byref = ignore # ignore/add/remove/force/not_defined +sp_before_unnamed_byref = ignore # ignore/add/remove/force # Add or remove space after reference sign '&', if followed by a word. # # Overrides sp_type_func. -sp_after_byref = ignore # ignore/add/remove/force/not_defined +sp_after_byref = ignore # ignore/add/remove/force # Add or remove space after a reference sign '&', if followed by a function # prototype or function definition. # # Overrides sp_after_byref and sp_type_func. -sp_after_byref_func = ignore # ignore/add/remove/force/not_defined +sp_after_byref_func = ignore # ignore/add/remove/force # Add or remove space before a reference sign '&', if followed by a function # prototype or function definition. -sp_before_byref_func = ignore # ignore/add/remove/force/not_defined +sp_before_byref_func = ignore # ignore/add/remove/force # Add or remove space after a reference sign '&', if followed by an open # parenthesis, as in 'char& (*)()'. -sp_byref_paren = ignore # ignore/add/remove/force/not_defined +sp_byref_paren = ignore # ignore/add/remove/force # Add or remove space between type and word. In cases where total removal of # whitespace would be a syntax error, a value of 'remove' is treated the same @@ -320,50 +317,50 @@ sp_byref_paren = ignore # ignore/add/remove/force/not_defined # following word. # # Default: force -sp_after_type = force # ignore/add/remove/force/not_defined +sp_after_type = force # ignore/add/remove/force # Add or remove space between 'decltype(...)' and word, # brace or function call. -sp_after_decltype = ignore # ignore/add/remove/force/not_defined +sp_after_decltype = ignore # ignore/add/remove/force # (D) Add or remove space before the parenthesis in the D constructs # 'template Foo(' and 'class Foo('. -sp_before_template_paren = ignore # ignore/add/remove/force/not_defined +sp_before_template_paren = ignore # ignore/add/remove/force # Add or remove space between 'template' and '<'. # If set to ignore, sp_before_angle is used. -sp_template_angle = ignore # ignore/add/remove/force/not_defined +sp_template_angle = ignore # ignore/add/remove/force # Add or remove space before '<'. -sp_before_angle = ignore # ignore/add/remove/force/not_defined +sp_before_angle = ignore # ignore/add/remove/force # Add or remove space inside '<' and '>'. -sp_inside_angle = ignore # ignore/add/remove/force/not_defined +sp_inside_angle = ignore # ignore/add/remove/force # Add or remove space inside '<>'. # if empty. -sp_inside_angle_empty = ignore # ignore/add/remove/force/not_defined +sp_inside_angle_empty = ignore # ignore/add/remove/force # Add or remove space between '>' and ':'. -sp_angle_colon = ignore # ignore/add/remove/force/not_defined +sp_angle_colon = ignore # ignore/add/remove/force # Add or remove space after '>'. -sp_after_angle = ignore # ignore/add/remove/force/not_defined +sp_after_angle = ignore # ignore/add/remove/force # Add or remove space between '>' and '(' as found in 'new List<byte>(foo);'. -sp_angle_paren = ignore # ignore/add/remove/force/not_defined +sp_angle_paren = ignore # ignore/add/remove/force # Add or remove space between '>' and '()' as found in 'new List<byte>();'. -sp_angle_paren_empty = ignore # ignore/add/remove/force/not_defined +sp_angle_paren_empty = ignore # ignore/add/remove/force # Add or remove space between '>' and a word as in 'List<byte> m;' or # 'template <typename T> static ...'. -sp_angle_word = ignore # ignore/add/remove/force/not_defined +sp_angle_word = ignore # ignore/add/remove/force # Add or remove space between '>' and '>' in '>>' (template stuff). # # Default: add -sp_angle_shift = add # ignore/add/remove/force/not_defined +sp_angle_shift = add # ignore/add/remove/force # (C++11) Permit removal of the space between '>>' in 'foo<bar<int> >'. Note # that sp_angle_shift cannot remove the space without this option. @@ -371,658 +368,662 @@ sp_permit_cpp11_shift = false # true/false # Add or remove space before '(' of control statements ('if', 'for', 'switch', # 'while', etc.). -sp_before_sparen = force # ignore/add/remove/force/not_defined +sp_before_sparen = force # ignore/add/remove/force # Add or remove space inside '(' and ')' of control statements other than # 'for'. -sp_inside_sparen = remove # ignore/add/remove/force/not_defined +sp_inside_sparen = remove # ignore/add/remove/force # Add or remove space after '(' of control statements other than 'for'. # # Overrides sp_inside_sparen. -sp_inside_sparen_open = ignore # ignore/add/remove/force/not_defined +sp_inside_sparen_open = ignore # ignore/add/remove/force # Add or remove space before ')' of control statements other than 'for'. # # Overrides sp_inside_sparen. -sp_inside_sparen_close = ignore # ignore/add/remove/force/not_defined +sp_inside_sparen_close = ignore # ignore/add/remove/force # Add or remove space inside '(' and ')' of 'for' statements. -sp_inside_for = remove # ignore/add/remove/force/not_defined +sp_inside_for = remove # ignore/add/remove/force # Add or remove space after '(' of 'for' statements. # # Overrides sp_inside_for. -sp_inside_for_open = ignore # ignore/add/remove/force/not_defined +sp_inside_for_open = ignore # ignore/add/remove/force # Add or remove space before ')' of 'for' statements. # # Overrides sp_inside_for. -sp_inside_for_close = ignore # ignore/add/remove/force/not_defined +sp_inside_for_close = ignore # ignore/add/remove/force # Add or remove space between '((' or '))' of control statements. -sp_sparen_paren = remove # ignore/add/remove/force/not_defined +sp_sparen_paren = remove # ignore/add/remove/force # Add or remove space after ')' of control statements. -sp_after_sparen = ignore # ignore/add/remove/force/not_defined +sp_after_sparen = ignore # ignore/add/remove/force # Add or remove space between ')' and '{' of control statements. -sp_sparen_brace = force # ignore/add/remove/force/not_defined +sp_sparen_brace = force # ignore/add/remove/force # Add or remove space between 'do' and '{'. -sp_do_brace_open = force # ignore/add/remove/force/not_defined +sp_do_brace_open = force # ignore/add/remove/force # Add or remove space between '}' and 'while'. -sp_brace_close_while = force # ignore/add/remove/force/not_defined +sp_brace_close_while = force # ignore/add/remove/force # Add or remove space between 'while' and '('. Overrides sp_before_sparen. -sp_while_paren_open = ignore # ignore/add/remove/force/not_defined +sp_while_paren_open = ignore # ignore/add/remove/force # (D) Add or remove space between 'invariant' and '('. -sp_invariant_paren = ignore # ignore/add/remove/force/not_defined +sp_invariant_paren = ignore # ignore/add/remove/force # (D) Add or remove space after the ')' in 'invariant (C) c'. -sp_after_invariant_paren = ignore # ignore/add/remove/force/not_defined +sp_after_invariant_paren = ignore # ignore/add/remove/force # Add or remove space before empty statement ';' on 'if', 'for' and 'while'. -sp_special_semi = ignore # ignore/add/remove/force/not_defined +sp_special_semi = ignore # ignore/add/remove/force # Add or remove space before ';'. # # Default: remove -sp_before_semi = remove # ignore/add/remove/force/not_defined +sp_before_semi = remove # ignore/add/remove/force # Add or remove space before ';' in non-empty 'for' statements. -sp_before_semi_for = remove # ignore/add/remove/force/not_defined +sp_before_semi_for = remove # ignore/add/remove/force # Add or remove space before a semicolon of an empty left part of a for # statement, as in 'for ( <here> ; ; )'. -sp_before_semi_for_empty = remove # ignore/add/remove/force/not_defined +sp_before_semi_for_empty = remove # ignore/add/remove/force # Add or remove space between the semicolons of an empty middle part of a for # statement, as in 'for ( ; <here> ; )'. -sp_between_semi_for_empty = remove # ignore/add/remove/force/not_defined +sp_between_semi_for_empty = remove # ignore/add/remove/force # Add or remove space after ';', except when followed by a comment. # # Default: add -sp_after_semi = add # ignore/add/remove/force/not_defined +sp_after_semi = add # ignore/add/remove/force # Add or remove space after ';' in non-empty 'for' statements. # # Default: force -sp_after_semi_for = force # ignore/add/remove/force/not_defined +sp_after_semi_for = force # ignore/add/remove/force # Add or remove space after the final semicolon of an empty part of a for # statement, as in 'for ( ; ; <here> )'. -sp_after_semi_for_empty = remove # ignore/add/remove/force/not_defined +sp_after_semi_for_empty = remove # ignore/add/remove/force # Add or remove space before '[' (except '[]'). -sp_before_square = remove # ignore/add/remove/force/not_defined +sp_before_square = remove # ignore/add/remove/force # Add or remove space before '[' for a variable definition. # # Default: remove -sp_before_vardef_square = remove # ignore/add/remove/force/not_defined +sp_before_vardef_square = remove # ignore/add/remove/force # Add or remove space before '[' for asm block. -sp_before_square_asm_block = ignore # ignore/add/remove/force/not_defined +sp_before_square_asm_block = ignore # ignore/add/remove/force # Add or remove space before '[]'. -sp_before_squares = remove # ignore/add/remove/force/not_defined +sp_before_squares = remove # ignore/add/remove/force + +# Add or remove space before C++17 structured bindings +# after byref. +sp_cpp_before_struct_binding_after_byref = ignore # ignore/add/remove/force # Add or remove space before C++17 structured bindings. -sp_cpp_before_struct_binding = ignore # ignore/add/remove/force/not_defined +sp_cpp_before_struct_binding = ignore # ignore/add/remove/force # Add or remove space inside a non-empty '[' and ']'. -sp_inside_square = remove # ignore/add/remove/force/not_defined +sp_inside_square = remove # ignore/add/remove/force # Add or remove space inside '[]'. # if empty. -sp_inside_square_empty = ignore # ignore/add/remove/force/not_defined +sp_inside_square_empty = ignore # ignore/add/remove/force # (OC) Add or remove space inside a non-empty Objective-C boxed array '@[' and # ']'. If set to ignore, sp_inside_square is used. -sp_inside_square_oc_array = ignore # ignore/add/remove/force/not_defined +sp_inside_square_oc_array = ignore # ignore/add/remove/force # Add or remove space after ',', i.e. 'a,b' vs. 'a, b'. -sp_after_comma = add # ignore/add/remove/force/not_defined +sp_after_comma = add # ignore/add/remove/force # Add or remove space before ',', i.e. 'a,b' vs. 'a ,b'. # # Default: remove -sp_before_comma = remove # ignore/add/remove/force/not_defined +sp_before_comma = remove # ignore/add/remove/force # (C#, Vala) Add or remove space between ',' and ']' in multidimensional array type # like 'int[,,]'. -sp_after_mdatype_commas = ignore # ignore/add/remove/force/not_defined +sp_after_mdatype_commas = ignore # ignore/add/remove/force # (C#, Vala) Add or remove space between '[' and ',' in multidimensional array type # like 'int[,,]'. -sp_before_mdatype_commas = ignore # ignore/add/remove/force/not_defined +sp_before_mdatype_commas = ignore # ignore/add/remove/force # (C#, Vala) Add or remove space between ',' in multidimensional array type # like 'int[,,]'. -sp_between_mdatype_commas = ignore # ignore/add/remove/force/not_defined +sp_between_mdatype_commas = ignore # ignore/add/remove/force # Add or remove space between an open parenthesis and comma, # i.e. '(,' vs. '( ,'. # # Default: force -sp_paren_comma = force # ignore/add/remove/force/not_defined +sp_paren_comma = force # ignore/add/remove/force # Add or remove space between a type and ':'. -sp_type_colon = ignore # ignore/add/remove/force/not_defined +sp_type_colon = ignore # ignore/add/remove/force # Add or remove space after the variadic '...' when preceded by a # non-punctuator. # The value REMOVE will be overridden with FORCE -sp_after_ellipsis = ignore # ignore/add/remove/force/not_defined +sp_after_ellipsis = ignore # ignore/add/remove/force # Add or remove space before the variadic '...' when preceded by a # non-punctuator. # The value REMOVE will be overridden with FORCE -sp_before_ellipsis = ignore # ignore/add/remove/force/not_defined +sp_before_ellipsis = ignore # ignore/add/remove/force # Add or remove space between a type and '...'. -sp_type_ellipsis = ignore # ignore/add/remove/force/not_defined +sp_type_ellipsis = ignore # ignore/add/remove/force # Add or remove space between a '*' and '...'. -sp_ptr_type_ellipsis = ignore # ignore/add/remove/force/not_defined +sp_ptr_type_ellipsis = ignore # ignore/add/remove/force # Add or remove space between ')' and '...'. -sp_paren_ellipsis = ignore # ignore/add/remove/force/not_defined +sp_paren_ellipsis = ignore # ignore/add/remove/force # Add or remove space between '&&' and '...'. -sp_byref_ellipsis = ignore # ignore/add/remove/force/not_defined +sp_byref_ellipsis = ignore # ignore/add/remove/force # Add or remove space between ')' and a qualifier such as 'const'. -sp_paren_qualifier = ignore # ignore/add/remove/force/not_defined +sp_paren_qualifier = ignore # ignore/add/remove/force # Add or remove space between ')' and 'noexcept'. -sp_paren_noexcept = ignore # ignore/add/remove/force/not_defined +sp_paren_noexcept = ignore # ignore/add/remove/force # Add or remove space after class ':'. -sp_after_class_colon = remove # ignore/add/remove/force/not_defined +sp_after_class_colon = remove # ignore/add/remove/force # Add or remove space before class ':'. -sp_before_class_colon = ignore # ignore/add/remove/force/not_defined +sp_before_class_colon = ignore # ignore/add/remove/force # Add or remove space after class constructor ':'. # # Default: add -sp_after_constr_colon = add # ignore/add/remove/force/not_defined +sp_after_constr_colon = add # ignore/add/remove/force # Add or remove space before class constructor ':'. # # Default: add -sp_before_constr_colon = add # ignore/add/remove/force/not_defined +sp_before_constr_colon = add # ignore/add/remove/force # Add or remove space before case ':'. # # Default: remove -sp_before_case_colon = remove # ignore/add/remove/force/not_defined +sp_before_case_colon = remove # ignore/add/remove/force # Add or remove space between 'operator' and operator sign. -sp_after_operator = ignore # ignore/add/remove/force/not_defined +sp_after_operator = ignore # ignore/add/remove/force # Add or remove space between the operator symbol and the open parenthesis, as # in 'operator ++('. -sp_after_operator_sym = ignore # ignore/add/remove/force/not_defined +sp_after_operator_sym = ignore # ignore/add/remove/force # Overrides sp_after_operator_sym when the operator has no arguments, as in # 'operator *()'. -sp_after_operator_sym_empty = ignore # ignore/add/remove/force/not_defined +sp_after_operator_sym_empty = ignore # ignore/add/remove/force # Add or remove space after C/D cast, i.e. 'cast(int)a' vs. 'cast(int) a' or # '(int)a' vs. '(int) a'. -sp_after_cast = remove # ignore/add/remove/force/not_defined +sp_after_cast = remove # ignore/add/remove/force # Add or remove spaces inside cast parentheses. -sp_inside_paren_cast = remove # ignore/add/remove/force/not_defined +sp_inside_paren_cast = remove # ignore/add/remove/force # Add or remove space between the type and open parenthesis in a C++ cast, # i.e. 'int(exp)' vs. 'int (exp)'. -sp_cpp_cast_paren = ignore # ignore/add/remove/force/not_defined +sp_cpp_cast_paren = ignore # ignore/add/remove/force # Add or remove space between 'sizeof' and '('. -sp_sizeof_paren = remove # ignore/add/remove/force/not_defined +sp_sizeof_paren = remove # ignore/add/remove/force # Add or remove space between 'sizeof' and '...'. -sp_sizeof_ellipsis = ignore # ignore/add/remove/force/not_defined +sp_sizeof_ellipsis = ignore # ignore/add/remove/force # Add or remove space between 'sizeof...' and '('. -sp_sizeof_ellipsis_paren = ignore # ignore/add/remove/force/not_defined +sp_sizeof_ellipsis_paren = ignore # ignore/add/remove/force # Add or remove space between '...' and a parameter pack. -sp_ellipsis_parameter_pack = ignore # ignore/add/remove/force/not_defined +sp_ellipsis_parameter_pack = ignore # ignore/add/remove/force # Add or remove space between a parameter pack and '...'. -sp_parameter_pack_ellipsis = ignore # ignore/add/remove/force/not_defined +sp_parameter_pack_ellipsis = ignore # ignore/add/remove/force # Add or remove space between 'decltype' and '('. -sp_decltype_paren = ignore # ignore/add/remove/force/not_defined +sp_decltype_paren = ignore # ignore/add/remove/force # (Pawn) Add or remove space after the tag keyword. -sp_after_tag = ignore # ignore/add/remove/force/not_defined +sp_after_tag = ignore # ignore/add/remove/force # Add or remove space inside enum '{' and '}'. -sp_inside_braces_enum = force # ignore/add/remove/force/not_defined +sp_inside_braces_enum = force # ignore/add/remove/force # Add or remove space inside struct/union '{' and '}'. -sp_inside_braces_struct = ignore # ignore/add/remove/force/not_defined +sp_inside_braces_struct = ignore # ignore/add/remove/force # (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}' -sp_inside_braces_oc_dict = ignore # ignore/add/remove/force/not_defined +sp_inside_braces_oc_dict = ignore # ignore/add/remove/force # Add or remove space after open brace in an unnamed temporary # direct-list-initialization # if statement is a brace_init_lst # works only if sp_brace_brace is set to ignore. -sp_after_type_brace_init_lst_open = ignore # ignore/add/remove/force/not_defined +sp_after_type_brace_init_lst_open = ignore # ignore/add/remove/force # Add or remove space before close brace in an unnamed temporary # direct-list-initialization # if statement is a brace_init_lst # works only if sp_brace_brace is set to ignore. -sp_before_type_brace_init_lst_close = ignore # ignore/add/remove/force/not_defined +sp_before_type_brace_init_lst_close = ignore # ignore/add/remove/force # Add or remove space inside an unnamed temporary direct-list-initialization # if statement is a brace_init_lst # works only if sp_brace_brace is set to ignore # works only if sp_before_type_brace_init_lst_close is set to ignore. -sp_inside_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined +sp_inside_type_brace_init_lst = ignore # ignore/add/remove/force # Add or remove space inside '{' and '}'. -sp_inside_braces = add # ignore/add/remove/force/not_defined +sp_inside_braces = add # ignore/add/remove/force # Add or remove space inside '{}'. # if empty. -sp_inside_braces_empty = remove # ignore/add/remove/force/not_defined +sp_inside_braces_empty = remove # ignore/add/remove/force # Add or remove space around trailing return operator '->'. -sp_trailing_return = ignore # ignore/add/remove/force/not_defined +sp_trailing_return = ignore # ignore/add/remove/force # Add or remove space between return type and function name. A minimum of 1 # is forced except for pointer return types. -sp_type_func = ignore # ignore/add/remove/force/not_defined +sp_type_func = ignore # ignore/add/remove/force # Add or remove space between type and open brace of an unnamed temporary # direct-list-initialization. -sp_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined +sp_type_brace_init_lst = ignore # ignore/add/remove/force # Add or remove space between function name and '(' on function declaration. -sp_func_proto_paren = remove # ignore/add/remove/force/not_defined +sp_func_proto_paren = remove # ignore/add/remove/force # Add or remove space between function name and '()' on function declaration # if empty. -sp_func_proto_paren_empty = ignore # ignore/add/remove/force/not_defined +sp_func_proto_paren_empty = ignore # ignore/add/remove/force # Add or remove space between function name and '(' with a typedef specifier. -sp_func_type_paren = ignore # ignore/add/remove/force/not_defined +sp_func_type_paren = ignore # ignore/add/remove/force # Add or remove space between alias name and '(' of a non-pointer function type typedef. -sp_func_def_paren = remove # ignore/add/remove/force/not_defined +sp_func_def_paren = remove # ignore/add/remove/force # Add or remove space between function name and '()' on function definition # if empty. -sp_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined +sp_func_def_paren_empty = ignore # ignore/add/remove/force # Add or remove space inside empty function '()'. # Overrides sp_after_angle unless use_sp_after_angle_always is set to true. -sp_inside_fparens = remove # ignore/add/remove/force/not_defined +sp_inside_fparens = remove # ignore/add/remove/force # Add or remove space inside function '(' and ')'. -sp_inside_fparen = remove # ignore/add/remove/force/not_defined +sp_inside_fparen = remove # ignore/add/remove/force # Add or remove space inside user functor '(' and ')'. -sp_func_call_user_inside_rparen = ignore # ignore/add/remove/force/not_defined +sp_func_call_user_inside_rparen = ignore # ignore/add/remove/force # Add or remove space inside empty functor '()'. # Overrides sp_after_angle unless use_sp_after_angle_always is set to true. -sp_inside_rparens = ignore # ignore/add/remove/force/not_defined +sp_inside_rparens = ignore # ignore/add/remove/force # Add or remove space inside functor '(' and ')'. -sp_inside_rparen = ignore # ignore/add/remove/force/not_defined +sp_inside_rparen = ignore # ignore/add/remove/force # Add or remove space inside the first parentheses in a function type, as in # 'void (*x)(...)'. -sp_inside_tparen = remove # ignore/add/remove/force/not_defined +sp_inside_tparen = remove # ignore/add/remove/force # Add or remove space between the ')' and '(' in a function type, as in # 'void (*x)(...)'. -sp_after_tparen_close = remove # ignore/add/remove/force/not_defined +sp_after_tparen_close = remove # ignore/add/remove/force # Add or remove space between ']' and '(' when part of a function call. -sp_square_fparen = ignore # ignore/add/remove/force/not_defined +sp_square_fparen = ignore # ignore/add/remove/force # Add or remove space between ')' and '{' of function. -sp_fparen_brace = ignore # ignore/add/remove/force/not_defined +sp_fparen_brace = ignore # ignore/add/remove/force # Add or remove space between ')' and '{' of a function call in object # initialization. # # Overrides sp_fparen_brace. -sp_fparen_brace_initializer = ignore # ignore/add/remove/force/not_defined +sp_fparen_brace_initializer = ignore # ignore/add/remove/force # (Java) Add or remove space between ')' and '{{' of double brace initializer. -sp_fparen_dbrace = ignore # ignore/add/remove/force/not_defined +sp_fparen_dbrace = ignore # ignore/add/remove/force # Add or remove space between function name and '(' on function calls. -sp_func_call_paren = remove # ignore/add/remove/force/not_defined +sp_func_call_paren = remove # ignore/add/remove/force # Add or remove space between function name and '()' on function calls without # parameters. If set to ignore (the default), sp_func_call_paren is used. -sp_func_call_paren_empty = ignore # ignore/add/remove/force/not_defined +sp_func_call_paren_empty = ignore # ignore/add/remove/force # Add or remove space between the user function name and '(' on function # calls. You need to set a keyword to be a user function in the config file, # like: # set func_call_user tr _ i18n -sp_func_call_user_paren = ignore # ignore/add/remove/force/not_defined +sp_func_call_user_paren = ignore # ignore/add/remove/force # Add or remove space inside user function '(' and ')'. -sp_func_call_user_inside_fparen = ignore # ignore/add/remove/force/not_defined +sp_func_call_user_inside_fparen = ignore # ignore/add/remove/force # Add or remove space between nested parentheses with user functions, # i.e. '((' vs. '( ('. -sp_func_call_user_paren_paren = ignore # ignore/add/remove/force/not_defined +sp_func_call_user_paren_paren = ignore # ignore/add/remove/force # Add or remove space between a constructor/destructor and the open # parenthesis. -sp_func_class_paren = ignore # ignore/add/remove/force/not_defined +sp_func_class_paren = ignore # ignore/add/remove/force # Add or remove space between a constructor without parameters or destructor # and '()'. -sp_func_class_paren_empty = ignore # ignore/add/remove/force/not_defined +sp_func_class_paren_empty = ignore # ignore/add/remove/force # Add or remove space after 'return'. # # Default: force -sp_return = force # ignore/add/remove/force/not_defined +sp_return = force # ignore/add/remove/force # Add or remove space between 'return' and '('. -sp_return_paren = force # ignore/add/remove/force/not_defined +sp_return_paren = force # ignore/add/remove/force # Add or remove space between 'return' and '{'. -sp_return_brace = ignore # ignore/add/remove/force/not_defined +sp_return_brace = ignore # ignore/add/remove/force # Add or remove space between '__attribute__' and '('. -sp_attribute_paren = remove # ignore/add/remove/force/not_defined +sp_attribute_paren = remove # ignore/add/remove/force # Add or remove space between 'defined' and '(' in '#if defined (FOO)'. -sp_defined_paren = remove # ignore/add/remove/force/not_defined +sp_defined_paren = remove # ignore/add/remove/force # Add or remove space between 'throw' and '(' in 'throw (something)'. -sp_throw_paren = ignore # ignore/add/remove/force/not_defined +sp_throw_paren = ignore # ignore/add/remove/force # Add or remove space between 'throw' and anything other than '(' as in # '@throw [...];'. -sp_after_throw = ignore # ignore/add/remove/force/not_defined +sp_after_throw = ignore # ignore/add/remove/force # Add or remove space between 'catch' and '(' in 'catch (something) { }'. # If set to ignore, sp_before_sparen is used. -sp_catch_paren = ignore # ignore/add/remove/force/not_defined +sp_catch_paren = ignore # ignore/add/remove/force # (OC) Add or remove space between '@catch' and '(' # in '@catch (something) { }'. If set to ignore, sp_catch_paren is used. -sp_oc_catch_paren = ignore # ignore/add/remove/force/not_defined +sp_oc_catch_paren = ignore # ignore/add/remove/force # (OC) Add or remove space before Objective-C protocol list # as in '@protocol Protocol<here><Protocol_A>' or '@interface MyClass : NSObject<here><MyProtocol>'. -sp_before_oc_proto_list = ignore # ignore/add/remove/force/not_defined +sp_before_oc_proto_list = ignore # ignore/add/remove/force # (OC) Add or remove space between class name and '(' # in '@interface className(categoryName)<ProtocolName>:BaseClass' -sp_oc_classname_paren = ignore # ignore/add/remove/force/not_defined +sp_oc_classname_paren = ignore # ignore/add/remove/force # (D) Add or remove space between 'version' and '(' # in 'version (something) { }'. If set to ignore, sp_before_sparen is used. -sp_version_paren = ignore # ignore/add/remove/force/not_defined +sp_version_paren = ignore # ignore/add/remove/force # (D) Add or remove space between 'scope' and '(' # in 'scope (something) { }'. If set to ignore, sp_before_sparen is used. -sp_scope_paren = ignore # ignore/add/remove/force/not_defined +sp_scope_paren = ignore # ignore/add/remove/force # Add or remove space between 'super' and '(' in 'super (something)'. # # Default: remove -sp_super_paren = remove # ignore/add/remove/force/not_defined +sp_super_paren = remove # ignore/add/remove/force # Add or remove space between 'this' and '(' in 'this (something)'. # # Default: remove -sp_this_paren = remove # ignore/add/remove/force/not_defined +sp_this_paren = remove # ignore/add/remove/force # Add or remove space between a macro name and its definition. -sp_macro = ignore # ignore/add/remove/force/not_defined +sp_macro = ignore # ignore/add/remove/force # Add or remove space between a macro function ')' and its definition. -sp_macro_func = ignore # ignore/add/remove/force/not_defined +sp_macro_func = ignore # ignore/add/remove/force # Add or remove space between 'else' and '{' if on the same line. -sp_else_brace = force # ignore/add/remove/force/not_defined +sp_else_brace = force # ignore/add/remove/force # Add or remove space between '}' and 'else' if on the same line. -sp_brace_else = force # ignore/add/remove/force/not_defined +sp_brace_else = force # ignore/add/remove/force # Add or remove space between '}' and the name of a typedef on the same line. -sp_brace_typedef = force # ignore/add/remove/force/not_defined +sp_brace_typedef = force # ignore/add/remove/force # Add or remove space before the '{' of a 'catch' statement, if the '{' and # 'catch' are on the same line, as in 'catch (decl) <here> {'. -sp_catch_brace = ignore # ignore/add/remove/force/not_defined +sp_catch_brace = ignore # ignore/add/remove/force # (OC) Add or remove space before the '{' of a '@catch' statement, if the '{' # and '@catch' are on the same line, as in '@catch (decl) <here> {'. # If set to ignore, sp_catch_brace is used. -sp_oc_catch_brace = ignore # ignore/add/remove/force/not_defined +sp_oc_catch_brace = ignore # ignore/add/remove/force # Add or remove space between '}' and 'catch' if on the same line. -sp_brace_catch = ignore # ignore/add/remove/force/not_defined +sp_brace_catch = ignore # ignore/add/remove/force # (OC) Add or remove space between '}' and '@catch' if on the same line. # If set to ignore, sp_brace_catch is used. -sp_oc_brace_catch = ignore # ignore/add/remove/force/not_defined +sp_oc_brace_catch = ignore # ignore/add/remove/force # Add or remove space between 'finally' and '{' if on the same line. -sp_finally_brace = ignore # ignore/add/remove/force/not_defined +sp_finally_brace = ignore # ignore/add/remove/force # Add or remove space between '}' and 'finally' if on the same line. -sp_brace_finally = ignore # ignore/add/remove/force/not_defined +sp_brace_finally = ignore # ignore/add/remove/force # Add or remove space between 'try' and '{' if on the same line. -sp_try_brace = ignore # ignore/add/remove/force/not_defined +sp_try_brace = ignore # ignore/add/remove/force # Add or remove space between get/set and '{' if on the same line. -sp_getset_brace = ignore # ignore/add/remove/force/not_defined +sp_getset_brace = ignore # ignore/add/remove/force # Add or remove space between a variable and '{' for C++ uniform # initialization. -sp_word_brace_init_lst = ignore # ignore/add/remove/force/not_defined +sp_word_brace_init_lst = ignore # ignore/add/remove/force # Add or remove space between a variable and '{' for a namespace. # # Default: add -sp_word_brace_ns = add # ignore/add/remove/force/not_defined +sp_word_brace_ns = add # ignore/add/remove/force # Add or remove space before the '::' operator. -sp_before_dc = ignore # ignore/add/remove/force/not_defined +sp_before_dc = ignore # ignore/add/remove/force # Add or remove space after the '::' operator. -sp_after_dc = ignore # ignore/add/remove/force/not_defined +sp_after_dc = ignore # ignore/add/remove/force # (D) Add or remove around the D named array initializer ':' operator. -sp_d_array_colon = ignore # ignore/add/remove/force/not_defined +sp_d_array_colon = ignore # ignore/add/remove/force # Add or remove space after the '!' (not) unary operator. # # Default: remove -sp_not = remove # ignore/add/remove/force/not_defined +sp_not = remove # ignore/add/remove/force # Add or remove space between two '!' (not) unary operators. # If set to ignore, sp_not will be used. -sp_not_not = ignore # ignore/add/remove/force/not_defined +sp_not_not = ignore # ignore/add/remove/force # Add or remove space after the '~' (invert) unary operator. # # Default: remove -sp_inv = remove # ignore/add/remove/force/not_defined +sp_inv = remove # ignore/add/remove/force # Add or remove space after the '&' (address-of) unary operator. This does not # affect the spacing after a '&' that is part of a type. # # Default: remove -sp_addr = ignore # ignore/add/remove/force/not_defined +sp_addr = ignore # ignore/add/remove/force # Add or remove space around the '.' or '->' operators. # # Default: remove -sp_member = remove # ignore/add/remove/force/not_defined +sp_member = remove # ignore/add/remove/force # Add or remove space after the '*' (dereference) unary operator. This does # not affect the spacing after a '*' that is part of a type. # # Default: remove -sp_deref = remove # ignore/add/remove/force/not_defined +sp_deref = remove # ignore/add/remove/force # Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. # # Default: remove -sp_sign = remove # ignore/add/remove/force/not_defined +sp_sign = remove # ignore/add/remove/force # Add or remove space between '++' and '--' the word to which it is being # applied, as in '(--x)' or 'y++;'. # # Default: remove -sp_incdec = remove # ignore/add/remove/force/not_defined +sp_incdec = remove # ignore/add/remove/force # Add or remove space before a backslash-newline at the end of a line. # # Default: add -sp_before_nl_cont = force # ignore/add/remove/force/not_defined +sp_before_nl_cont = force # ignore/add/remove/force # (OC) Add or remove space after the scope '+' or '-', as in '-(void) foo;' # or '+(int) bar;'. -sp_after_oc_scope = ignore # ignore/add/remove/force/not_defined +sp_after_oc_scope = ignore # ignore/add/remove/force # (OC) Add or remove space after the colon in message specs, # i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'. -sp_after_oc_colon = ignore # ignore/add/remove/force/not_defined +sp_after_oc_colon = ignore # ignore/add/remove/force # (OC) Add or remove space before the colon in message specs, # i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'. -sp_before_oc_colon = ignore # ignore/add/remove/force/not_defined +sp_before_oc_colon = ignore # ignore/add/remove/force # (OC) Add or remove space after the colon in immutable dictionary expression # 'NSDictionary *test = @{@"foo" :@"bar"};'. -sp_after_oc_dict_colon = ignore # ignore/add/remove/force/not_defined +sp_after_oc_dict_colon = ignore # ignore/add/remove/force # (OC) Add or remove space before the colon in immutable dictionary expression # 'NSDictionary *test = @{@"foo" :@"bar"};'. -sp_before_oc_dict_colon = ignore # ignore/add/remove/force/not_defined +sp_before_oc_dict_colon = ignore # ignore/add/remove/force # (OC) Add or remove space after the colon in message specs, # i.e. '[object setValue:1];' vs. '[object setValue: 1];'. -sp_after_send_oc_colon = ignore # ignore/add/remove/force/not_defined +sp_after_send_oc_colon = ignore # ignore/add/remove/force # (OC) Add or remove space before the colon in message specs, # i.e. '[object setValue:1];' vs. '[object setValue :1];'. -sp_before_send_oc_colon = ignore # ignore/add/remove/force/not_defined +sp_before_send_oc_colon = ignore # ignore/add/remove/force # (OC) Add or remove space after the (type) in message specs, # i.e. '-(int)f: (int) x;' vs. '-(int)f: (int)x;'. -sp_after_oc_type = ignore # ignore/add/remove/force/not_defined +sp_after_oc_type = ignore # ignore/add/remove/force # (OC) Add or remove space after the first (type) in message specs, # i.e. '-(int) f:(int)x;' vs. '-(int)f:(int)x;'. -sp_after_oc_return_type = ignore # ignore/add/remove/force/not_defined +sp_after_oc_return_type = ignore # ignore/add/remove/force # (OC) Add or remove space between '@selector' and '(', # i.e. '@selector(msgName)' vs. '@selector (msgName)'. # Also applies to '@protocol()' constructs. -sp_after_oc_at_sel = ignore # ignore/add/remove/force/not_defined +sp_after_oc_at_sel = ignore # ignore/add/remove/force # (OC) Add or remove space between '@selector(x)' and the following word, # i.e. '@selector(foo) a:' vs. '@selector(foo)a:'. -sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force/not_defined +sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force # (OC) Add or remove space inside '@selector' parentheses, # i.e. '@selector(foo)' vs. '@selector( foo )'. # Also applies to '@protocol()' constructs. -sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force/not_defined +sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force # (OC) Add or remove space before a block pointer caret, # i.e. '^int (int arg){...}' vs. ' ^int (int arg){...}'. -sp_before_oc_block_caret = ignore # ignore/add/remove/force/not_defined +sp_before_oc_block_caret = ignore # ignore/add/remove/force # (OC) Add or remove space after a block pointer caret, # i.e. '^int (int arg){...}' vs. '^ int (int arg){...}'. -sp_after_oc_block_caret = ignore # ignore/add/remove/force/not_defined +sp_after_oc_block_caret = ignore # ignore/add/remove/force # (OC) Add or remove space between the receiver and selector in a message, # as in '[receiver selector ...]'. -sp_after_oc_msg_receiver = ignore # ignore/add/remove/force/not_defined +sp_after_oc_msg_receiver = ignore # ignore/add/remove/force # (OC) Add or remove space after '@property'. -sp_after_oc_property = ignore # ignore/add/remove/force/not_defined +sp_after_oc_property = ignore # ignore/add/remove/force # (OC) Add or remove space between '@synchronized' and the open parenthesis, # i.e. '@synchronized(foo)' vs. '@synchronized (foo)'. -sp_after_oc_synchronized = ignore # ignore/add/remove/force/not_defined +sp_after_oc_synchronized = ignore # ignore/add/remove/force # Add or remove space around the ':' in 'b ? t : f'. -sp_cond_colon = force # ignore/add/remove/force/not_defined +sp_cond_colon = force # ignore/add/remove/force # Add or remove space before the ':' in 'b ? t : f'. # # Overrides sp_cond_colon. -sp_cond_colon_before = ignore # ignore/add/remove/force/not_defined +sp_cond_colon_before = ignore # ignore/add/remove/force # Add or remove space after the ':' in 'b ? t : f'. # # Overrides sp_cond_colon. -sp_cond_colon_after = ignore # ignore/add/remove/force/not_defined +sp_cond_colon_after = ignore # ignore/add/remove/force # Add or remove space around the '?' in 'b ? t : f'. -sp_cond_question = force # ignore/add/remove/force/not_defined +sp_cond_question = force # ignore/add/remove/force # Add or remove space before the '?' in 'b ? t : f'. # # Overrides sp_cond_question. -sp_cond_question_before = ignore # ignore/add/remove/force/not_defined +sp_cond_question_before = ignore # ignore/add/remove/force # Add or remove space after the '?' in 'b ? t : f'. # # Overrides sp_cond_question. -sp_cond_question_after = ignore # ignore/add/remove/force/not_defined +sp_cond_question_after = ignore # ignore/add/remove/force # In the abbreviated ternary form '(a ?: b)', add or remove space between '?' # and ':'. # # Overrides all other sp_cond_* options. -sp_cond_ternary_short = ignore # ignore/add/remove/force/not_defined +sp_cond_ternary_short = ignore # ignore/add/remove/force # Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make # sense here. -sp_case_label = ignore # ignore/add/remove/force/not_defined +sp_case_label = ignore # ignore/add/remove/force # (D) Add or remove space around the D '..' operator. -sp_range = ignore # ignore/add/remove/force/not_defined +sp_range = ignore # ignore/add/remove/force # Add or remove space after ':' in a Java/C++11 range-based 'for', # as in 'for (Type var : <here> expr)'. -sp_after_for_colon = ignore # ignore/add/remove/force/not_defined +sp_after_for_colon = ignore # ignore/add/remove/force # Add or remove space before ':' in a Java/C++11 range-based 'for', # as in 'for (Type var <here> : expr)'. -sp_before_for_colon = ignore # ignore/add/remove/force/not_defined +sp_before_for_colon = ignore # ignore/add/remove/force # (D) Add or remove space between 'extern' and '(' as in 'extern <here> (C)'. -sp_extern_paren = ignore # ignore/add/remove/force/not_defined +sp_extern_paren = ignore # ignore/add/remove/force # Add or remove space after the opening of a C++ comment, as in '// <here> A'. -sp_cmt_cpp_start = ignore # ignore/add/remove/force/not_defined +sp_cmt_cpp_start = ignore # ignore/add/remove/force # remove space after the '//' and the pvs command '-V1234', # only works with sp_cmt_cpp_start set to add or force. @@ -1038,7 +1039,7 @@ sp_cmt_cpp_lint = false # true/false # with either 'BEGIN' or 'END'. # # Overrides sp_cmt_cpp_start. -sp_cmt_cpp_region = ignore # ignore/add/remove/force/not_defined +sp_cmt_cpp_region = ignore # ignore/add/remove/force # If true, space added with sp_cmt_cpp_start will be added after Doxygen # sequences like '///', '///<', '//!' and '//!<'. @@ -1049,35 +1050,35 @@ sp_cmt_cpp_doxygen = false # true/false sp_cmt_cpp_qttr = false # true/false # Add or remove space between #else or #endif and a trailing comment. -sp_endif_cmt = ignore # ignore/add/remove/force/not_defined +sp_endif_cmt = ignore # ignore/add/remove/force # Add or remove space after 'new', 'delete' and 'delete[]'. -sp_after_new = ignore # ignore/add/remove/force/not_defined +sp_after_new = ignore # ignore/add/remove/force # Add or remove space between 'new' and '(' in 'new()'. -sp_between_new_paren = ignore # ignore/add/remove/force/not_defined +sp_between_new_paren = ignore # ignore/add/remove/force # Add or remove space between ')' and type in 'new(foo) BAR'. -sp_after_newop_paren = ignore # ignore/add/remove/force/not_defined +sp_after_newop_paren = ignore # ignore/add/remove/force # Add or remove space inside parentheses of the new operator # as in 'new(foo) BAR'. -sp_inside_newop_paren = ignore # ignore/add/remove/force/not_defined +sp_inside_newop_paren = ignore # ignore/add/remove/force # Add or remove space after the open parenthesis of the new operator, # as in 'new(foo) BAR'. # # Overrides sp_inside_newop_paren. -sp_inside_newop_paren_open = ignore # ignore/add/remove/force/not_defined +sp_inside_newop_paren_open = ignore # ignore/add/remove/force # Add or remove space before the close parenthesis of the new operator, # as in 'new(foo) BAR'. # # Overrides sp_inside_newop_paren. -sp_inside_newop_paren_close = ignore # ignore/add/remove/force/not_defined +sp_inside_newop_paren_close = ignore # ignore/add/remove/force # Add or remove space before a trailing comment. -sp_before_tr_cmt = add # ignore/add/remove/force/not_defined +sp_before_tr_cmt = add # ignore/add/remove/force # Number of spaces before a trailing comment. sp_num_before_tr_cmt = 2 # unsigned number @@ -1085,7 +1086,7 @@ sp_num_before_tr_cmt = 2 # unsigned number # Add or remove space before an embedded comment. # # Default: force -sp_before_emb_cmt = force # ignore/add/remove/force/not_defined +sp_before_emb_cmt = force # ignore/add/remove/force # Number of spaces before an embedded comment. # @@ -1095,7 +1096,7 @@ sp_num_before_emb_cmt = 1 # unsigned number # Add or remove space after an embedded comment. # # Default: force -sp_after_emb_cmt = force # ignore/add/remove/force/not_defined +sp_after_emb_cmt = force # ignore/add/remove/force # Number of spaces after an embedded comment. # @@ -1103,26 +1104,29 @@ sp_after_emb_cmt = force # ignore/add/remove/force/not_defined sp_num_after_emb_cmt = 1 # unsigned number # (Java) Add or remove space between an annotation and the open parenthesis. -sp_annotation_paren = ignore # ignore/add/remove/force/not_defined +sp_annotation_paren = ignore # ignore/add/remove/force # If true, vbrace tokens are dropped to the previous token and skipped. sp_skip_vbrace_tokens = false # true/false # Add or remove space after 'noexcept'. -sp_after_noexcept = ignore # ignore/add/remove/force/not_defined +sp_after_noexcept = ignore # ignore/add/remove/force # Add or remove space after '_'. -sp_vala_after_translation = ignore # ignore/add/remove/force/not_defined +sp_vala_after_translation = ignore # ignore/add/remove/force # Add or remove space before a bit colon ':'. -sp_before_bit_colon = ignore # ignore/add/remove/force/not_defined +sp_before_bit_colon = ignore # ignore/add/remove/force # Add or remove space after a bit colon ':'. -sp_after_bit_colon = ignore # ignore/add/remove/force/not_defined +sp_after_bit_colon = ignore # ignore/add/remove/force # If true, a <TAB> is inserted after #define. force_tab_after_define = false # true/false +# Add or remove space between two strings. +sp_string_string = force # ignore/add/remove/force + # # Indenting options # @@ -1683,166 +1687,166 @@ nl_for_leave_one_liners = false # true/false nl_oc_msg_leave_one_liner = false # true/false # (OC) Add or remove newline between method declaration and '{'. -nl_oc_mdef_brace = ignore # ignore/add/remove/force/not_defined +nl_oc_mdef_brace = ignore # ignore/add/remove/force # (OC) Add or remove newline between Objective-C block signature and '{'. -nl_oc_block_brace = ignore # ignore/add/remove/force/not_defined +nl_oc_block_brace = ignore # ignore/add/remove/force # (OC) Add or remove blank line before '@interface' statement. -nl_oc_before_interface = ignore # ignore/add/remove/force/not_defined +nl_oc_before_interface = ignore # ignore/add/remove/force # (OC) Add or remove blank line before '@implementation' statement. -nl_oc_before_implementation = ignore # ignore/add/remove/force/not_defined +nl_oc_before_implementation = ignore # ignore/add/remove/force # (OC) Add or remove blank line before '@end' statement. -nl_oc_before_end = ignore # ignore/add/remove/force/not_defined +nl_oc_before_end = ignore # ignore/add/remove/force # (OC) Add or remove newline between '@interface' and '{'. -nl_oc_interface_brace = ignore # ignore/add/remove/force/not_defined +nl_oc_interface_brace = ignore # ignore/add/remove/force # (OC) Add or remove newline between '@implementation' and '{'. -nl_oc_implementation_brace = ignore # ignore/add/remove/force/not_defined +nl_oc_implementation_brace = ignore # ignore/add/remove/force # Add or remove newlines at the start of the file. -nl_start_of_file = ignore # ignore/add/remove/force/not_defined +nl_start_of_file = ignore # ignore/add/remove/force # The minimum number of newlines at the start of the file (only used if # nl_start_of_file is 'add' or 'force'). nl_start_of_file_min = 0 # unsigned number # Add or remove newline at the end of the file. -nl_end_of_file = force # ignore/add/remove/force/not_defined +nl_end_of_file = force # ignore/add/remove/force # The minimum number of newlines at the end of the file (only used if # nl_end_of_file is 'add' or 'force'). nl_end_of_file_min = 1 # unsigned number # Add or remove newline between '=' and '{'. -nl_assign_brace = remove # ignore/add/remove/force/not_defined +nl_assign_brace = remove # ignore/add/remove/force # (D) Add or remove newline between '=' and '['. -nl_assign_square = ignore # ignore/add/remove/force/not_defined +nl_assign_square = ignore # ignore/add/remove/force # Add or remove newline between '[]' and '{'. -nl_tsquare_brace = ignore # ignore/add/remove/force/not_defined +nl_tsquare_brace = ignore # ignore/add/remove/force # (D) Add or remove newline after '= ['. Will also affect the newline before # the ']'. -nl_after_square_assign = ignore # ignore/add/remove/force/not_defined +nl_after_square_assign = ignore # ignore/add/remove/force # Add or remove newline between a function call's ')' and '{', as in # 'list_for_each(item, &list) { }'. -nl_fcall_brace = ignore # ignore/add/remove/force/not_defined +nl_fcall_brace = ignore # ignore/add/remove/force # Add or remove newline between 'enum' and '{'. -nl_enum_brace = remove # ignore/add/remove/force/not_defined +nl_enum_brace = remove # ignore/add/remove/force # Add or remove newline between 'enum' and 'class'. -nl_enum_class = ignore # ignore/add/remove/force/not_defined +nl_enum_class = ignore # ignore/add/remove/force # Add or remove newline between 'enum class' and the identifier. -nl_enum_class_identifier = ignore # ignore/add/remove/force/not_defined +nl_enum_class_identifier = ignore # ignore/add/remove/force # Add or remove newline between 'enum class' type and ':'. -nl_enum_identifier_colon = ignore # ignore/add/remove/force/not_defined +nl_enum_identifier_colon = ignore # ignore/add/remove/force # Add or remove newline between 'enum class identifier :' and type. -nl_enum_colon_type = ignore # ignore/add/remove/force/not_defined +nl_enum_colon_type = ignore # ignore/add/remove/force # Add or remove newline between 'struct and '{'. -nl_struct_brace = remove # ignore/add/remove/force/not_defined +nl_struct_brace = remove # ignore/add/remove/force # Add or remove newline between 'union' and '{'. -nl_union_brace = remove # ignore/add/remove/force/not_defined +nl_union_brace = remove # ignore/add/remove/force # Add or remove newline between 'if' and '{'. -nl_if_brace = remove # ignore/add/remove/force/not_defined +nl_if_brace = remove # ignore/add/remove/force # Add or remove newline between '}' and 'else'. -nl_brace_else = remove # ignore/add/remove/force/not_defined +nl_brace_else = remove # ignore/add/remove/force # Add or remove newline between 'else if' and '{'. If set to ignore, # nl_if_brace is used instead. -nl_elseif_brace = ignore # ignore/add/remove/force/not_defined +nl_elseif_brace = ignore # ignore/add/remove/force # Add or remove newline between 'else' and '{'. -nl_else_brace = remove # ignore/add/remove/force/not_defined +nl_else_brace = remove # ignore/add/remove/force # Add or remove newline between 'else' and 'if'. -nl_else_if = remove # ignore/add/remove/force/not_defined +nl_else_if = remove # ignore/add/remove/force # Add or remove newline before '{' opening brace -nl_before_opening_brace_func_class_def = ignore # ignore/add/remove/force/not_defined +nl_before_opening_brace_func_class_def = ignore # ignore/add/remove/force # Add or remove newline before 'if'/'else if' closing parenthesis. -nl_before_if_closing_paren = remove # ignore/add/remove/force/not_defined +nl_before_if_closing_paren = remove # ignore/add/remove/force # Add or remove newline between '}' and 'finally'. -nl_brace_finally = ignore # ignore/add/remove/force/not_defined +nl_brace_finally = ignore # ignore/add/remove/force # Add or remove newline between 'finally' and '{'. -nl_finally_brace = ignore # ignore/add/remove/force/not_defined +nl_finally_brace = ignore # ignore/add/remove/force # Add or remove newline between 'try' and '{'. -nl_try_brace = ignore # ignore/add/remove/force/not_defined +nl_try_brace = ignore # ignore/add/remove/force # Add or remove newline between get/set and '{'. -nl_getset_brace = ignore # ignore/add/remove/force/not_defined +nl_getset_brace = ignore # ignore/add/remove/force # Add or remove newline between 'for' and '{'. -nl_for_brace = remove # ignore/add/remove/force/not_defined +nl_for_brace = remove # ignore/add/remove/force # Add or remove newline before the '{' of a 'catch' statement, as in # 'catch (decl) <here> {'. -nl_catch_brace = ignore # ignore/add/remove/force/not_defined +nl_catch_brace = ignore # ignore/add/remove/force # (OC) Add or remove newline before the '{' of a '@catch' statement, as in # '@catch (decl) <here> {'. If set to ignore, nl_catch_brace is used. -nl_oc_catch_brace = ignore # ignore/add/remove/force/not_defined +nl_oc_catch_brace = ignore # ignore/add/remove/force # Add or remove newline between '}' and 'catch'. -nl_brace_catch = ignore # ignore/add/remove/force/not_defined +nl_brace_catch = ignore # ignore/add/remove/force # (OC) Add or remove newline between '}' and '@catch'. If set to ignore, # nl_brace_catch is used. -nl_oc_brace_catch = ignore # ignore/add/remove/force/not_defined +nl_oc_brace_catch = ignore # ignore/add/remove/force # Add or remove newline between '}' and ']'. -nl_brace_square = ignore # ignore/add/remove/force/not_defined +nl_brace_square = ignore # ignore/add/remove/force # Add or remove newline between '}' and ')' in a function invocation. -nl_brace_fparen = remove # ignore/add/remove/force/not_defined +nl_brace_fparen = remove # ignore/add/remove/force # Add or remove newline between 'while' and '{'. -nl_while_brace = remove # ignore/add/remove/force/not_defined +nl_while_brace = remove # ignore/add/remove/force # (D) Add or remove newline between 'scope (x)' and '{'. -nl_scope_brace = ignore # ignore/add/remove/force/not_defined +nl_scope_brace = ignore # ignore/add/remove/force # (D) Add or remove newline between 'unittest' and '{'. -nl_unittest_brace = ignore # ignore/add/remove/force/not_defined +nl_unittest_brace = ignore # ignore/add/remove/force # (D) Add or remove newline between 'version (x)' and '{'. -nl_version_brace = ignore # ignore/add/remove/force/not_defined +nl_version_brace = ignore # ignore/add/remove/force # (C#) Add or remove newline between 'using' and '{'. -nl_using_brace = ignore # ignore/add/remove/force/not_defined +nl_using_brace = ignore # ignore/add/remove/force # Add or remove newline between two open or close braces. Due to general # newline/brace handling, REMOVE may not work. -nl_brace_brace = ignore # ignore/add/remove/force/not_defined +nl_brace_brace = ignore # ignore/add/remove/force # Add or remove newline between 'do' and '{'. -nl_do_brace = remove # ignore/add/remove/force/not_defined +nl_do_brace = remove # ignore/add/remove/force # Add or remove newline between '}' and 'while' of 'do' statement. -nl_brace_while = remove # ignore/add/remove/force/not_defined +nl_brace_while = remove # ignore/add/remove/force # Add or remove newline between 'switch' and '{'. -nl_switch_brace = remove # ignore/add/remove/force/not_defined +nl_switch_brace = remove # ignore/add/remove/force # Add or remove newline between 'synchronized' and '{'. -nl_synchronized_brace = ignore # ignore/add/remove/force/not_defined +nl_synchronized_brace = ignore # ignore/add/remove/force # Add a newline between ')' and '{' if the ')' is on a different line than the # if/for/etc. @@ -1853,11 +1857,11 @@ nl_multi_line_cond = false # true/false # Add a newline after '(' if an if/for/while/switch condition spans multiple # lines -nl_multi_line_sparen_open = remove # ignore/add/remove/force/not_defined +nl_multi_line_sparen_open = remove # ignore/add/remove/force # Add a newline before ')' if an if/for/while/switch condition spans multiple # lines. Overrides nl_before_if_closing_paren if both are specified. -nl_multi_line_sparen_close = remove # ignore/add/remove/force/not_defined +nl_multi_line_sparen_close = remove # ignore/add/remove/force # Force a newline in a define after the macro name for multi-line defines. nl_multi_line_define = false # true/false @@ -1872,141 +1876,141 @@ nl_after_case = true # true/false # Add or remove newline between a case ':' and '{'. # # Overrides nl_after_case. -nl_case_colon_brace = remove # ignore/add/remove/force/not_defined +nl_case_colon_brace = remove # ignore/add/remove/force # Add or remove newline between ')' and 'throw'. -nl_before_throw = ignore # ignore/add/remove/force/not_defined +nl_before_throw = ignore # ignore/add/remove/force # Add or remove newline between 'namespace' and '{'. -nl_namespace_brace = ignore # ignore/add/remove/force/not_defined +nl_namespace_brace = ignore # ignore/add/remove/force # Add or remove newline after 'template<...>' of a template class. -nl_template_class = ignore # ignore/add/remove/force/not_defined +nl_template_class = ignore # ignore/add/remove/force # Add or remove newline after 'template<...>' of a template class declaration. # # Overrides nl_template_class. -nl_template_class_decl = ignore # ignore/add/remove/force/not_defined +nl_template_class_decl = ignore # ignore/add/remove/force # Add or remove newline after 'template<>' of a specialized class declaration. # # Overrides nl_template_class_decl. -nl_template_class_decl_special = ignore # ignore/add/remove/force/not_defined +nl_template_class_decl_special = ignore # ignore/add/remove/force # Add or remove newline after 'template<...>' of a template class definition. # # Overrides nl_template_class. -nl_template_class_def = ignore # ignore/add/remove/force/not_defined +nl_template_class_def = ignore # ignore/add/remove/force # Add or remove newline after 'template<>' of a specialized class definition. # # Overrides nl_template_class_def. -nl_template_class_def_special = ignore # ignore/add/remove/force/not_defined +nl_template_class_def_special = ignore # ignore/add/remove/force # Add or remove newline after 'template<...>' of a template function. -nl_template_func = ignore # ignore/add/remove/force/not_defined +nl_template_func = ignore # ignore/add/remove/force # Add or remove newline after 'template<...>' of a template function # declaration. # # Overrides nl_template_func. -nl_template_func_decl = ignore # ignore/add/remove/force/not_defined +nl_template_func_decl = ignore # ignore/add/remove/force # Add or remove newline after 'template<>' of a specialized function # declaration. # # Overrides nl_template_func_decl. -nl_template_func_decl_special = ignore # ignore/add/remove/force/not_defined +nl_template_func_decl_special = ignore # ignore/add/remove/force # Add or remove newline after 'template<...>' of a template function # definition. # # Overrides nl_template_func. -nl_template_func_def = ignore # ignore/add/remove/force/not_defined +nl_template_func_def = ignore # ignore/add/remove/force # Add or remove newline after 'template<>' of a specialized function # definition. # # Overrides nl_template_func_def. -nl_template_func_def_special = ignore # ignore/add/remove/force/not_defined +nl_template_func_def_special = ignore # ignore/add/remove/force # Add or remove newline after 'template<...>' of a template variable. -nl_template_var = ignore # ignore/add/remove/force/not_defined +nl_template_var = ignore # ignore/add/remove/force # Add or remove newline between 'template<...>' and 'using' of a templated # type alias. -nl_template_using = ignore # ignore/add/remove/force/not_defined +nl_template_using = ignore # ignore/add/remove/force # Add or remove newline between 'class' and '{'. -nl_class_brace = ignore # ignore/add/remove/force/not_defined +nl_class_brace = ignore # ignore/add/remove/force # Add or remove newline before or after (depending on pos_class_comma, # may not be IGNORE) each',' in the base class list. -nl_class_init_args = ignore # ignore/add/remove/force/not_defined +nl_class_init_args = ignore # ignore/add/remove/force # Add or remove newline after each ',' in the constructor member # initialization. Related to nl_constr_colon, pos_constr_colon and # pos_constr_comma. -nl_constr_init_args = ignore # ignore/add/remove/force/not_defined +nl_constr_init_args = ignore # ignore/add/remove/force # Add or remove newline before first element, after comma, and after last # element, in 'enum'. -nl_enum_own_lines = ignore # ignore/add/remove/force/not_defined +nl_enum_own_lines = ignore # ignore/add/remove/force # Add or remove newline between return type and function name in a function # definition. # might be modified by nl_func_leave_one_liners -nl_func_type_name = remove # ignore/add/remove/force/not_defined +nl_func_type_name = remove # ignore/add/remove/force # Add or remove newline between return type and function name inside a class # definition. If set to ignore, nl_func_type_name or nl_func_proto_type_name # is used instead. -nl_func_type_name_class = ignore # ignore/add/remove/force/not_defined +nl_func_type_name_class = ignore # ignore/add/remove/force # Add or remove newline between class specification and '::' # in 'void A::f() { }'. Only appears in separate member implementation (does # not appear with in-line implementation). -nl_func_class_scope = ignore # ignore/add/remove/force/not_defined +nl_func_class_scope = ignore # ignore/add/remove/force # Add or remove newline between function scope and name, as in # 'void A :: <here> f() { }'. -nl_func_scope_name = ignore # ignore/add/remove/force/not_defined +nl_func_scope_name = ignore # ignore/add/remove/force # Add or remove newline between return type and function name in a prototype. -nl_func_proto_type_name = ignore # ignore/add/remove/force/not_defined +nl_func_proto_type_name = ignore # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' in the # declaration. -nl_func_paren = ignore # ignore/add/remove/force/not_defined +nl_func_paren = ignore # ignore/add/remove/force # Overrides nl_func_paren for functions with no parameters. -nl_func_paren_empty = ignore # ignore/add/remove/force/not_defined +nl_func_paren_empty = ignore # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' in the # definition. -nl_func_def_paren = remove # ignore/add/remove/force/not_defined +nl_func_def_paren = remove # ignore/add/remove/force # Overrides nl_func_def_paren for functions with no parameters. -nl_func_def_paren_empty = ignore # ignore/add/remove/force/not_defined +nl_func_def_paren_empty = ignore # ignore/add/remove/force # Add or remove newline between a function name and the opening '(' in the # call. -nl_func_call_paren = ignore # ignore/add/remove/force/not_defined +nl_func_call_paren = ignore # ignore/add/remove/force # Overrides nl_func_call_paren for functions with no parameters. -nl_func_call_paren_empty = ignore # ignore/add/remove/force/not_defined +nl_func_call_paren_empty = ignore # ignore/add/remove/force # Add or remove newline after '(' in a function declaration. -nl_func_decl_start = remove # ignore/add/remove/force/not_defined +nl_func_decl_start = remove # ignore/add/remove/force # Add or remove newline after '(' in a function definition. -nl_func_def_start = remove # ignore/add/remove/force/not_defined +nl_func_def_start = remove # ignore/add/remove/force # Overrides nl_func_decl_start when there is only one parameter. -nl_func_decl_start_single = ignore # ignore/add/remove/force/not_defined +nl_func_decl_start_single = ignore # ignore/add/remove/force # Overrides nl_func_def_start when there is only one parameter. -nl_func_def_start_single = ignore # ignore/add/remove/force/not_defined +nl_func_def_start_single = ignore # ignore/add/remove/force # Whether to add a newline after '(' in a function declaration if '(' and ')' # are in different lines. If false, nl_func_decl_start is used instead. @@ -2017,13 +2021,13 @@ nl_func_decl_start_multi_line = false # true/false nl_func_def_start_multi_line = false # true/false # Add or remove newline after each ',' in a function declaration. -nl_func_decl_args = remove # ignore/add/remove/force/not_defined +nl_func_decl_args = remove # ignore/add/remove/force # Add or remove newline after each ',' in a function definition. -nl_func_def_args = remove # ignore/add/remove/force/not_defined +nl_func_def_args = remove # ignore/add/remove/force # Add or remove newline after each ',' in a function call. -nl_func_call_args = ignore # ignore/add/remove/force/not_defined +nl_func_call_args = ignore # ignore/add/remove/force # Whether to add a newline after each ',' in a function declaration if '(' # and ')' are in different lines. If false, nl_func_decl_args is used instead. @@ -2034,16 +2038,16 @@ nl_func_decl_args_multi_line = false # true/false nl_func_def_args_multi_line = false # true/false # Add or remove newline before the ')' in a function declaration. -nl_func_decl_end = remove # ignore/add/remove/force/not_defined +nl_func_decl_end = remove # ignore/add/remove/force # Add or remove newline before the ')' in a function definition. -nl_func_def_end = remove # ignore/add/remove/force/not_defined +nl_func_def_end = remove # ignore/add/remove/force # Overrides nl_func_decl_end when there is only one parameter. -nl_func_decl_end_single = ignore # ignore/add/remove/force/not_defined +nl_func_decl_end_single = ignore # ignore/add/remove/force # Overrides nl_func_def_end when there is only one parameter. -nl_func_def_end_single = ignore # ignore/add/remove/force/not_defined +nl_func_def_end_single = ignore # ignore/add/remove/force # Whether to add a newline before ')' in a function declaration if '(' and ')' # are in different lines. If false, nl_func_decl_end is used instead. @@ -2054,20 +2058,20 @@ nl_func_decl_end_multi_line = false # true/false nl_func_def_end_multi_line = false # true/false # Add or remove newline between '()' in a function declaration. -nl_func_decl_empty = ignore # ignore/add/remove/force/not_defined +nl_func_decl_empty = ignore # ignore/add/remove/force # Add or remove newline between '()' in a function definition. -nl_func_def_empty = ignore # ignore/add/remove/force/not_defined +nl_func_def_empty = ignore # ignore/add/remove/force # Add or remove newline between '()' in a function call. -nl_func_call_empty = ignore # ignore/add/remove/force/not_defined +nl_func_call_empty = ignore # ignore/add/remove/force # Whether to add a newline after '(' in a function call, # has preference over nl_func_call_start_multi_line. -nl_func_call_start = remove # ignore/add/remove/force/not_defined +nl_func_call_start = remove # ignore/add/remove/force # Whether to add a newline before ')' in a function call. -nl_func_call_end = remove # ignore/add/remove/force/not_defined +nl_func_call_end = remove # ignore/add/remove/force # Whether to add a newline after '(' in a function call if '(' and ')' are in # different lines. @@ -2103,41 +2107,45 @@ nl_oc_msg_args_min_params = 0 # unsigned number # (OC) Max code width of Objective-C message before applying nl_oc_msg_args. nl_oc_msg_args_max_code_width = 0 # unsigned number +# (OC) Whether to apply nl_oc_msg_args if some of the parameters are already +# on new lines. Overrides nl_oc_msg_args_min_params and nl_oc_msg_args_max_code_width. +nl_oc_msg_args_finish_multi_line = false # true/false + # Add or remove newline between function signature and '{'. -nl_fdef_brace = force # ignore/add/remove/force/not_defined +nl_fdef_brace = force # ignore/add/remove/force # Add or remove newline between function signature and '{', # if signature ends with ')'. Overrides nl_fdef_brace. -nl_fdef_brace_cond = ignore # ignore/add/remove/force/not_defined +nl_fdef_brace_cond = ignore # ignore/add/remove/force # Add or remove newline between C++11 lambda signature and '{'. -nl_cpp_ldef_brace = ignore # ignore/add/remove/force/not_defined +nl_cpp_ldef_brace = ignore # ignore/add/remove/force # Add or remove newline between 'return' and the return expression. -nl_return_expr = remove # ignore/add/remove/force/not_defined +nl_return_expr = remove # ignore/add/remove/force # Add or remove newline between 'throw' and the throw expression. -nl_throw_expr = ignore # ignore/add/remove/force/not_defined +nl_throw_expr = ignore # ignore/add/remove/force # Whether to add a newline after semicolons, except in 'for' statements. nl_after_semicolon = false # true/false # (Java) Add or remove newline between the ')' and '{{' of the double brace # initializer. -nl_paren_dbrace_open = ignore # ignore/add/remove/force/not_defined +nl_paren_dbrace_open = ignore # ignore/add/remove/force # Whether to add a newline after the type in an unnamed temporary # direct-list-initialization, better: # before a direct-list-initialization. -nl_type_brace_init_lst = ignore # ignore/add/remove/force/not_defined +nl_type_brace_init_lst = ignore # ignore/add/remove/force # Whether to add a newline after the open brace in an unnamed temporary # direct-list-initialization. -nl_type_brace_init_lst_open = ignore # ignore/add/remove/force/not_defined +nl_type_brace_init_lst_open = ignore # ignore/add/remove/force # Whether to add a newline before the close brace in an unnamed temporary # direct-list-initialization. -nl_type_brace_init_lst_close = ignore # ignore/add/remove/force/not_defined +nl_type_brace_init_lst_close = ignore # ignore/add/remove/force # Whether to add a newline before '{'. nl_before_brace_open = false # true/false @@ -2168,7 +2176,7 @@ nl_after_vbrace_close = false # true/false # Add or remove newline between the close brace and identifier, # as in 'struct { int a; } <here> b;'. Affects enumerations, unions and # structures. If set to ignore, uses nl_after_brace_close. -nl_brace_struct_var = ignore # ignore/add/remove/force/not_defined +nl_brace_struct_var = ignore # ignore/add/remove/force # Whether to alter newlines in '#define' macros. nl_define_macro = false # true/false @@ -2186,41 +2194,41 @@ nl_squeeze_ifdef = false # true/false nl_squeeze_ifdef_top_level = false # true/false # Add or remove blank line before 'if'. -nl_before_if = ignore # ignore/add/remove/force/not_defined +nl_before_if = ignore # ignore/add/remove/force # Add or remove blank line after 'if' statement. Add/Force work only if the # next token is not a closing brace. -nl_after_if = ignore # ignore/add/remove/force/not_defined +nl_after_if = ignore # ignore/add/remove/force # Add or remove blank line before 'for'. -nl_before_for = ignore # ignore/add/remove/force/not_defined +nl_before_for = ignore # ignore/add/remove/force # Add or remove blank line after 'for' statement. -nl_after_for = ignore # ignore/add/remove/force/not_defined +nl_after_for = ignore # ignore/add/remove/force # Add or remove blank line before 'while'. -nl_before_while = ignore # ignore/add/remove/force/not_defined +nl_before_while = ignore # ignore/add/remove/force # Add or remove blank line after 'while' statement. -nl_after_while = ignore # ignore/add/remove/force/not_defined +nl_after_while = ignore # ignore/add/remove/force # Add or remove blank line before 'switch'. -nl_before_switch = ignore # ignore/add/remove/force/not_defined +nl_before_switch = ignore # ignore/add/remove/force # Add or remove blank line after 'switch' statement. -nl_after_switch = ignore # ignore/add/remove/force/not_defined +nl_after_switch = ignore # ignore/add/remove/force # Add or remove blank line before 'synchronized'. -nl_before_synchronized = ignore # ignore/add/remove/force/not_defined +nl_before_synchronized = ignore # ignore/add/remove/force # Add or remove blank line after 'synchronized' statement. -nl_after_synchronized = ignore # ignore/add/remove/force/not_defined +nl_after_synchronized = ignore # ignore/add/remove/force # Add or remove blank line before 'do'. -nl_before_do = ignore # ignore/add/remove/force/not_defined +nl_before_do = ignore # ignore/add/remove/force # Add or remove blank line after 'do/while' statement. -nl_after_do = ignore # ignore/add/remove/force/not_defined +nl_after_do = ignore # ignore/add/remove/force # Ignore nl_before_{if,for,switch,do,synchronized} if the control # statement is immediately after a case statement. @@ -2237,10 +2245,10 @@ nl_before_return = false # true/false nl_after_return = false # true/false # Whether to put a blank line before a member '.' or '->' operators. -nl_before_member = ignore # ignore/add/remove/force/not_defined +nl_before_member = ignore # ignore/add/remove/force # (Java) Whether to put a blank line after a member '.' or '->' operators. -nl_after_member = ignore # ignore/add/remove/force/not_defined +nl_after_member = ignore # ignore/add/remove/force # Whether to double-space commented-entries in 'struct'/'union'/'enum'. nl_ds_struct_enum_cmt = false # true/false @@ -2251,11 +2259,11 @@ nl_ds_struct_enum_close_brace = false # true/false # Add or remove newline before or after (depending on pos_class_colon) a class # colon, as in 'class Foo <here> : <or here> public Bar'. -nl_class_colon = ignore # ignore/add/remove/force/not_defined +nl_class_colon = ignore # ignore/add/remove/force # Add or remove newline around a class constructor colon. The exact position # depends on nl_constr_init_args, pos_constr_colon and pos_constr_comma. -nl_constr_colon = ignore # ignore/add/remove/force/not_defined +nl_constr_colon = ignore # ignore/add/remove/force # Whether to collapse a two-line namespace, like 'namespace foo\n{ decl; }' # into a single line. If true, prevents other brace newline rules from turning @@ -2509,7 +2517,7 @@ nl_around_cs_property = 0 # unsigned number nl_between_get_set = 0 # unsigned number # (C#) Add or remove newline between property and the '{'. -nl_property_brace = ignore # ignore/add/remove/force/not_defined +nl_property_brace = ignore # ignore/add/remove/force # Whether to remove blank lines after '{'. eat_blanks_after_open_brace = true # true/false @@ -2526,10 +2534,10 @@ nl_remove_extra_newlines = 0 # unsigned number # (Java) Add or remove newline after an annotation statement. Only affects # annotations that are after a newline. -nl_after_annotation = ignore # ignore/add/remove/force/not_defined +nl_after_annotation = ignore # ignore/add/remove/force # (Java) Add or remove newline between two annotations. -nl_between_annotation = ignore # ignore/add/remove/force/not_defined +nl_between_annotation = ignore # ignore/add/remove/force # The number of newlines before a whole-file #ifdef. # @@ -3168,17 +3176,17 @@ cmt_insert_before_ctor_dtor = false # true/false # # Add or remove braces on a single-line 'do' statement. -mod_full_brace_do = add # ignore/add/remove/force/not_defined +mod_full_brace_do = add # ignore/add/remove/force # Add or remove braces on a single-line 'for' statement. -mod_full_brace_for = add # ignore/add/remove/force/not_defined +mod_full_brace_for = add # ignore/add/remove/force # (Pawn) Add or remove braces on a single-line function definition. -mod_full_brace_function = ignore # ignore/add/remove/force/not_defined +mod_full_brace_function = ignore # ignore/add/remove/force # Add or remove braces on a single-line 'if' statement. Braces will not be # removed if the braced statement contains an 'else'. -mod_full_brace_if = add # ignore/add/remove/force/not_defined +mod_full_brace_if = add # ignore/add/remove/force # Whether to enforce that all blocks of an 'if'/'else if'/'else' chain either # have, or do not have, braces. Overrides mod_full_brace_if. @@ -3199,10 +3207,10 @@ mod_full_brace_if_chain = 0 # unsigned number mod_full_brace_if_chain_only = false # true/false # Add or remove braces on single-line 'while' statement. -mod_full_brace_while = add # ignore/add/remove/force/not_defined +mod_full_brace_while = add # ignore/add/remove/force # Add or remove braces on single-line 'using ()' statement. -mod_full_brace_using = ignore # ignore/add/remove/force/not_defined +mod_full_brace_using = ignore # ignore/add/remove/force # Don't remove braces around statements that span N newlines mod_full_brace_nl = 0 # unsigned number @@ -3224,10 +3232,10 @@ mod_full_brace_nl = 0 # unsigned number mod_full_brace_nl_block_rem_mlcond = false # true/false # Add or remove unnecessary parentheses on 'return' statement. -mod_paren_on_return = ignore # ignore/add/remove/force/not_defined +mod_paren_on_return = ignore # ignore/add/remove/force # Add or remove unnecessary parentheses on 'throw' statement. -mod_paren_on_throw = ignore # ignore/add/remove/force/not_defined +mod_paren_on_throw = ignore # ignore/add/remove/force # (Pawn) Whether to change optional semicolons to real semicolons. mod_pawn_semicolon = false # true/false @@ -3323,14 +3331,14 @@ mod_move_case_return = false # true/false # Add or remove braces around a fully braced case statement. Will only remove # braces if there are no variable declarations in the block. -mod_case_brace = ignore # ignore/add/remove/force/not_defined +mod_case_brace = ignore # ignore/add/remove/force # Whether to remove a void 'return;' that appears as the last statement in a # function. mod_remove_empty_return = false # true/false # Add or remove the comma after the last value of an enumeration. -mod_enum_last_comma = add # ignore/add/remove/force/not_defined +mod_enum_last_comma = add # ignore/add/remove/force # Syntax to use for infinite loops. # @@ -3347,28 +3355,28 @@ mod_enum_last_comma = add # ignore/add/remove/force/not_defined mod_infinite_loop = 2 # unsigned number # Add or remove the 'int' keyword in 'int short'. -mod_int_short = remove # ignore/add/remove/force/not_defined +mod_int_short = remove # ignore/add/remove/force # Add or remove the 'int' keyword in 'short int'. -mod_short_int = remove # ignore/add/remove/force/not_defined +mod_short_int = remove # ignore/add/remove/force # Add or remove the 'int' keyword in 'int long'. -mod_int_long = remove # ignore/add/remove/force/not_defined +mod_int_long = remove # ignore/add/remove/force # Add or remove the 'int' keyword in 'long int'. -mod_long_int = remove # ignore/add/remove/force/not_defined +mod_long_int = remove # ignore/add/remove/force # Add or remove the 'int' keyword in 'int signed'. -mod_int_signed = remove # ignore/add/remove/force/not_defined +mod_int_signed = remove # ignore/add/remove/force # Add or remove the 'int' keyword in 'signed int'. -mod_signed_int = remove # ignore/add/remove/force/not_defined +mod_signed_int = remove # ignore/add/remove/force # Add or remove the 'int' keyword in 'int unsigned'. -mod_int_unsigned = remove # ignore/add/remove/force/not_defined +mod_int_unsigned = remove # ignore/add/remove/force # Add or remove the 'int' keyword in 'unsigned int'. -mod_unsigned_int = remove # ignore/add/remove/force/not_defined +mod_unsigned_int = remove # ignore/add/remove/force # If there is a situation where mod_int_* and mod_*_int would result in # multiple int keywords, whether to keep the rightmost int (the default) or the @@ -3418,7 +3426,7 @@ pp_indent_with_tabs = -1 # number # Add or remove indentation of preprocessor directives inside #if blocks # at brace level 0 (file-level). -pp_indent = remove # ignore/add/remove/force/not_defined +pp_indent = remove # ignore/add/remove/force # Whether to indent #if/#else/#endif at the brace level. If false, these are # indented from column 1. @@ -3437,7 +3445,7 @@ pp_indent_at_level0 = false # true/false pp_indent_count = 1 # unsigned number # Add or remove space after # based on pp level of #if blocks. -pp_space_after = force # ignore/add/remove/force/not_defined +pp_space_after = force # ignore/add/remove/force # Sets the number of spaces per level added with pp_space_after. pp_space_count = 1 # unsigned number @@ -3515,8 +3523,12 @@ pp_indent_extern = true # true/false # Default: 1 pp_indent_brace = 1 # number -# Whether to print warning messages for unbalanced #if and #else blocks. -# This will print a message in the following cases: +# Action to perform when unbalanced #if and #else blocks are found. +# 0: do nothing +# 1: print a warning message +# 2: terminate the program with an error (EX_SOFTWARE) +# +# The action will be triggered in the following cases: # - if an #ifdef block ends on a different indent level than # where it started from. Example: # @@ -3535,7 +3547,7 @@ pp_indent_brace = 1 # number # } # int j; # #endif -pp_warn_unbalanced_if = false # true/false +pp_unbalanced_if_action = 0 # unsigned number # # Sort includes options @@ -3649,6 +3661,9 @@ debug_decode_the_flags = false # true/false # Default: true debug_use_the_exit_function_pop = true # true/false +# print (or not) the version in the file defined at the command option -o. +debug_print_version = false # true/false + # insert the number of the line at the beginning of each line set_numbering_for_html_output = false # true/false @@ -3732,5 +3747,5 @@ set CLASS_COLON REAL_FATTR_CONST set CLASS_COLON REAL_FATTR_NONNULL_ALL set CLASS_COLON REAL_FATTR_PURE set CLASS_COLON REAL_FATTR_WARN_UNUSED_RESULT -# option(s) with 'not default' value: 135 +# option(s) with 'not default' value: 136 # |