diff options
Diffstat (limited to 'src')
80 files changed, 4282 insertions, 3377 deletions
diff --git a/src/cjson/lua_cjson.c b/src/cjson/lua_cjson.c index 92d07963bd..cf9e82c38e 100644 --- a/src/cjson/lua_cjson.c +++ b/src/cjson/lua_cjson.c @@ -171,10 +171,18 @@ typedef struct { } json_config_t; typedef struct { + /* convert null in json objects to lua nil instead of vim.NIL */ + int luanil_object; + /* convert null in json arrays to lua nil instead of vim.NIL */ + int luanil_array; +} json_options_t; + +typedef struct { const char *data; const char *ptr; strbuf_t *tmp; /* Temporary storage for strings */ json_config_t *cfg; + json_options_t *options; int current_depth; } json_parse_t; @@ -865,7 +873,7 @@ static int json_encode(lua_State *l) /* ===== DECODING ===== */ static void json_process_value(lua_State *l, json_parse_t *json, - json_token_t *token); + json_token_t *token, bool use_luanil); static int hexdigit2int(char hex) { @@ -1296,7 +1304,7 @@ static void json_parse_object_context(lua_State *l, json_parse_t *json) /* Fetch value */ json_next_token(json, &token); - json_process_value(l, json, &token); + json_process_value(l, json, &token, json->options->luanil_object); /* Set key = value */ lua_rawset(l, -3); @@ -1343,7 +1351,7 @@ static void json_parse_array_context(lua_State *l, json_parse_t *json) } for (i = 1; ; i++) { - json_process_value(l, json, &token); + json_process_value(l, json, &token, json->options->luanil_array); lua_rawseti(l, -2, i); /* arr[i] = value */ json_next_token(json, &token); @@ -1362,7 +1370,7 @@ static void json_parse_array_context(lua_State *l, json_parse_t *json) /* Handle the "value" context */ static void json_process_value(lua_State *l, json_parse_t *json, - json_token_t *token) + json_token_t *token, bool use_luanil) { switch (token->type) { case T_STRING: @@ -1381,7 +1389,11 @@ static void json_process_value(lua_State *l, json_parse_t *json, json_parse_array_context(l, json); break;; case T_NULL: - nlua_pushref(l, nlua_nil_ref); + if (use_luanil) { + lua_pushnil(l); + } else { + nlua_pushref(l, nlua_nil_ref); + } break;; default: json_throw_parse_error(l, json, "value", token); @@ -1392,12 +1404,46 @@ static int json_decode(lua_State *l) { json_parse_t json; json_token_t token; + json_options_t options = { .luanil_object = false, .luanil_array = false }; + + size_t json_len; - luaL_argcheck(l, lua_gettop(l) == 1, 1, "expected 1 argument"); + switch (lua_gettop(l)) { + case 1: + break; + case 2: + luaL_checktype(l, 2, LUA_TTABLE); + lua_getfield(l, 2, "luanil"); + + /* We only handle the luanil option for now */ + if (lua_isnil(l, -1)) { + lua_pop(l, 1); + break; + } + + luaL_checktype(l, -1, LUA_TTABLE); + + lua_getfield(l, -1, "object"); + if (!lua_isnil(l, -1)) { + options.luanil_object = true; + } + lua_pop(l, 1); + + lua_getfield(l, -1, "array"); + if (!lua_isnil(l, -1)) { + options.luanil_array = true; + } + /* Also pop the luanil table */ + lua_pop(l, 2); + break; + default: + return luaL_error (l, "expected 1 or 2 arguments"); + } json.cfg = json_fetch_config(l); json.data = luaL_checklstring(l, 1, &json_len); + json.options = &options; json.current_depth = 0; json.ptr = json.data; @@ -1415,7 +1461,7 @@ static int json_decode(lua_State *l) json.tmp = strbuf_new(json_len); json_next_token(&json, &token); - json_process_value(l, &json, &token); + json_process_value(l, &json, &token, json.options->luanil_object); /* Ensure there is no more input left */ json_next_token(&json, &token); diff --git a/src/clint.py b/src/clint.py index e7d76366b0..4b7bf002e6 100755 --- a/src/clint.py +++ b/src/clint.py @@ -2544,6 +2544,7 @@ def CheckSpacing(filename, clean_lines, linenum, nesting_state, error): r'(?<!\bPMap)' r'(?<!\bArrayOf)' r'(?<!\bDictionaryOf)' + r'(?<!\bDict)' r'\((?:const )?(?:struct )?[a-zA-Z_]\w*(?: *\*(?:const)?)*\)' r' +' r'-?(?:\*+|&)?(?:\w+|\+\+|--|\()', cast_line) diff --git a/src/mpack/conv.c b/src/mpack/conv.c index 31297a8784..6bd446ca49 100644 --- a/src/mpack/conv.c +++ b/src/mpack/conv.c @@ -301,7 +301,6 @@ MPACK_API double mpack_unpack_number(mpack_token_t t) */ if (!hi) { assert(t.length <= 4); - hi = 0; lo = (~lo & (((mpack_uint32_t)1 << ((t.length * 8) - 1)) - 1)); } else { hi = ~hi; diff --git a/src/mpack/lmpack.c b/src/mpack/lmpack.c index 4b0e132a3a..2d6131d7cb 100644 --- a/src/mpack/lmpack.c +++ b/src/mpack/lmpack.c @@ -445,7 +445,6 @@ static int lmpack_unpacker_unpack_str(lua_State *L, Unpacker *unpacker, if (rv == MPACK_NOMEM) { unpacker->parser = lmpack_grow_parser(unpacker->parser); if (!unpacker->parser) { - unpacker->unpacking = 0; return luaL_error(L, "failed to grow Unpacker capacity"); } } @@ -799,7 +798,6 @@ static int lmpack_packer_pack(lua_State *L) if (result == MPACK_NOMEM) { packer->parser = lmpack_grow_parser(packer->parser); if (!packer->parser) { - packer->packing = 0; return luaL_error(L, "Failed to grow Packer capacity"); } } diff --git a/src/nvim/CMakeLists.txt b/src/nvim/CMakeLists.txt index e35e7ce2d4..9c6eafa2df 100644 --- a/src/nvim/CMakeLists.txt +++ b/src/nvim/CMakeLists.txt @@ -27,6 +27,7 @@ set(BINARY_LIB_DIR ${PROJECT_BINARY_DIR}/lib/nvim/) set(API_DISPATCH_GENERATOR ${GENERATOR_DIR}/gen_api_dispatch.lua) set(API_UI_EVENTS_GENERATOR ${GENERATOR_DIR}/gen_api_ui_events.lua) set(GENERATOR_C_GRAMMAR ${GENERATOR_DIR}/c_grammar.lua) +set(GENERATOR_HASHY ${GENERATOR_DIR}/hashy.lua) set(API_METADATA ${PROJECT_BINARY_DIR}/api_metadata.mpack) set(FUNCS_DATA ${PROJECT_BINARY_DIR}/funcs_data.mpack) set(LUA_API_C_BINDINGS ${GENERATED_DIR}/lua_api_c_bindings.generated.c) @@ -42,12 +43,15 @@ set(GENERATED_UI_EVENTS_METADATA ${GENERATED_DIR}/api/private/ui_events_metadata set(GENERATED_EX_CMDS_ENUM ${GENERATED_INCLUDES_DIR}/ex_cmds_enum.generated.h) set(GENERATED_EX_CMDS_DEFS ${GENERATED_DIR}/ex_cmds_defs.generated.h) set(GENERATED_FUNCS ${GENERATED_DIR}/funcs.generated.h) +set(GENERATED_KEYSETS ${GENERATED_DIR}/keysets.generated.h) +set(GENERATED_KEYSETS_DEFS ${GENERATED_DIR}/keysets_defs.generated.h) set(GENERATED_EVENTS_ENUM ${GENERATED_INCLUDES_DIR}/auevents_enum.generated.h) set(GENERATED_EVENTS_NAMES_MAP ${GENERATED_DIR}/auevents_name_map.generated.h) set(GENERATED_OPTIONS ${GENERATED_DIR}/options.generated.h) set(EX_CMDS_GENERATOR ${GENERATOR_DIR}/gen_ex_cmds.lua) set(FUNCS_GENERATOR ${GENERATOR_DIR}/gen_eval.lua) set(EVENTS_GENERATOR ${GENERATOR_DIR}/gen_events.lua) +set(KEYSETS_GENERATOR ${GENERATOR_DIR}/gen_keysets.lua) set(OPTIONS_GENERATOR ${GENERATOR_DIR}/gen_options.lua) set(UNICODE_TABLES_GENERATOR ${GENERATOR_DIR}/gen_unicode_tables.lua) set(UNICODE_DIR ${PROJECT_SOURCE_DIR}/unicode) @@ -261,6 +265,7 @@ foreach(sfile ${NVIM_SOURCES} "${GENERATED_UI_EVENTS_CALL}" "${GENERATED_UI_EVENTS_REMOTE}" "${GENERATED_UI_EVENTS_BRIDGE}" + "${GENERATED_KEYSETS}" ) get_filename_component(full_d ${sfile} PATH) file(RELATIVE_PATH d "${CMAKE_CURRENT_LIST_DIR}" "${full_d}") @@ -364,12 +369,14 @@ add_custom_command( list(APPEND NVIM_GENERATED_FOR_HEADERS "${GENERATED_EX_CMDS_ENUM}" "${GENERATED_EVENTS_ENUM}" + "${GENERATED_KEYSETS_DEFS}" ) list(APPEND NVIM_GENERATED_FOR_SOURCES "${GENERATED_API_DISPATCH}" "${GENERATED_EX_CMDS_DEFS}" "${GENERATED_EVENTS_NAMES_MAP}" + "${GENERATED_KEYSETS}" "${GENERATED_OPTIONS}" "${GENERATED_UNICODE_TABLES}" "${VIM_MODULE_FILE}" @@ -404,6 +411,12 @@ add_custom_command(OUTPUT ${GENERATED_EVENTS_ENUM} ${GENERATED_EVENTS_NAMES_MAP} DEPENDS ${EVENTS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/auevents.lua ) +add_custom_command(OUTPUT ${GENERATED_KEYSETS} ${GENERATED_KEYSETS_DEFS} + COMMAND ${LUA_PRG} ${KEYSETS_GENERATOR} + ${CMAKE_CURRENT_LIST_DIR} ${LUA_SHARED_MODULE_SOURCE} ${GENERATED_KEYSETS} ${GENERATED_KEYSETS_DEFS} + DEPENDS ${KEYSETS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR}/api/keysets.lua ${GENERATOR_HASHY} +) + add_custom_command(OUTPUT ${GENERATED_OPTIONS} COMMAND ${LUA_PRG} ${OPTIONS_GENERATOR} ${CMAKE_CURRENT_LIST_DIR} ${GENERATED_OPTIONS} diff --git a/src/nvim/api/buffer.c b/src/nvim/api/buffer.c index 0ef2776263..3ab7e6b778 100644 --- a/src/nvim/api/buffer.c +++ b/src/nvim/api/buffer.c @@ -858,7 +858,7 @@ ArrayOf(Dictionary) nvim_buf_get_keymap(Buffer buffer, String mode, Error *err) /// @see |nvim_set_keymap()| /// /// @param buffer Buffer handle, or 0 for current buffer -void nvim_buf_set_keymap(Buffer buffer, String mode, String lhs, String rhs, Dictionary opts, +void nvim_buf_set_keymap(Buffer buffer, String mode, String lhs, String rhs, Dict(keymap) *opts, Error *err) FUNC_API_SINCE(6) { @@ -874,8 +874,7 @@ void nvim_buf_del_keymap(Buffer buffer, String mode, String lhs, Error *err) FUNC_API_SINCE(6) { String rhs = { .data = "", .size = 0 }; - Dictionary opts = ARRAY_DICT_INIT; - modify_keymap(buffer, true, mode, lhs, rhs, opts, err); + modify_keymap(buffer, true, mode, lhs, rhs, NULL, err); } /// Gets a map of buffer-local |user-commands|. @@ -885,22 +884,13 @@ void nvim_buf_del_keymap(Buffer buffer, String mode, String lhs, Error *err) /// @param[out] err Error details, if any. /// /// @returns Map of maps describing commands. -Dictionary nvim_buf_get_commands(Buffer buffer, Dictionary opts, Error *err) +Dictionary nvim_buf_get_commands(Buffer buffer, Dict(get_commands) *opts, Error *err) FUNC_API_SINCE(4) { bool global = (buffer == -1); - bool builtin = false; - - for (size_t i = 0; i < opts.size; i++) { - String k = opts.items[i].key; - Object v = opts.items[i].value; - if (!strequal("builtin", k.data)) { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); - return (Dictionary)ARRAY_DICT_INIT; - } - if (strequal("builtin", k.data)) { - builtin = v.data.boolean; - } + bool builtin = api_object_to_bool(opts->builtin, "builtin", false, err); + if (ERROR_SET(err)) { + return (Dictionary)ARRAY_DICT_INIT; } if (global) { @@ -1118,14 +1108,97 @@ Boolean nvim_buf_is_valid(Buffer buffer) return ret; } -/// Return a tuple (row,col) representing the position of the named mark. +/// Deletes a named mark in the buffer. See |mark-motions|. +/// +/// @note only deletes marks set in the buffer, if the mark is not set +/// in the buffer it will return false. +/// @param buffer Buffer to set the mark on +/// @param name Mark name +/// @return true if the mark was deleted, else false. +/// @see |nvim_buf_set_mark()| +/// @see |nvim_del_mark()| +Boolean nvim_buf_del_mark(Buffer buffer, String name, Error *err) + FUNC_API_SINCE(8) +{ + bool res = false; + buf_T *buf = find_buffer_by_handle(buffer, err); + + if (!buf) { + return res; + } + + if (name.size != 1) { + api_set_error(err, kErrorTypeValidation, + "Mark name must be a single character"); + return res; + } + + pos_T *pos = getmark_buf(buf, *name.data, false); + + // pos point to NULL when there's no mark with name + if (pos == NULL) { + api_set_error(err, kErrorTypeValidation, "Invalid mark name: '%c'", + *name.data); + return res; + } + + // pos->lnum is 0 when the mark is not valid in the buffer, or is not set. + if (pos->lnum != 0) { + // since the mark belongs to the buffer delete it. + res = set_mark(buf, name, 0, 0, err); + } + + return res; +} + +/// Sets a named mark in the given buffer, all marks are allowed +/// file/uppercase, visual, last change, etc. See |mark-motions|. +/// +/// Marks are (1,0)-indexed. |api-indexing| +/// +/// @note Passing 0 as line deletes the mark +/// +/// @param buffer Buffer to set the mark on +/// @param name Mark name +/// @param line Line number +/// @param col Column/row number +/// @return true if the mark was set, else false. +/// @see |nvim_buf_del_mark()| +/// @see |nvim_buf_get_mark()| +Boolean nvim_buf_set_mark(Buffer buffer, String name, + Integer line, Integer col, Error *err) + FUNC_API_SINCE(8) +{ + bool res = false; + buf_T *buf = find_buffer_by_handle(buffer, err); + + if (!buf) { + return res; + } + + if (name.size != 1) { + api_set_error(err, kErrorTypeValidation, + "Mark name must be a single character"); + return res; + } + + res = set_mark(buf, name, line, col, err); + + return res; +} + +/// Returns a tuple (row,col) representing the position of the named mark. See +/// |mark-motions|. /// /// Marks are (1,0)-indexed. |api-indexing| /// /// @param buffer Buffer handle, or 0 for current buffer /// @param name Mark name /// @param[out] err Error details, if any -/// @return (row, col) tuple +/// @return (row, col) tuple, (0, 0) if the mark is not set, or is an +/// uppercase/file mark set in another buffer. +/// @see |nvim_buf_set_mark()| +/// @see |nvim_buf_del_mark()| ArrayOf(Integer, 2) nvim_buf_get_mark(Buffer buffer, String name, Error *err) FUNC_API_SINCE(1) { @@ -1485,7 +1558,7 @@ Array nvim_buf_get_extmarks(Buffer buffer, Integer ns_id, Object start, Object e /// @param[out] err Error details, if any /// @return Id of the created/updated extmark Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer col, - Dictionary opts, Error *err) + Dict(set_extmark) *opts, Error *err) FUNC_API_SINCE(7) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -1498,211 +1571,174 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer return 0; } - bool ephemeral = false; uint64_t id = 0; + if (opts->id.type == kObjectTypeInteger && opts->id.data.integer > 0) { + id = (uint64_t)opts->id.data.integer; + } else if (HAS_KEY(opts->id)) { + api_set_error(err, kErrorTypeValidation, "id is not a positive integer"); + goto error; + } + int line2 = -1; - Decoration decor = DECORATION_INIT; + if (opts->end_line.type == kObjectTypeInteger) { + Integer val = opts->end_line.data.integer; + if (val < 0 || val > buf->b_ml.ml_line_count) { + api_set_error(err, kErrorTypeValidation, "end_line value outside range"); + goto error; + } else { + line2 = (int)val; + } + } else if (HAS_KEY(opts->end_line)) { + api_set_error(err, kErrorTypeValidation, "end_line is not an integer"); + goto error; + } + colnr_T col2 = -1; + if (opts->end_col.type == kObjectTypeInteger) { + Integer val = opts->end_col.data.integer; + if (val < 0 || val > MAXCOL) { + api_set_error(err, kErrorTypeValidation, "end_col value outside range"); + goto error; + } else { + col2 = (int)val; + } + } else if (HAS_KEY(opts->end_col)) { + api_set_error(err, kErrorTypeValidation, "end_col is not an integer"); + goto error; + } - bool right_gravity = true; - bool end_right_gravity = false; - bool end_gravity_set = false; + Decoration decor = DECORATION_INIT; - VirtLines virt_lines = KV_INITIAL_VALUE; - bool virt_lines_above = false; - bool virt_lines_leftcol = false; + if (HAS_KEY(opts->hl_group)) { + decor.hl_id = object_to_hl_id(opts->hl_group, "hl_group", err); + if (ERROR_SET(err)) { + goto error; + } + } - for (size_t i = 0; i < opts.size; i++) { - String k = opts.items[i].key; - Object *v = &opts.items[i].value; - if (strequal("id", k.data)) { - if (v->type != kObjectTypeInteger || v->data.integer <= 0) { - api_set_error(err, kErrorTypeValidation, - "id is not a positive integer"); - goto error; - } + if (opts->virt_text.type == kObjectTypeArray) { + decor.virt_text = parse_virt_text(opts->virt_text.data.array, err, + &decor.virt_text_width); + if (ERROR_SET(err)) { + goto error; + } + } else if (HAS_KEY(opts->virt_text)) { + api_set_error(err, kErrorTypeValidation, "virt_text is not an Array"); + goto error; + } + + if (opts->virt_text_pos.type == kObjectTypeString) { + String str = opts->virt_text_pos.data.string; + if (strequal("eol", str.data)) { + decor.virt_text_pos = kVTEndOfLine; + } else if (strequal("overlay", str.data)) { + decor.virt_text_pos = kVTOverlay; + } else if (strequal("right_align", str.data)) { + decor.virt_text_pos = kVTRightAlign; + } else { + api_set_error(err, kErrorTypeValidation, "virt_text_pos: invalid value"); + goto error; + } + } else if (HAS_KEY(opts->virt_text_pos)) { + api_set_error(err, kErrorTypeValidation, "virt_text_pos is not a String"); + goto error; + } - id = (uint64_t)v->data.integer; - } else if (strequal("end_line", k.data)) { - if (v->type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, - "end_line is not an integer"); - goto error; - } - if (v->data.integer < 0 || v->data.integer > buf->b_ml.ml_line_count) { - api_set_error(err, kErrorTypeValidation, - "end_line value outside range"); - goto error; - } + if (opts->virt_text_win_col.type == kObjectTypeInteger) { + decor.col = (int)opts->virt_text_win_col.data.integer; + decor.virt_text_pos = kVTWinCol; + } else if (HAS_KEY(opts->virt_text_win_col)) { + api_set_error(err, kErrorTypeValidation, + "virt_text_win_col is not a Number of the correct size"); + goto error; + } - line2 = (int)v->data.integer; - } else if (strequal("end_col", k.data)) { - if (v->type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, - "end_col is not an integer"); - goto error; - } - if (v->data.integer < 0 || v->data.integer > MAXCOL) { - api_set_error(err, kErrorTypeValidation, - "end_col value outside range"); - goto error; - } +#define OPTION_TO_BOOL(target, name, val) \ + target = api_object_to_bool(opts-> name, #name, val, err); \ + if (ERROR_SET(err)) { \ + goto error; \ + } - col2 = (colnr_T)v->data.integer; - } else if (strequal("hl_group", k.data)) { - String hl_group; - switch (v->type) { - case kObjectTypeString: - hl_group = v->data.string; - decor.hl_id = syn_check_group((char_u *)(hl_group.data), - (int)hl_group.size); - break; - case kObjectTypeInteger: - decor.hl_id = (int)v->data.integer; - break; - default: - api_set_error(err, kErrorTypeValidation, - "hl_group is not valid."); - goto error; - } - } else if (strequal("virt_text", k.data)) { - if (v->type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, - "virt_text is not an Array"); - goto error; - } - decor.virt_text = parse_virt_text(v->data.array, err, - &decor.virt_text_width); - if (ERROR_SET(err)) { - goto error; - } - } else if (strequal("virt_text_pos", k.data)) { - if (v->type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "virt_text_pos is not a String"); - goto error; - } - String str = v->data.string; - if (strequal("eol", str.data)) { - decor.virt_text_pos = kVTEndOfLine; - } else if (strequal("overlay", str.data)) { - decor.virt_text_pos = kVTOverlay; - } else if (strequal("right_align", str.data)) { - decor.virt_text_pos = kVTRightAlign; - } else { - api_set_error(err, kErrorTypeValidation, - "virt_text_pos: invalid value"); - goto error; - } - } else if (strequal("virt_text_win_col", k.data)) { - if (v->type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, - "virt_text_win_col is not a Number of the correct size"); - goto error; - } + OPTION_TO_BOOL(decor.virt_text_hide, virt_text_hide, false); + OPTION_TO_BOOL(decor.hl_eol, hl_eol, false); + + if (opts->hl_mode.type == kObjectTypeString) { + String str = opts->hl_mode.data.string; + if (strequal("replace", str.data)) { + decor.hl_mode = kHlModeReplace; + } else if (strequal("combine", str.data)) { + decor.hl_mode = kHlModeCombine; + } else if (strequal("blend", str.data)) { + decor.hl_mode = kHlModeBlend; + } else { + api_set_error(err, kErrorTypeValidation, + "virt_text_pos: invalid value"); + goto error; + } + } else if (HAS_KEY(opts->hl_mode)) { + api_set_error(err, kErrorTypeValidation, "hl_mode is not a String"); + goto error; + } - decor.col = (int)v->data.integer; - decor.virt_text_pos = kVTWinCol; - } else if (strequal("virt_text_hide", k.data)) { - decor.virt_text_hide = api_object_to_bool(*v, - "virt_text_hide", false, err); - if (ERROR_SET(err)) { - goto error; - } - } else if (strequal("virt_lines", k.data)) { - if (v->type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, - "virt_lines is not an Array"); - goto error; - } - Array a = v->data.array; - for (size_t j = 0; j < a.size; j++) { - if (a.items[j].type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, - "virt_text_line item is not an Array"); - goto error; - } - int dummig; - VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig); - kv_push(virt_lines, jtem); - if (ERROR_SET(err)) { - goto error; - } - } - } else if (strequal("virt_lines_above", k.data)) { - virt_lines_above = api_object_to_bool(*v, "virt_lines_above", false, err); - if (ERROR_SET(err)) { - goto error; - } - } else if (strequal("virt_lines_leftcol", k.data)) { - virt_lines_leftcol = api_object_to_bool(*v, "virt_lines_leftcol", false, err); - if (ERROR_SET(err)) { - goto error; - } - } else if (strequal("hl_eol", k.data)) { - decor.hl_eol = api_object_to_bool(*v, "hl_eol", false, err); - if (ERROR_SET(err)) { - goto error; - } - } else if (strequal("hl_mode", k.data)) { - if (v->type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "hl_mode is not a String"); - goto error; - } - String str = v->data.string; - if (strequal("replace", str.data)) { - decor.hl_mode = kHlModeReplace; - } else if (strequal("combine", str.data)) { - decor.hl_mode = kHlModeCombine; - } else if (strequal("blend", str.data)) { - decor.hl_mode = kHlModeBlend; - } else { - api_set_error(err, kErrorTypeValidation, - "virt_text_pos: invalid value"); + VirtLines virt_lines = KV_INITIAL_VALUE; + bool virt_lines_above = false; + bool virt_lines_leftcol = false; + + if (opts->virt_lines.type == kObjectTypeArray) { + Array a = opts->virt_lines.data.array; + for (size_t j = 0; j < a.size; j++) { + if (a.items[j].type != kObjectTypeArray) { + api_set_error(err, kErrorTypeValidation, "virt_text_line item is not an Array"); goto error; } - } else if (strequal("ephemeral", k.data)) { - ephemeral = api_object_to_bool(*v, "ephemeral", false, err); + int dummig; + VirtText jtem = parse_virt_text(a.items[j].data.array, err, &dummig); + kv_push(virt_lines, jtem); if (ERROR_SET(err)) { goto error; } - } else if (strequal("priority", k.data)) { - if (v->type != kObjectTypeInteger) { - api_set_error(err, kErrorTypeValidation, - "priority is not a Number of the correct size"); - goto error; - } + } + } else if (HAS_KEY(opts->virt_lines)) { + api_set_error(err, kErrorTypeValidation, "virt_lines is not an Array"); + goto error; + } - if (v->data.integer < 0 || v->data.integer > UINT16_MAX) { - api_set_error(err, kErrorTypeValidation, - "priority is not a valid value"); - goto error; - } - decor.priority = (DecorPriority)v->data.integer; - } else if (strequal("right_gravity", k.data)) { - if (v->type != kObjectTypeBoolean) { - api_set_error(err, kErrorTypeValidation, - "right_gravity must be a boolean"); - goto error; - } - right_gravity = v->data.boolean; - } else if (strequal("end_right_gravity", k.data)) { - if (v->type != kObjectTypeBoolean) { - api_set_error(err, kErrorTypeValidation, - "end_right_gravity must be a boolean"); - goto error; - } - end_right_gravity = v->data.boolean; - end_gravity_set = true; - } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); + OPTION_TO_BOOL(virt_lines_above, virt_lines_above, false); + OPTION_TO_BOOL(virt_lines_leftcol, virt_lines_leftcol, false); + + if (opts->priority.type == kObjectTypeInteger) { + Integer val = opts->priority.data.integer; + + if (val < 0 || val > UINT16_MAX) { + api_set_error(err, kErrorTypeValidation, "priority is not a valid value"); goto error; } + decor.priority = (DecorPriority)val; + } else if (HAS_KEY(opts->priority)) { + api_set_error(err, kErrorTypeValidation, "priority is not a Number of the correct size"); + goto error; + } + + bool right_gravity = true; + OPTION_TO_BOOL(right_gravity, right_gravity, true); + + // Only error out if they try to set end_right_gravity without + // setting end_col or end_line + if (line2 == -1 && col2 == -1 && HAS_KEY(opts->end_right_gravity)) { + api_set_error(err, kErrorTypeValidation, + "cannot set end_right_gravity without setting end_line or end_col"); + goto error; } + bool end_right_gravity = false; + OPTION_TO_BOOL(end_right_gravity, end_right_gravity, false); + size_t len = 0; + + bool ephemeral = false; + OPTION_TO_BOOL(ephemeral, ephemeral, false); + if (line < 0 || line > buf->b_ml.ml_line_count) { api_set_error(err, kErrorTypeValidation, "line value outside range"); return 0; @@ -1717,15 +1753,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer return 0; } - - // Only error out if they try to set end_right_gravity without - // setting end_col or end_line - if (line2 == -1 && col2 == -1 && end_gravity_set) { - api_set_error(err, kErrorTypeValidation, - "cannot set end_right_gravity " - "without setting end_line or end_col"); - } - if (col2 >= 0) { if (line2 >= 0 && line2 < buf->b_ml.ml_line_count) { len = ephemeral ? MAXCOL : STRLEN(ml_get_buf(buf, (linenr_T)line2 + 1, false)); @@ -1744,15 +1771,6 @@ Integer nvim_buf_set_extmark(Buffer buffer, Integer ns_id, Integer line, Integer col2 = 0; } - if (decor.virt_text_pos == kVTRightAlign) { - decor.col = 0; - for (size_t i = 0; i < kv_size(decor.virt_text); i++) { - decor.col - += (int)mb_string2cells((char_u *)kv_A(decor.virt_text, i).text); - } - } - - Decoration *d = NULL; if (ephemeral) { diff --git a/src/nvim/api/deprecated.c b/src/nvim/api/deprecated.c index 332fc0ba96..907d09e5b7 100644 --- a/src/nvim/api/deprecated.c +++ b/src/nvim/api/deprecated.c @@ -165,6 +165,7 @@ Integer nvim_buf_set_virtual_text(Buffer buffer, Integer src_id, Integer line, A /// @param lines Array of lines /// @param[out] err Error details, if any void buffer_insert(Buffer buffer, Integer lnum, ArrayOf(String) lines, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { // "lnum" will be the index of the line after inserting, // no matter if it is negative or not @@ -184,6 +185,7 @@ void buffer_insert(Buffer buffer, Integer lnum, ArrayOf(String) lines, Error *er /// @param[out] err Error details, if any /// @return Line string String buffer_get_line(Buffer buffer, Integer index, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { String rv = { .size = 0 }; @@ -212,6 +214,7 @@ String buffer_get_line(Buffer buffer, Integer index, Error *err) /// @param line Contents of the new line /// @param[out] err Error details, if any void buffer_set_line(Buffer buffer, Integer index, String line, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { Object l = STRING_OBJ(line); Array array = { .items = &l, .size = 1 }; @@ -230,6 +233,7 @@ void buffer_set_line(Buffer buffer, Integer index, String line, Error *err) /// @param index line index /// @param[out] err Error details, if any void buffer_del_line(Buffer buffer, Integer index, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { Array array = ARRAY_DICT_INIT; index = convert_index(index); @@ -255,6 +259,7 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer, Boolean include_start, Boolean include_end, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { start = convert_index(start) + !include_start; end = convert_index(end) + include_end; @@ -278,6 +283,7 @@ ArrayOf(String) buffer_get_line_slice(Buffer buffer, /// @param[out] err Error details, if any void buffer_set_line_slice(Buffer buffer, Integer start, Integer end, Boolean include_start, Boolean include_end, ArrayOf(String) replacement, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { start = convert_index(start) + !include_start; end = convert_index(end) + include_end; @@ -298,6 +304,7 @@ void buffer_set_line_slice(Buffer buffer, Integer start, Integer end, Boolean in /// @warning It may return nil if there was no previous value /// or if previous value was `v:null`. Object buffer_set_var(Buffer buffer, String name, Object value, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -317,6 +324,7 @@ Object buffer_set_var(Buffer buffer, String name, Object value, Error *err) /// @param[out] err Error details, if any /// @return Old value Object buffer_del_var(Buffer buffer, String name, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { buf_T *buf = find_buffer_by_handle(buffer, err); @@ -340,6 +348,7 @@ Object buffer_del_var(Buffer buffer, String name, Error *err) /// @warning It may return nil if there was no previous value /// or if previous value was `v:null`. Object window_set_var(Window window, String name, Object value, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { win_T *win = find_window_by_handle(window, err); @@ -359,6 +368,7 @@ Object window_set_var(Window window, String name, Object value, Error *err) /// @param[out] err Error details, if any /// @return Old value Object window_del_var(Window window, String name, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { win_T *win = find_window_by_handle(window, err); @@ -382,6 +392,7 @@ Object window_del_var(Window window, String name, Error *err) /// @warning It may return nil if there was no previous value /// or if previous value was `v:null`. Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { tabpage_T *tab = find_tab_by_handle(tabpage, err); @@ -401,6 +412,7 @@ Object tabpage_set_var(Tabpage tabpage, String name, Object value, Error *err) /// @param[out] err Error details, if any /// @return Old value Object tabpage_del_var(Tabpage tabpage, String name, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { tabpage_T *tab = find_tab_by_handle(tabpage, err); @@ -417,6 +429,7 @@ Object tabpage_del_var(Tabpage tabpage, String name, Error *err) /// OR if previous value was `v:null`. /// @return Old value or nil if there was no previous value. Object vim_set_var(String name, Object value, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { return dict_set_var(&globvardict, name, value, false, true, err); } @@ -424,6 +437,7 @@ Object vim_set_var(String name, Object value, Error *err) /// @deprecated /// @see nvim_del_var Object vim_del_var(String name, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { return dict_set_var(&globvardict, name, NIL, true, true, err); } diff --git a/src/nvim/api/keysets.lua b/src/nvim/api/keysets.lua new file mode 100644 index 0000000000..76ce9e15ea --- /dev/null +++ b/src/nvim/api/keysets.lua @@ -0,0 +1,52 @@ +return { + context = { + "types"; + }; + set_extmark = { + "id"; + "end_line"; + "end_col"; + "hl_group"; + "virt_text"; + "virt_text_pos"; + "virt_text_win_col"; + "virt_text_hide"; + "hl_eol"; + "hl_mode"; + "ephemeral"; + "priority"; + "right_gravity"; + "end_right_gravity"; + "virt_lines"; + "virt_lines_above"; + "virt_lines_leftcol"; + }; + keymap = { + "noremap"; + "nowait"; + "silent"; + "script"; + "expr"; + "unique"; + }; + get_commands = { + "builtin"; + }; + float_config = { + "row"; + "col"; + "width"; + "height"; + "anchor"; + "relative"; + "win"; + "bufpos"; + "external"; + "focusable"; + "zindex"; + "border"; + "style"; + "noautocmd"; + }; +} + diff --git a/src/nvim/api/private/defs.h b/src/nvim/api/private/defs.h index f0d48bf145..8346e01558 100644 --- a/src/nvim/api/private/defs.h +++ b/src/nvim/api/private/defs.h @@ -19,6 +19,7 @@ #ifdef INCLUDE_GENERATED_DECLARATIONS # define ArrayOf(...) Array # define DictionaryOf(...) Dictionary +# define Dict(name) KeyDict_##name #endif // Basic types @@ -129,5 +130,14 @@ struct key_value_pair { Object value; }; +typedef Object *(*field_hash)(void *retval, const char *str, size_t len); +typedef struct { + char *str; + size_t ptr_off; +} KeySetLink; + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "keysets_defs.generated.h" +#endif #endif // NVIM_API_PRIVATE_DEFS_H diff --git a/src/nvim/api/private/dispatch.c b/src/nvim/api/private/dispatch.c index 5e93ccce17..ee0cdc4c07 100644 --- a/src/nvim/api/private/dispatch.c +++ b/src/nvim/api/private/dispatch.c @@ -15,6 +15,7 @@ #include "nvim/api/ui.h" #include "nvim/api/vim.h" #include "nvim/api/window.h" +#include "nvim/api/win_config.h" #include "nvim/log.h" #include "nvim/map.h" #include "nvim/msgpack_rpc/helpers.h" diff --git a/src/nvim/api/private/helpers.c b/src/nvim/api/private/helpers.c index 193f1dd572..46ef41cc38 100644 --- a/src/nvim/api/private/helpers.c +++ b/src/nvim/api/private/helpers.c @@ -6,6 +6,7 @@ #include <stdbool.h> #include <stdlib.h> #include <string.h> +#include <stddef.h> #include "nvim/api/private/defs.h" #include "nvim/api/private/helpers.h" @@ -24,6 +25,7 @@ #include "nvim/lua/executor.h" #include "nvim/map.h" #include "nvim/map_defs.h" +#include "nvim/mark.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/msgpack_rpc/helpers.h" @@ -395,7 +397,7 @@ void set_option_to(uint64_t channel_id, void *to, int type, String name, Object return; } - stringval = (char *)value.data.string.data; + stringval = value.data.string.data; } const sctx_T save_current_sctx = current_sctx; @@ -814,7 +816,7 @@ Array string_to_array(const String input, bool crlf) /// buffer, or -1 to signify global behavior ("all buffers") /// @param is_unmap When true, removes the mapping that matches {lhs}. void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String rhs, - Dictionary opts, Error *err) + Dict(keymap) *opts, Error *err) { char *err_msg = NULL; // the error message to report, if any char *err_arg = NULL; // argument for the error message format string @@ -833,10 +835,21 @@ void modify_keymap(Buffer buffer, bool is_unmap, String mode, String lhs, String return; } - MapArguments parsed_args; - memset(&parsed_args, 0, sizeof(parsed_args)); - if (parse_keymap_opts(opts, &parsed_args, err)) { - goto fail_and_free; + MapArguments parsed_args = MAP_ARGUMENTS_INIT; + if (opts) { +#define KEY_TO_BOOL(name) \ + parsed_args. name = api_object_to_bool(opts-> name, #name, false, err); \ + if (ERROR_SET(err)) { \ + goto fail_and_free; \ + } + + KEY_TO_BOOL(nowait); + KEY_TO_BOOL(noremap); + KEY_TO_BOOL(silent); + KEY_TO_BOOL(script); + KEY_TO_BOOL(expr); + KEY_TO_BOOL(unique); +#undef KEY_TO_BOOL } parsed_args.buffer = !global; @@ -947,95 +960,6 @@ fail_and_free: return; } -/// Read in the given opts, setting corresponding flags in `out`. -/// -/// @param opts A dictionary passed to @ref nvim_set_keymap or -/// @ref nvim_buf_set_keymap. -/// @param[out] out MapArguments object in which to set parsed -/// |:map-arguments| flags. -/// @param[out] err Error details, if any. -/// -/// @returns Zero on success, nonzero on failure. -Integer parse_keymap_opts(Dictionary opts, MapArguments *out, Error *err) -{ - char *err_msg = NULL; // the error message to report, if any - char *err_arg = NULL; // argument for the error message format string - ErrorType err_type = kErrorTypeNone; - - out->buffer = false; - out->nowait = false; - out->silent = false; - out->script = false; - out->expr = false; - out->unique = false; - - for (size_t i = 0; i < opts.size; i++) { - KeyValuePair *key_and_val = &opts.items[i]; - char *optname = key_and_val->key.data; - - if (key_and_val->value.type != kObjectTypeBoolean) { - err_msg = "Gave non-boolean value for an opt: %s"; - err_arg = optname; - err_type = kErrorTypeValidation; - goto fail_with_message; - } - - bool was_valid_opt = false; - switch (optname[0]) { - // note: strncmp up to and including the null terminator, so that - // "nowaitFoobar" won't match against "nowait" - - // don't recognize 'buffer' as a key; user shouldn't provide <buffer> - // when calling nvim_set_keymap or nvim_buf_set_keymap, since it can be - // inferred from which function they called - case 'n': - if (STRNCMP(optname, "noremap", 8) == 0) { - was_valid_opt = true; - out->noremap = key_and_val->value.data.boolean; - } else if (STRNCMP(optname, "nowait", 7) == 0) { - was_valid_opt = true; - out->nowait = key_and_val->value.data.boolean; - } - break; - case 's': - if (STRNCMP(optname, "silent", 7) == 0) { - was_valid_opt = true; - out->silent = key_and_val->value.data.boolean; - } else if (STRNCMP(optname, "script", 7) == 0) { - was_valid_opt = true; - out->script = key_and_val->value.data.boolean; - } - break; - case 'e': - if (STRNCMP(optname, "expr", 5) == 0) { - was_valid_opt = true; - out->expr = key_and_val->value.data.boolean; - } - break; - case 'u': - if (STRNCMP(optname, "unique", 7) == 0) { - was_valid_opt = true; - out->unique = key_and_val->value.data.boolean; - } - break; - default: - break; - } // switch - if (!was_valid_opt) { - err_msg = "Invalid key: %s"; - err_arg = optname; - err_type = kErrorTypeValidation; - goto fail_with_message; - } - } // for - - return 0; - -fail_with_message: - api_set_error(err, err_type, err_msg, err_arg); - return 1; -} - /// Collects `n` buffer lines into array `l`, optionally replacing newlines /// with NUL. /// @@ -1725,367 +1649,65 @@ const char *describe_ns(NS ns_id) return "(UNKNOWN PLUGIN)"; } -static bool parse_float_anchor(String anchor, FloatAnchor *out) +bool api_dict_to_keydict(void *rv, field_hash hashy, Dictionary dict, Error *err) { - if (anchor.size == 0) { - *out = (FloatAnchor)0; - } - char *str = anchor.data; - if (striequal(str, "NW")) { - *out = 0; // NW is the default - } else if (striequal(str, "NE")) { - *out = kFloatAnchorEast; - } else if (striequal(str, "SW")) { - *out = kFloatAnchorSouth; - } else if (striequal(str, "SE")) { - *out = kFloatAnchorSouth | kFloatAnchorEast; - } else { - return false; - } - return true; -} + for (size_t i = 0; i < dict.size; i++) { + String k = dict.items[i].key; + Object *field = hashy(rv, k.data, k.size); + if (!field) { + api_set_error(err, kErrorTypeValidation, "Invalid key: '%.*s'", (int)k.size, k.data); + return false; + } -static bool parse_float_relative(String relative, FloatRelative *out) -{ - char *str = relative.data; - if (striequal(str, "editor")) { - *out = kFloatRelativeEditor; - } else if (striequal(str, "win")) { - *out = kFloatRelativeWindow; - } else if (striequal(str, "cursor")) { - *out = kFloatRelativeCursor; - } else { - return false; + *field = dict.items[i].value; } + return true; } -static bool parse_float_bufpos(Array bufpos, lpos_T *out) +void api_free_keydict(void *dict, KeySetLink *table) { - if (bufpos.size != 2 - || bufpos.items[0].type != kObjectTypeInteger - || bufpos.items[1].type != kObjectTypeInteger) { - return false; + for (size_t i = 0; table[i].str; i++) { + api_free_object(*(Object *)((char *)dict + table[i].ptr_off)); } - out->lnum = bufpos.items[0].data.integer; - out->col = (colnr_T)bufpos.items[1].data.integer; - return true; } -static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) +/// Set a named mark +/// buffer and mark name must be validated already +/// @param buffer Buffer to set the mark on +/// @param name Mark name +/// @param line Line number +/// @param col Column/row number +/// @return true if the mark was set, else false +bool set_mark(buf_T *buf, String name, Integer line, Integer col, Error *err) { - struct { - const char *name; - schar_T chars[8]; - bool shadow_color; - } defaults[] = { - { "double", { "╔", "═", "╗", "║", "╝", "═", "╚", "║" }, false }, - { "single", { "┌", "─", "┐", "│", "┘", "─", "└", "│" }, false }, - { "shadow", { "", "", " ", " ", " ", " ", " ", "" }, true }, - { "rounded", { "╭", "─", "╮", "│", "╯", "─", "╰", "│" }, false }, - { "solid", { " ", " ", " ", " ", " ", " ", " ", " " }, false }, - { NULL, { { NUL } }, false }, - }; - - schar_T *chars = fconfig->border_chars; - int *hl_ids = fconfig->border_hl_ids; - - fconfig->border = true; - - if (style.type == kObjectTypeArray) { - Array arr = style.data.array; - size_t size = arr.size; - if (!size || size > 8 || (size & (size-1))) { - api_set_error(err, kErrorTypeValidation, - "invalid number of border chars"); - return; - } - for (size_t i = 0; i < size; i++) { - Object iytem = arr.items[i]; - String string; - int hl_id = 0; - if (iytem.type == kObjectTypeArray) { - Array iarr = iytem.data.array; - if (!iarr.size || iarr.size > 2) { - api_set_error(err, kErrorTypeValidation, "invalid border char"); - return; - } - if (iarr.items[0].type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, "invalid border char"); - return; - } - string = iarr.items[0].data.string; - if (iarr.size == 2) { - hl_id = object_to_hl_id(iarr.items[1], "border char highlight", err); - if (ERROR_SET(err)) { - return; - } - } - } else if (iytem.type == kObjectTypeString) { - string = iytem.data.string; - } else { - api_set_error(err, kErrorTypeValidation, "invalid border char"); - return; - } - if (string.size - && mb_string2cells_len((char_u *)string.data, string.size) > 1) { - api_set_error(err, kErrorTypeValidation, - "border chars must be one cell"); - return; - } - size_t len = MIN(string.size, sizeof(*chars)-1); - if (len) { - memcpy(chars[i], string.data, len); - } - chars[i][len] = NUL; - hl_ids[i] = hl_id; - } - while (size < 8) { - memcpy(chars+size, chars, sizeof(*chars) * size); - memcpy(hl_ids+size, hl_ids, sizeof(*hl_ids) * size); - size <<= 1; - } - if ((chars[7][0] && chars[1][0] && !chars[0][0]) - || (chars[1][0] && chars[3][0] && !chars[2][0]) - || (chars[3][0] && chars[5][0] && !chars[4][0]) - || (chars[5][0] && chars[7][0] && !chars[6][0])) { - api_set_error(err, kErrorTypeValidation, - "corner between used edges must be specified"); - } - } else if (style.type == kObjectTypeString) { - String str = style.data.string; - if (str.size == 0 || strequal(str.data, "none")) { - fconfig->border = false; - return; + buf = buf == NULL ? curbuf : buf; + // If line == 0 the marks is being deleted + bool res = false; + bool deleting = false; + if (line == 0) { + col = 0; + deleting = true; + } else { + if (col > MAXCOL) { + api_set_error(err, kErrorTypeValidation, "Column value outside range"); + return res; } - for (size_t i = 0; defaults[i].name; i++) { - if (strequal(str.data, defaults[i].name)) { - memcpy(chars, defaults[i].chars, sizeof(defaults[i].chars)); - memset(hl_ids, 0, 8 * sizeof(*hl_ids)); - if (defaults[i].shadow_color) { - int hl_blend = SYN_GROUP_STATIC("FloatShadow"); - int hl_through = SYN_GROUP_STATIC("FloatShadowThrough"); - hl_ids[2] = hl_through; - hl_ids[3] = hl_blend; - hl_ids[4] = hl_blend; - hl_ids[5] = hl_blend; - hl_ids[6] = hl_through; - } - return; - } + if (line < 1 || line > buf->b_ml.ml_line_count) { + api_set_error(err, kErrorTypeValidation, "Line value outside range"); + return res; } - api_set_error(err, kErrorTypeValidation, - "invalid border style \"%s\"", str.data); } -} - -bool parse_float_config(Dictionary config, FloatConfig *fconfig, bool reconf, bool new_win, - Error *err) -{ - // TODO(bfredl): use a get/has_key interface instead and get rid of extra - // flags - bool has_row = false, has_col = false, has_relative = false; - bool has_external = false, has_window = false; - bool has_width = false, has_height = false; - bool has_bufpos = false; - - for (size_t i = 0; i < config.size; i++) { - char *key = config.items[i].key.data; - Object val = config.items[i].value; - if (!strcmp(key, "row")) { - has_row = true; - if (val.type == kObjectTypeInteger) { - fconfig->row = (double)val.data.integer; - } else if (val.type == kObjectTypeFloat) { - fconfig->row = val.data.floating; - } else { - api_set_error(err, kErrorTypeValidation, - "'row' key must be Integer or Float"); - return false; - } - } else if (!strcmp(key, "col")) { - has_col = true; - if (val.type == kObjectTypeInteger) { - fconfig->col = (double)val.data.integer; - } else if (val.type == kObjectTypeFloat) { - fconfig->col = val.data.floating; - } else { - api_set_error(err, kErrorTypeValidation, - "'col' key must be Integer or Float"); - return false; - } - } else if (strequal(key, "width")) { - has_width = true; - if (val.type == kObjectTypeInteger && val.data.integer > 0) { - fconfig->width = (int)val.data.integer; - } else { - api_set_error(err, kErrorTypeValidation, - "'width' key must be a positive Integer"); - return false; - } - } else if (strequal(key, "height")) { - has_height = true; - if (val.type == kObjectTypeInteger && val.data.integer > 0) { - fconfig->height = (int)val.data.integer; - } else { - api_set_error(err, kErrorTypeValidation, - "'height' key must be a positive Integer"); - return false; - } - } else if (!strcmp(key, "anchor")) { - if (val.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "'anchor' key must be String"); - return false; - } - if (!parse_float_anchor(val.data.string, &fconfig->anchor)) { - api_set_error(err, kErrorTypeValidation, - "Invalid value of 'anchor' key"); - return false; - } - } else if (!strcmp(key, "relative")) { - if (val.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "'relative' key must be String"); - return false; - } - // ignore empty string, to match nvim_win_get_config - if (val.data.string.size > 0) { - has_relative = true; - if (!parse_float_relative(val.data.string, &fconfig->relative)) { - api_set_error(err, kErrorTypeValidation, - "Invalid value of 'relative' key"); - return false; - } - } - } else if (!strcmp(key, "win")) { - has_window = true; - if (val.type != kObjectTypeInteger - && val.type != kObjectTypeWindow) { - api_set_error(err, kErrorTypeValidation, - "'win' key must be Integer or Window"); - return false; - } - fconfig->window = (Window)val.data.integer; - } else if (!strcmp(key, "bufpos")) { - if (val.type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, - "'bufpos' key must be Array"); - return false; - } - if (!parse_float_bufpos(val.data.array, &fconfig->bufpos)) { - api_set_error(err, kErrorTypeValidation, - "Invalid value of 'bufpos' key"); - return false; - } - has_bufpos = true; - } else if (!strcmp(key, "external")) { - has_external = fconfig->external - = api_object_to_bool(val, "'external' key", false, err); - if (ERROR_SET(err)) { - return false; - } - } else if (!strcmp(key, "focusable")) { - fconfig->focusable - = api_object_to_bool(val, "'focusable' key", true, err); - if (ERROR_SET(err)) { - return false; - } - } else if (strequal(key, "zindex")) { - if (val.type == kObjectTypeInteger && val.data.integer > 0) { - fconfig->zindex = (int)val.data.integer; - } else { - api_set_error(err, kErrorTypeValidation, - "'zindex' key must be a positive Integer"); - return false; - } - } else if (!strcmp(key, "border")) { - parse_border_style(val, fconfig, err); - if (ERROR_SET(err)) { - return false; - } - } else if (!strcmp(key, "style")) { - if (val.type != kObjectTypeString) { - api_set_error(err, kErrorTypeValidation, - "'style' key must be String"); - return false; - } - if (val.data.string.data[0] == NUL) { - fconfig->style = kWinStyleUnused; - } else if (striequal(val.data.string.data, "minimal")) { - fconfig->style = kWinStyleMinimal; - } else { - api_set_error(err, kErrorTypeValidation, - "Invalid value of 'style' key"); - } - } else if (strequal(key, "noautocmd") && new_win) { - fconfig->noautocmd - = api_object_to_bool(val, "'noautocmd' key", false, err); - if (ERROR_SET(err)) { - return false; - } + pos_T pos = { line, (int)col, (int)col }; + res = setmark_pos(*name.data, &pos, buf->handle); + if (!res) { + if (deleting) { + api_set_error(err, kErrorTypeException, + "Failed to delete named mark: %c", *name.data); } else { - api_set_error(err, kErrorTypeValidation, - "Invalid key '%s'", key); - return false; - } - } - - if (has_window && !(has_relative - && fconfig->relative == kFloatRelativeWindow)) { - api_set_error(err, kErrorTypeValidation, - "'win' key is only valid with relative='win'"); - return false; - } - - if ((has_relative && fconfig->relative == kFloatRelativeWindow) - && (!has_window || fconfig->window == 0)) { - fconfig->window = curwin->handle; - } - - if (has_window && !has_bufpos) { - fconfig->bufpos.lnum = -1; - } - - if (has_bufpos) { - if (!has_row) { - fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1; - has_row = true; - } - if (!has_col) { - fconfig->col = 0; - has_col = true; + api_set_error(err, kErrorTypeException, + "Failed to set named mark: %c", *name.data); } } - - if (has_relative && has_external) { - api_set_error(err, kErrorTypeValidation, - "Only one of 'relative' and 'external' must be used"); - return false; - } else if (!reconf && !has_relative && !has_external) { - api_set_error(err, kErrorTypeValidation, - "One of 'relative' and 'external' must be used"); - return false; - } else if (has_relative) { - fconfig->external = false; - } - - if (!reconf && !(has_height && has_width)) { - api_set_error(err, kErrorTypeValidation, - "Must specify 'width' and 'height'"); - return false; - } - - if (fconfig->external && !ui_has(kUIMultigrid)) { - api_set_error(err, kErrorTypeValidation, - "UI doesn't support external windows"); - return false; - } - - if (has_relative != has_row || has_row != has_col) { - api_set_error(err, kErrorTypeValidation, - "'relative' requires 'row'/'col' or 'bufpos'"); - return false; - } - return true; + return res; } diff --git a/src/nvim/api/private/helpers.h b/src/nvim/api/private/helpers.h index ecce6afa26..2cdd80bffe 100644 --- a/src/nvim/api/private/helpers.h +++ b/src/nvim/api/private/helpers.h @@ -59,6 +59,9 @@ #define NIL ((Object)OBJECT_INIT) #define NULL_STRING ((String)STRING_INIT) +// currently treat key=vim.NIL as if the key was missing +#define HAS_KEY(o) ((o).type != kObjectTypeNil) + #define PUT(dict, k, v) \ kv_push(dict, ((KeyValuePair) { .key = cstr_to_string(k), .value = v })) @@ -138,6 +141,9 @@ typedef struct { } while (0) #ifdef INCLUDE_GENERATED_DECLARATIONS +# include "keysets.h.generated.h" # include "api/private/helpers.h.generated.h" #endif + + #endif // NVIM_API_PRIVATE_HELPERS_H diff --git a/src/nvim/api/ui.c b/src/nvim/api/ui.c index 9b200dcba2..d86aecc318 100644 --- a/src/nvim/api/ui.c +++ b/src/nvim/api/ui.c @@ -40,7 +40,6 @@ typedef struct { static PMap(uint64_t) connected_uis = MAP_INIT; void remote_ui_disconnect(uint64_t channel_id) - FUNC_API_NOEXPORT { UI *ui = pmap_get(uint64_t)(&connected_uis, channel_id); if (!ui) { @@ -57,7 +56,6 @@ void remote_ui_disconnect(uint64_t channel_id) /// Wait until ui has connected on stdio channel. void remote_ui_wait_for_attach(void) - FUNC_API_NOEXPORT { Channel *channel = find_channel(CHAN_STDIO); if (!channel) { @@ -172,6 +170,7 @@ void nvim_ui_attach(uint64_t channel_id, Integer width, Integer height, Dictiona /// @deprecated void ui_attach(uint64_t channel_id, Integer width, Integer height, Boolean enable_rgb, Error *err) + FUNC_API_DEPRECATED_SINCE(1) { Dictionary opts = ARRAY_DICT_INIT; PUT(opts, "rgb", BOOLEAN_OBJ(enable_rgb)); diff --git a/src/nvim/api/vim.c b/src/nvim/api/vim.c index 3be45d0cf7..9b39b18c4e 100644 --- a/src/nvim/api/vim.c +++ b/src/nvim/api/vim.c @@ -59,7 +59,6 @@ #endif void api_vim_free_all_mem(void) - FUNC_API_NOEXPORT { String name; handle_T id; @@ -264,7 +263,6 @@ void nvim__set_hl_ns(Integer ns_id, Error *err) } static void on_redraw_event(void **argv) - FUNC_API_NOEXPORT { redraw_all_later(NOT_VALID); } @@ -1221,7 +1219,7 @@ fail: /// buffer in a configured window before calling this. For instance, for a /// floating display, first create an empty buffer using |nvim_create_buf()|, /// then display it using |nvim_open_win()|, and then call this function. -/// Then |nvim_chan_send()| cal be called immediately to process sequences +/// Then |nvim_chan_send()| can be called immediately to process sequences /// in a virtual terminal having the intended size. /// /// @param buffer the buffer to use (expected to be empty) @@ -1305,153 +1303,6 @@ void nvim_chan_send(Integer chan, String data, Error *err) } } -/// Open a new window. -/// -/// Currently this is used to open floating and external windows. -/// Floats are windows that are drawn above the split layout, at some anchor -/// position in some other window. Floats can be drawn internally or by external -/// GUI with the |ui-multigrid| extension. External windows are only supported -/// with multigrid GUIs, and are displayed as separate top-level windows. -/// -/// For a general overview of floats, see |api-floatwin|. -/// -/// Exactly one of `external` and `relative` must be specified. The `width` and -/// `height` of the new window must be specified. -/// -/// With relative=editor (row=0,col=0) refers to the top-left corner of the -/// screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right -/// corner. Fractional values are allowed, but the builtin implementation -/// (used by non-multigrid UIs) will always round down to nearest integer. -/// -/// Out-of-bounds values, and configurations that make the float not fit inside -/// the main editor, are allowed. The builtin implementation truncates values -/// so floats are fully within the main screen grid. External GUIs -/// could let floats hover outside of the main window like a tooltip, but -/// this should not be used to specify arbitrary WM screen positions. -/// -/// Example (Lua): window-relative float -/// <pre> -/// vim.api.nvim_open_win(0, false, -/// {relative='win', row=3, col=3, width=12, height=3}) -/// </pre> -/// -/// Example (Lua): buffer-relative float (travels as buffer is scrolled) -/// <pre> -/// vim.api.nvim_open_win(0, false, -/// {relative='win', width=12, height=3, bufpos={100,10}}) -/// </pre> -/// -/// @param buffer Buffer to display, or 0 for current buffer -/// @param enter Enter the window (make it the current window) -/// @param config Map defining the window configuration. Keys: -/// - `relative`: Sets the window layout to "floating", placed at (row,col) -/// coordinates relative to: -/// - "editor" The global editor grid -/// - "win" Window given by the `win` field, or current window. -/// - "cursor" Cursor position in current window. -/// - `win`: |window-ID| for relative="win". -/// - `anchor`: Decides which corner of the float to place at (row,col): -/// - "NW" northwest (default) -/// - "NE" northeast -/// - "SW" southwest -/// - "SE" southeast -/// - `width`: Window width (in character cells). Minimum of 1. -/// - `height`: Window height (in character cells). Minimum of 1. -/// - `bufpos`: Places float relative to buffer text (only when -/// relative="win"). Takes a tuple of zero-indexed [line, column]. -/// `row` and `col` if given are applied relative to this -/// position, else they default to `row=1` and `col=0` -/// (thus like a tooltip near the buffer text). -/// - `row`: Row position in units of "screen cell height", may be fractional. -/// - `col`: Column position in units of "screen cell width", may be -/// fractional. -/// - `focusable`: Enable focus by user actions (wincmds, mouse events). -/// Defaults to true. Non-focusable windows can be entered by -/// |nvim_set_current_win()|. -/// - `external`: GUI should display the window as an external -/// top-level window. Currently accepts no other positioning -/// configuration together with this. -/// - `zindex`: Stacking order. floats with higher `zindex` go on top on -/// floats with lower indices. Must be larger than zero. The -/// following screen elements have hard-coded z-indices: -/// - 100: insert completion popupmenu -/// - 200: message scrollback -/// - 250: cmdline completion popupmenu (when wildoptions+=pum) -/// The default value for floats are 50. In general, values below 100 are -/// recommended, unless there is a good reason to overshadow builtin -/// elements. -/// - `style`: Configure the appearance of the window. Currently only takes -/// one non-empty value: -/// - "minimal" Nvim will display the window with many UI options -/// disabled. This is useful when displaying a temporary -/// float where the text should not be edited. Disables -/// 'number', 'relativenumber', 'cursorline', 'cursorcolumn', -/// 'foldcolumn', 'spell' and 'list' options. 'signcolumn' -/// is changed to `auto` and 'colorcolumn' is cleared. The -/// end-of-buffer region is hidden by setting `eob` flag of -/// 'fillchars' to a space char, and clearing the -/// |EndOfBuffer| region in 'winhighlight'. -/// - `border`: Style of (optional) window border. This can either be a string -/// or an array. The string values are -/// - "none": No border (default). -/// - "single": A single line box. -/// - "double": A double line box. -/// - "rounded": Like "single", but with rounded corners ("╭" etc.). -/// - "solid": Adds padding by a single whitespace cell. -/// - "shadow": A drop shadow effect by blending with the background. -/// - If it is an array, it should have a length of eight or any divisor of -/// eight. The array will specifify the eight chars building up the border -/// in a clockwise fashion starting with the top-left corner. As an -/// example, the double box style could be specified as -/// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ]. -/// If the number of chars are less than eight, they will be repeated. Thus -/// an ASCII border could be specified as -/// [ "/", "-", "\\", "|" ], -/// or all chars the same as -/// [ "x" ]. -/// An empty string can be used to turn off a specific border, for instance, -/// [ "", "", "", ">", "", "", "", "<" ] -/// will only make vertical borders but not horizontal ones. -/// By default, `FloatBorder` highlight is used, which links to `VertSplit` -/// when not defined. It could also be specified by character: -/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ]. -/// - `noautocmd`: If true then no buffer-related autocommand events such as -/// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from -/// calling this function. -/// -/// @param[out] err Error details, if any -/// -/// @return Window handle, or 0 on error -Window nvim_open_win(Buffer buffer, Boolean enter, Dictionary config, Error *err) - FUNC_API_SINCE(6) - FUNC_API_CHECK_TEXTLOCK -{ - FloatConfig fconfig = FLOAT_CONFIG_INIT; - if (!parse_float_config(config, &fconfig, false, true, err)) { - return 0; - } - win_T *wp = win_new_float(NULL, fconfig, err); - if (!wp) { - return 0; - } - if (enter) { - win_enter(wp, false); - } - if (!win_valid(wp)) { - api_set_error(err, kErrorTypeException, "Window was closed immediately"); - return 0; - } - if (buffer > 0) { - win_set_buf(wp->handle, buffer, fconfig.noautocmd, err); - } - - if (fconfig.style == kWinStyleMinimal) { - win_set_minimal_style(wp); - didset_window_options(wp); - } - return wp->handle; -} - /// Gets the current list of tabpage handles. /// /// @return List of tabpage handles @@ -1507,7 +1358,7 @@ void nvim_set_current_tabpage(Tabpage tabpage, Error *err) } } -/// Creates a new *namespace*, or gets an existing one. +/// Creates a new \*namespace\* or gets an existing one. /// /// Namespaces are used for buffer highlights and virtual text, see /// |nvim_buf_add_highlight()| and |nvim_buf_set_extmark()|. @@ -1758,24 +1609,15 @@ Dictionary nvim_get_color_map(void) /// @param[out] err Error details, if any /// /// @return map of global |context|. -Dictionary nvim_get_context(Dictionary opts, Error *err) +Dictionary nvim_get_context(Dict(context) *opts, Error *err) FUNC_API_SINCE(6) { Array types = ARRAY_DICT_INIT; - for (size_t i = 0; i < opts.size; i++) { - String k = opts.items[i].key; - Object v = opts.items[i].value; - if (strequal("types", k.data)) { - if (v.type != kObjectTypeArray) { - api_set_error(err, kErrorTypeValidation, "invalid value for key: %s", - k.data); - return (Dictionary)ARRAY_DICT_INIT; - } - types = v.data.array; - } else { - api_set_error(err, kErrorTypeValidation, "unexpected key: %s", k.data); - return (Dictionary)ARRAY_DICT_INIT; - } + if (opts->types.type == kObjectTypeArray) { + types = opts->types.data.array; + } else if (opts->types.type != kObjectTypeNil) { + api_set_error(err, kErrorTypeValidation, "invalid value for key: types"); + return (Dictionary)ARRAY_DICT_INIT; } int int_types = types.size > 0 ? 0 : kCtxAll; @@ -1885,7 +1727,7 @@ ArrayOf(Dictionary) nvim_get_keymap(String mode) /// as keys excluding |<buffer>| but including |noremap|. /// Values are Booleans. Unknown key is an error. /// @param[out] err Error details, if any. -void nvim_set_keymap(String mode, String lhs, String rhs, Dictionary opts, Error *err) +void nvim_set_keymap(String mode, String lhs, String rhs, Dict(keymap) *opts, Error *err) FUNC_API_SINCE(6) { modify_keymap(-1, false, mode, lhs, rhs, opts, err); @@ -1911,7 +1753,7 @@ void nvim_del_keymap(String mode, String lhs, Error *err) /// @param[out] err Error details, if any. /// /// @returns Map of maps describing commands. -Dictionary nvim_get_commands(Dictionary opts, Error *err) +Dictionary nvim_get_commands(Dict(get_commands) *opts, Error *err) FUNC_API_SINCE(4) { return nvim_buf_get_commands(-1, opts, err); @@ -2937,3 +2779,106 @@ void nvim_set_decoration_provider(Integer ns_id, DictionaryOf(LuaRef) opts, Erro error: decor_provider_clear(p); } + +/// Deletes a uppercase/file named mark. See |mark-motions|. +/// +/// @note fails with error if a lowercase or buffer local named mark is used. +/// @param name Mark name +/// @return true if the mark was deleted, else false. +/// @see |nvim_buf_del_mark()| +/// @see |nvim_get_mark()| +Boolean nvim_del_mark(String name, Error *err) + FUNC_API_SINCE(8) +{ + bool res = false; + if (name.size != 1) { + api_set_error(err, kErrorTypeValidation, + "Mark name must be a single character"); + return res; + } + // Only allow file/uppercase marks + // TODO(muniter): Refactor this ASCII_ISUPPER macro to a proper function + if (ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data)) { + res = set_mark(NULL, name, 0, 0, err); + } else { + api_set_error(err, kErrorTypeValidation, + "Only file/uppercase marks allowed, invalid mark name: '%c'", + *name.data); + } + return res; +} + +/// Return a tuple (row, col, buffer, buffername) representing the position of +/// the uppercase/file named mark. See |mark-motions|. +/// +/// Marks are (1,0)-indexed. |api-indexing| +/// +/// @note fails with error if a lowercase or buffer local named mark is used. +/// @param name Mark name +/// @return 4-tuple (row, col, buffer, buffername), (0, 0, 0, '') if the mark is +/// not set. +/// @see |nvim_buf_set_mark()| +/// @see |nvim_del_mark()| +Array nvim_get_mark(String name, Error *err) + FUNC_API_SINCE(8) +{ + Array rv = ARRAY_DICT_INIT; + + if (name.size != 1) { + api_set_error(err, kErrorTypeValidation, + "Mark name must be a single character"); + return rv; + } else if (!(ASCII_ISUPPER(*name.data) || ascii_isdigit(*name.data))) { + api_set_error(err, kErrorTypeValidation, + "Only file/uppercase marks allowed, invalid mark name: '%c'", + *name.data); + return rv; + } + + xfmark_T mark = get_global_mark(*name.data); + pos_T pos = mark.fmark.mark; + bool allocated = false; + int bufnr; + char *filename; + + // Marks are from an open buffer it fnum is non zero + if (mark.fmark.fnum != 0) { + bufnr = mark.fmark.fnum; + filename = (char *)buflist_nr2name(bufnr, true, true); + allocated = true; + // Marks comes from shada + } else { + filename = (char *)mark.fname; + bufnr = 0; + } + + bool exists = filename != NULL; + Integer row; + Integer col; + + if (!exists || pos.lnum <= 0) { + if (allocated) { + xfree(filename); + allocated = false; + } + filename = ""; + bufnr = 0; + row = 0; + col = 0; + } else { + row = pos.lnum; + col = pos.col; + } + + ADD(rv, INTEGER_OBJ(row)); + ADD(rv, INTEGER_OBJ(col)); + ADD(rv, INTEGER_OBJ(bufnr)); + ADD(rv, STRING_OBJ(cstr_to_string(filename))); + + if (allocated) { + xfree(filename); + } + + return rv; +} + diff --git a/src/nvim/api/win_config.c b/src/nvim/api/win_config.c new file mode 100644 index 0000000000..d82e7e8a03 --- /dev/null +++ b/src/nvim/api/win_config.c @@ -0,0 +1,639 @@ +// This is an open source non-commercial project. Dear PVS-Studio, please check +// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com + +#include <assert.h> +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> + +#include "nvim/api/private/defs.h" +#include "nvim/api/private/helpers.h" +#include "nvim/api/win_config.h" +#include "nvim/ascii.h" +#include "nvim/option.h" +#include "nvim/screen.h" +#include "nvim/strings.h" +#include "nvim/syntax.h" +#include "nvim/ui.h" +#include "nvim/window.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/win_config.c.generated.h" +#endif + + +/// Open a new window. +/// +/// Currently this is used to open floating and external windows. +/// Floats are windows that are drawn above the split layout, at some anchor +/// position in some other window. Floats can be drawn internally or by external +/// GUI with the |ui-multigrid| extension. External windows are only supported +/// with multigrid GUIs, and are displayed as separate top-level windows. +/// +/// For a general overview of floats, see |api-floatwin|. +/// +/// Exactly one of `external` and `relative` must be specified. The `width` and +/// `height` of the new window must be specified. +/// +/// With relative=editor (row=0,col=0) refers to the top-left corner of the +/// screen-grid and (row=Lines-1,col=Columns-1) refers to the bottom-right +/// corner. Fractional values are allowed, but the builtin implementation +/// (used by non-multigrid UIs) will always round down to nearest integer. +/// +/// Out-of-bounds values, and configurations that make the float not fit inside +/// the main editor, are allowed. The builtin implementation truncates values +/// so floats are fully within the main screen grid. External GUIs +/// could let floats hover outside of the main window like a tooltip, but +/// this should not be used to specify arbitrary WM screen positions. +/// +/// Example (Lua): window-relative float +/// <pre> +/// vim.api.nvim_open_win(0, false, +/// {relative='win', row=3, col=3, width=12, height=3}) +/// </pre> +/// +/// Example (Lua): buffer-relative float (travels as buffer is scrolled) +/// <pre> +/// vim.api.nvim_open_win(0, false, +/// {relative='win', width=12, height=3, bufpos={100,10}}) +/// </pre> +/// +/// @param buffer Buffer to display, or 0 for current buffer +/// @param enter Enter the window (make it the current window) +/// @param config Map defining the window configuration. Keys: +/// - `relative`: Sets the window layout to "floating", placed at (row,col) +/// coordinates relative to: +/// - "editor" The global editor grid +/// - "win" Window given by the `win` field, or current window. +/// - "cursor" Cursor position in current window. +/// - `win`: |window-ID| for relative="win". +/// - `anchor`: Decides which corner of the float to place at (row,col): +/// - "NW" northwest (default) +/// - "NE" northeast +/// - "SW" southwest +/// - "SE" southeast +/// - `width`: Window width (in character cells). Minimum of 1. +/// - `height`: Window height (in character cells). Minimum of 1. +/// - `bufpos`: Places float relative to buffer text (only when +/// relative="win"). Takes a tuple of zero-indexed [line, column]. +/// `row` and `col` if given are applied relative to this +/// position, else they default to: +/// - `row=1` and `col=0` if `anchor` is "NW" or "NE" +/// - `row=0` and `col=0` if `anchor` is "SW" or "SE" +/// (thus like a tooltip near the buffer text). +/// - `row`: Row position in units of "screen cell height", may be fractional. +/// - `col`: Column position in units of "screen cell width", may be +/// fractional. +/// - `focusable`: Enable focus by user actions (wincmds, mouse events). +/// Defaults to true. Non-focusable windows can be entered by +/// |nvim_set_current_win()|. +/// - `external`: GUI should display the window as an external +/// top-level window. Currently accepts no other positioning +/// configuration together with this. +/// - `zindex`: Stacking order. floats with higher `zindex` go on top on +/// floats with lower indices. Must be larger than zero. The +/// following screen elements have hard-coded z-indices: +/// - 100: insert completion popupmenu +/// - 200: message scrollback +/// - 250: cmdline completion popupmenu (when wildoptions+=pum) +/// The default value for floats are 50. In general, values below 100 are +/// recommended, unless there is a good reason to overshadow builtin +/// elements. +/// - `style`: Configure the appearance of the window. Currently only takes +/// one non-empty value: +/// - "minimal" Nvim will display the window with many UI options +/// disabled. This is useful when displaying a temporary +/// float where the text should not be edited. Disables +/// 'number', 'relativenumber', 'cursorline', 'cursorcolumn', +/// 'foldcolumn', 'spell' and 'list' options. 'signcolumn' +/// is changed to `auto` and 'colorcolumn' is cleared. The +/// end-of-buffer region is hidden by setting `eob` flag of +/// 'fillchars' to a space char, and clearing the +/// |EndOfBuffer| region in 'winhighlight'. +/// - `border`: Style of (optional) window border. This can either be a string +/// or an array. The string values are +/// - "none": No border (default). +/// - "single": A single line box. +/// - "double": A double line box. +/// - "rounded": Like "single", but with rounded corners ("╭" etc.). +/// - "solid": Adds padding by a single whitespace cell. +/// - "shadow": A drop shadow effect by blending with the background. +/// - If it is an array, it should have a length of eight or any divisor of +/// eight. The array will specifify the eight chars building up the border +/// in a clockwise fashion starting with the top-left corner. As an +/// example, the double box style could be specified as +/// [ "╔", "═" ,"╗", "║", "╝", "═", "╚", "║" ]. +/// If the number of chars are less than eight, they will be repeated. Thus +/// an ASCII border could be specified as +/// [ "/", "-", "\\", "|" ], +/// or all chars the same as +/// [ "x" ]. +/// An empty string can be used to turn off a specific border, for instance, +/// [ "", "", "", ">", "", "", "", "<" ] +/// will only make vertical borders but not horizontal ones. +/// By default, `FloatBorder` highlight is used, which links to `VertSplit` +/// when not defined. It could also be specified by character: +/// [ {"+", "MyCorner"}, {"x", "MyBorder"} ]. +/// - `noautocmd`: If true then no buffer-related autocommand events such as +/// |BufEnter|, |BufLeave| or |BufWinEnter| may fire from +/// calling this function. +/// +/// @param[out] err Error details, if any +/// +/// @return Window handle, or 0 on error +Window nvim_open_win(Buffer buffer, Boolean enter, Dict(float_config) *config, Error *err) + FUNC_API_SINCE(6) + FUNC_API_CHECK_TEXTLOCK +{ + FloatConfig fconfig = FLOAT_CONFIG_INIT; + if (!parse_float_config(config, &fconfig, false, true, err)) { + return 0; + } + win_T *wp = win_new_float(NULL, fconfig, err); + if (!wp) { + return 0; + } + if (enter) { + win_enter(wp, false); + } + // autocmds in win_enter or win_set_buf below may close the window + if (win_valid(wp) && buffer > 0) { + win_set_buf(wp->handle, buffer, fconfig.noautocmd, err); + } + if (!win_valid(wp)) { + api_set_error(err, kErrorTypeException, "Window was closed immediately"); + return 0; + } + + if (fconfig.style == kWinStyleMinimal) { + win_set_minimal_style(wp); + didset_window_options(wp); + } + return wp->handle; +} + +/// Configures window layout. Currently only for floating and external windows +/// (including changing a split window to those layouts). +/// +/// When reconfiguring a floating window, absent option keys will not be +/// changed. `row`/`col` and `relative` must be reconfigured together. +/// +/// @see |nvim_open_win()| +/// +/// @param window Window handle, or 0 for current window +/// @param config Map defining the window configuration, +/// see |nvim_open_win()| +/// @param[out] err Error details, if any +void nvim_win_set_config(Window window, Dict(float_config) *config, Error *err) + FUNC_API_SINCE(6) +{ + win_T *win = find_window_by_handle(window, err); + if (!win) { + return; + } + bool new_float = !win->w_floating; + // reuse old values, if not overridden + FloatConfig fconfig = new_float ? FLOAT_CONFIG_INIT : win->w_float_config; + + if (!parse_float_config(config, &fconfig, !new_float, false, err)) { + return; + } + if (new_float) { + if (!win_new_float(win, fconfig, err)) { + return; + } + redraw_later(win, NOT_VALID); + } else { + win_config_float(win, fconfig); + win->w_pos_changed = true; + } + if (fconfig.style == kWinStyleMinimal) { + win_set_minimal_style(win); + didset_window_options(win); + } +} + +/// Gets window configuration. +/// +/// The returned value may be given to |nvim_open_win()|. +/// +/// `relative` is empty for normal windows. +/// +/// @param window Window handle, or 0 for current window +/// @param[out] err Error details, if any +/// @return Map defining the window configuration, see |nvim_open_win()| +Dictionary nvim_win_get_config(Window window, Error *err) + FUNC_API_SINCE(6) +{ + Dictionary rv = ARRAY_DICT_INIT; + + win_T *wp = find_window_by_handle(window, err); + if (!wp) { + return rv; + } + + FloatConfig *config = &wp->w_float_config; + + PUT(rv, "focusable", BOOLEAN_OBJ(config->focusable)); + PUT(rv, "external", BOOLEAN_OBJ(config->external)); + + if (wp->w_floating) { + PUT(rv, "width", INTEGER_OBJ(config->width)); + PUT(rv, "height", INTEGER_OBJ(config->height)); + if (!config->external) { + if (config->relative == kFloatRelativeWindow) { + PUT(rv, "win", INTEGER_OBJ(config->window)); + if (config->bufpos.lnum >= 0) { + Array pos = ARRAY_DICT_INIT; + ADD(pos, INTEGER_OBJ(config->bufpos.lnum)); + ADD(pos, INTEGER_OBJ(config->bufpos.col)); + PUT(rv, "bufpos", ARRAY_OBJ(pos)); + } + } + PUT(rv, "anchor", STRING_OBJ(cstr_to_string(float_anchor_str[config->anchor]))); + PUT(rv, "row", FLOAT_OBJ(config->row)); + PUT(rv, "col", FLOAT_OBJ(config->col)); + PUT(rv, "zindex", INTEGER_OBJ(config->zindex)); + } + if (config->border) { + Array border = ARRAY_DICT_INIT; + for (size_t i = 0; i < 8; i++) { + Array tuple = ARRAY_DICT_INIT; + + String s = cstrn_to_string((const char *)config->border_chars[i], sizeof(schar_T)); + + int hi_id = config->border_hl_ids[i]; + char_u *hi_name = syn_id2name(hi_id); + if (hi_name[0]) { + ADD(tuple, STRING_OBJ(s)); + ADD(tuple, STRING_OBJ(cstr_to_string((const char *)hi_name))); + ADD(border, ARRAY_OBJ(tuple)); + } else { + ADD(border, STRING_OBJ(s)); + } + } + PUT(rv, "border", ARRAY_OBJ(border)); + } + } + + const char *rel = (wp->w_floating && !config->external + ? float_relative_str[config->relative] : ""); + PUT(rv, "relative", STRING_OBJ(cstr_to_string(rel))); + + return rv; +} + +static bool parse_float_anchor(String anchor, FloatAnchor *out) +{ + if (anchor.size == 0) { + *out = (FloatAnchor)0; + } + char *str = anchor.data; + if (striequal(str, "NW")) { + *out = 0; // NW is the default + } else if (striequal(str, "NE")) { + *out = kFloatAnchorEast; + } else if (striequal(str, "SW")) { + *out = kFloatAnchorSouth; + } else if (striequal(str, "SE")) { + *out = kFloatAnchorSouth | kFloatAnchorEast; + } else { + return false; + } + return true; +} + +static bool parse_float_relative(String relative, FloatRelative *out) +{ + char *str = relative.data; + if (striequal(str, "editor")) { + *out = kFloatRelativeEditor; + } else if (striequal(str, "win")) { + *out = kFloatRelativeWindow; + } else if (striequal(str, "cursor")) { + *out = kFloatRelativeCursor; + } else { + return false; + } + return true; +} + +static bool parse_float_bufpos(Array bufpos, lpos_T *out) +{ + if (bufpos.size != 2 + || bufpos.items[0].type != kObjectTypeInteger + || bufpos.items[1].type != kObjectTypeInteger) { + return false; + } + out->lnum = bufpos.items[0].data.integer; + out->col = (colnr_T)bufpos.items[1].data.integer; + return true; +} + +static void parse_border_style(Object style, FloatConfig *fconfig, Error *err) +{ + struct { + const char *name; + schar_T chars[8]; + bool shadow_color; + } defaults[] = { + { "double", { "╔", "═", "╗", "║", "╝", "═", "╚", "║" }, false }, + { "single", { "┌", "─", "┐", "│", "┘", "─", "└", "│" }, false }, + { "shadow", { "", "", " ", " ", " ", " ", " ", "" }, true }, + { "rounded", { "╭", "─", "╮", "│", "╯", "─", "╰", "│" }, false }, + { "solid", { " ", " ", " ", " ", " ", " ", " ", " " }, false }, + { NULL, { { NUL } }, false }, + }; + + schar_T *chars = fconfig->border_chars; + int *hl_ids = fconfig->border_hl_ids; + + fconfig->border = true; + + if (style.type == kObjectTypeArray) { + Array arr = style.data.array; + size_t size = arr.size; + if (!size || size > 8 || (size & (size-1))) { + api_set_error(err, kErrorTypeValidation, + "invalid number of border chars"); + return; + } + for (size_t i = 0; i < size; i++) { + Object iytem = arr.items[i]; + String string; + int hl_id = 0; + if (iytem.type == kObjectTypeArray) { + Array iarr = iytem.data.array; + if (!iarr.size || iarr.size > 2) { + api_set_error(err, kErrorTypeValidation, "invalid border char"); + return; + } + if (iarr.items[0].type != kObjectTypeString) { + api_set_error(err, kErrorTypeValidation, "invalid border char"); + return; + } + string = iarr.items[0].data.string; + if (iarr.size == 2) { + hl_id = object_to_hl_id(iarr.items[1], "border char highlight", err); + if (ERROR_SET(err)) { + return; + } + } + } else if (iytem.type == kObjectTypeString) { + string = iytem.data.string; + } else { + api_set_error(err, kErrorTypeValidation, "invalid border char"); + return; + } + if (string.size + && mb_string2cells_len((char_u *)string.data, string.size) > 1) { + api_set_error(err, kErrorTypeValidation, + "border chars must be one cell"); + return; + } + size_t len = MIN(string.size, sizeof(*chars)-1); + if (len) { + memcpy(chars[i], string.data, len); + } + chars[i][len] = NUL; + hl_ids[i] = hl_id; + } + while (size < 8) { + memcpy(chars+size, chars, sizeof(*chars) * size); + memcpy(hl_ids+size, hl_ids, sizeof(*hl_ids) * size); + size <<= 1; + } + if ((chars[7][0] && chars[1][0] && !chars[0][0]) + || (chars[1][0] && chars[3][0] && !chars[2][0]) + || (chars[3][0] && chars[5][0] && !chars[4][0]) + || (chars[5][0] && chars[7][0] && !chars[6][0])) { + api_set_error(err, kErrorTypeValidation, + "corner between used edges must be specified"); + } + } else if (style.type == kObjectTypeString) { + String str = style.data.string; + if (str.size == 0 || strequal(str.data, "none")) { + fconfig->border = false; + return; + } + for (size_t i = 0; defaults[i].name; i++) { + if (strequal(str.data, defaults[i].name)) { + memcpy(chars, defaults[i].chars, sizeof(defaults[i].chars)); + memset(hl_ids, 0, 8 * sizeof(*hl_ids)); + if (defaults[i].shadow_color) { + int hl_blend = SYN_GROUP_STATIC("FloatShadow"); + int hl_through = SYN_GROUP_STATIC("FloatShadowThrough"); + hl_ids[2] = hl_through; + hl_ids[3] = hl_blend; + hl_ids[4] = hl_blend; + hl_ids[5] = hl_blend; + hl_ids[6] = hl_through; + } + return; + } + } + api_set_error(err, kErrorTypeValidation, + "invalid border style \"%s\"", str.data); + } +} + +static bool parse_float_config(Dict(float_config) *config, FloatConfig *fconfig, bool reconf, + bool new_win, Error *err) +{ + bool has_relative = false, relative_is_win = false; + if (config->relative.type == kObjectTypeString) { + // ignore empty string, to match nvim_win_get_config + if (config->relative.data.string.size > 0) { + if (!parse_float_relative(config->relative.data.string, &fconfig->relative)) { + api_set_error(err, kErrorTypeValidation, "Invalid value of 'relative' key"); + return false; + } + + if (!(HAS_KEY(config->row) && HAS_KEY(config->col)) && !HAS_KEY(config->bufpos)) { + api_set_error(err, kErrorTypeValidation, + "'relative' requires 'row'/'col' or 'bufpos'"); + return false; + } + + has_relative = true; + fconfig->external = false; + if (fconfig->relative == kFloatRelativeWindow) { + relative_is_win = true; + fconfig->bufpos.lnum = -1; + } + } + } else if (HAS_KEY(config->relative)) { + api_set_error(err, kErrorTypeValidation, "'relative' key must be String"); + return false; + } + + if (config->anchor.type == kObjectTypeString) { + if (!parse_float_anchor(config->anchor.data.string, &fconfig->anchor)) { + api_set_error(err, kErrorTypeValidation, "Invalid value of 'anchor' key"); + return false; + } + } else if (HAS_KEY(config->anchor)) { + api_set_error(err, kErrorTypeValidation, "'anchor' key must be String"); + return false; + } + + if (HAS_KEY(config->row)) { + if (!has_relative) { + api_set_error(err, kErrorTypeValidation, "non-float cannot have 'row'"); + return false; + } else if (config->row.type == kObjectTypeInteger) { + fconfig->row = (double)config->row.data.integer; + } else if (config->row.type == kObjectTypeFloat) { + fconfig->row = config->row.data.floating; + } else { + api_set_error(err, kErrorTypeValidation, + "'row' key must be Integer or Float"); + return false; + } + } + + if (HAS_KEY(config->col)) { + if (!has_relative) { + api_set_error(err, kErrorTypeValidation, "non-float cannot have 'col'"); + return false; + } else if (config->col.type == kObjectTypeInteger) { + fconfig->col = (double)config->col.data.integer; + } else if (config->col.type == kObjectTypeFloat) { + fconfig->col = config->col.data.floating; + } else { + api_set_error(err, kErrorTypeValidation, + "'col' key must be Integer or Float"); + return false; + } + } + + if (HAS_KEY(config->bufpos)) { + if (!has_relative) { + api_set_error(err, kErrorTypeValidation, "non-float cannot have 'bufpos'"); + return false; + } else if (config->bufpos.type == kObjectTypeArray) { + if (!parse_float_bufpos(config->bufpos.data.array, &fconfig->bufpos)) { + api_set_error(err, kErrorTypeValidation, "Invalid value of 'bufpos' key"); + return false; + } + + if (!HAS_KEY(config->row)) { + fconfig->row = (fconfig->anchor & kFloatAnchorSouth) ? 0 : 1; + } + if (!HAS_KEY(config->col)) { + fconfig->col = 0; + } + } else { + api_set_error(err, kErrorTypeValidation, "'bufpos' key must be Array"); + return false; + } + } + + if (config->width.type == kObjectTypeInteger && config->width.data.integer > 0) { + fconfig->width = (int)config->width.data.integer; + } else if (HAS_KEY(config->width)) { + api_set_error(err, kErrorTypeValidation, "'width' key must be a positive Integer"); + return false; + } else if (!reconf) { + api_set_error(err, kErrorTypeValidation, "Must specify 'width'"); + return false; + } + + if (config->height.type == kObjectTypeInteger && config->height.data.integer > 0) { + fconfig->height = (int)config->height.data.integer; + } else if (HAS_KEY(config->height)) { + api_set_error(err, kErrorTypeValidation, "'height' key must be a positive Integer"); + return false; + } else if (!reconf) { + api_set_error(err, kErrorTypeValidation, "Must specify 'height'"); + return false; + } + + if (relative_is_win) { + fconfig->window = curwin->handle; + if (config->win.type == kObjectTypeInteger || config->win.type == kObjectTypeWindow) { + if (config->win.data.integer > 0) { + fconfig->window = (Window)config->win.data.integer; + } + } else if (HAS_KEY(config->win)) { + api_set_error(err, kErrorTypeValidation, "'win' key must be Integer or Window"); + return false; + } + } else { + if (HAS_KEY(config->win)) { + api_set_error(err, kErrorTypeValidation, "'win' key is only valid with relative='win'"); + return false; + } + } + + if (HAS_KEY(config->external)) { + fconfig->external = api_object_to_bool(config->external, "'external' key", false, err); + if (ERROR_SET(err)) { + return false; + } + if (has_relative && fconfig->external) { + api_set_error(err, kErrorTypeValidation, + "Only one of 'relative' and 'external' must be used"); + return false; + } + if (fconfig->external && !ui_has(kUIMultigrid)) { + api_set_error(err, kErrorTypeValidation, + "UI doesn't support external windows"); + return false; + } + } + + if (!reconf && (!has_relative && !fconfig->external)) { + api_set_error(err, kErrorTypeValidation, + "One of 'relative' and 'external' must be used"); + return false; + } + + + if (HAS_KEY(config->focusable)) { + fconfig->focusable = api_object_to_bool(config->focusable, "'focusable' key", false, err); + if (ERROR_SET(err)) { + return false; + } + } + + if (config->zindex.type == kObjectTypeInteger && config->zindex.data.integer > 0) { + fconfig->zindex = (int)config->zindex.data.integer; + } else if (HAS_KEY(config->zindex)) { + api_set_error(err, kErrorTypeValidation, "'zindex' key must be a positive Integer"); + return false; + } + + if (HAS_KEY(config->border)) { + parse_border_style(config->border, fconfig, err); + if (ERROR_SET(err)) { + return false; + } + } + + if (config->style.type == kObjectTypeString) { + if (config->style.data.string.data[0] == NUL) { + fconfig->style = kWinStyleUnused; + } else if (striequal(config->style.data.string.data, "minimal")) { + fconfig->style = kWinStyleMinimal; + } else { + api_set_error(err, kErrorTypeValidation, "Invalid value of 'style' key"); + } + } else if (HAS_KEY(config->style)) { + api_set_error(err, kErrorTypeValidation, "'style' key must be String"); + return false; + } + + if (HAS_KEY(config->noautocmd)) { + if (!new_win) { + api_set_error(err, kErrorTypeValidation, "Invalid key: 'noautocmd'"); + return false; + } + fconfig->noautocmd = api_object_to_bool(config->noautocmd, "'noautocmd' key", false, err); + if (ERROR_SET(err)) { + return false; + } + } + + return true; +} diff --git a/src/nvim/api/win_config.h b/src/nvim/api/win_config.h new file mode 100644 index 0000000000..9271c35f23 --- /dev/null +++ b/src/nvim/api/win_config.h @@ -0,0 +1,11 @@ +#ifndef NVIM_API_WIN_CONFIG_H +#define NVIM_API_WIN_CONFIG_H + +#include <stdint.h> + +#include "nvim/api/private/defs.h" + +#ifdef INCLUDE_GENERATED_DECLARATIONS +# include "api/win_config.h.generated.h" +#endif +#endif // NVIM_API_WIN_CONFIG_H diff --git a/src/nvim/api/window.c b/src/nvim/api/window.c index 99ba297111..6e68c057dc 100644 --- a/src/nvim/api/window.c +++ b/src/nvim/api/window.c @@ -373,117 +373,6 @@ Boolean nvim_win_is_valid(Window window) } -/// Configures window layout. Currently only for floating and external windows -/// (including changing a split window to those layouts). -/// -/// When reconfiguring a floating window, absent option keys will not be -/// changed. `row`/`col` and `relative` must be reconfigured together. -/// -/// @see |nvim_open_win()| -/// -/// @param window Window handle, or 0 for current window -/// @param config Map defining the window configuration, -/// see |nvim_open_win()| -/// @param[out] err Error details, if any -void nvim_win_set_config(Window window, Dictionary config, Error *err) - FUNC_API_SINCE(6) -{ - win_T *win = find_window_by_handle(window, err); - if (!win) { - return; - } - bool new_float = !win->w_floating; - // reuse old values, if not overridden - FloatConfig fconfig = new_float ? FLOAT_CONFIG_INIT : win->w_float_config; - - if (!parse_float_config(config, &fconfig, !new_float, false, err)) { - return; - } - if (new_float) { - if (!win_new_float(win, fconfig, err)) { - return; - } - redraw_later(win, NOT_VALID); - } else { - win_config_float(win, fconfig); - win->w_pos_changed = true; - } - if (fconfig.style == kWinStyleMinimal) { - win_set_minimal_style(win); - didset_window_options(win); - } -} - -/// Gets window configuration. -/// -/// The returned value may be given to |nvim_open_win()|. -/// -/// `relative` is empty for normal windows. -/// -/// @param window Window handle, or 0 for current window -/// @param[out] err Error details, if any -/// @return Map defining the window configuration, see |nvim_open_win()| -Dictionary nvim_win_get_config(Window window, Error *err) - FUNC_API_SINCE(6) -{ - Dictionary rv = ARRAY_DICT_INIT; - - win_T *wp = find_window_by_handle(window, err); - if (!wp) { - return rv; - } - - FloatConfig *config = &wp->w_float_config; - - PUT(rv, "focusable", BOOLEAN_OBJ(config->focusable)); - PUT(rv, "external", BOOLEAN_OBJ(config->external)); - - if (wp->w_floating) { - PUT(rv, "width", INTEGER_OBJ(config->width)); - PUT(rv, "height", INTEGER_OBJ(config->height)); - if (!config->external) { - if (config->relative == kFloatRelativeWindow) { - PUT(rv, "win", INTEGER_OBJ(config->window)); - if (config->bufpos.lnum >= 0) { - Array pos = ARRAY_DICT_INIT; - ADD(pos, INTEGER_OBJ(config->bufpos.lnum)); - ADD(pos, INTEGER_OBJ(config->bufpos.col)); - PUT(rv, "bufpos", ARRAY_OBJ(pos)); - } - } - PUT(rv, "anchor", STRING_OBJ(cstr_to_string(float_anchor_str[config->anchor]))); - PUT(rv, "row", FLOAT_OBJ(config->row)); - PUT(rv, "col", FLOAT_OBJ(config->col)); - PUT(rv, "zindex", INTEGER_OBJ(config->zindex)); - } - if (config->border) { - Array border = ARRAY_DICT_INIT; - for (size_t i = 0; i < 8; i++) { - Array tuple = ARRAY_DICT_INIT; - - String s = cstrn_to_string((const char *)config->border_chars[i], sizeof(schar_T)); - - int hi_id = config->border_hl_ids[i]; - char_u *hi_name = syn_id2name(hi_id); - if (hi_name[0]) { - ADD(tuple, STRING_OBJ(s)); - ADD(tuple, STRING_OBJ(cstr_to_string((const char *)hi_name))); - ADD(border, ARRAY_OBJ(tuple)); - } else { - ADD(border, STRING_OBJ(s)); - } - } - PUT(rv, "border", ARRAY_OBJ(border)); - } - } - - const char *rel = (wp->w_floating && !config->external - ? float_relative_str[config->relative] : ""); - PUT(rv, "relative", STRING_OBJ(cstr_to_string(rel))); - - return rv; -} - /// Closes the window and hide the buffer it contains (like |:hide| with a /// |window-ID|). /// diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index e7b2ad9000..d991b88131 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -199,7 +199,7 @@ static void au_cleanup(void) } // Loop over all events. - for (event = (event_T)0; (int)event < (int)NUM_EVENTS; + for (event = (event_T)0; (int)event < NUM_EVENTS; event = (event_T)((int)event + 1)) { // Loop over all autocommand patterns. prev_ap = &(first_autopat[(int)event]); @@ -266,7 +266,7 @@ void aubuflocal_remove(buf_T *buf) } // invalidate buflocals looping through events - for (event = (event_T)0; (int)event < (int)NUM_EVENTS; + for (event = (event_T)0; (int)event < NUM_EVENTS; event = (event_T)((int)event + 1)) { // loop over all autocommand patterns for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) { @@ -321,7 +321,7 @@ static void au_del_group(char_u *name) AutoPat *ap; int in_use = false; - for (event = (event_T)0; (int)event < (int)NUM_EVENTS; + for (event = (event_T)0; (int)event < NUM_EVENTS; event = (event_T)((int)event + 1)) { for (ap = first_autopat[(int)event]; ap != NULL; ap = ap->next) { if (ap->group == i && ap->pat != NULL) { @@ -475,7 +475,7 @@ static char_u *find_end_event(char_u *arg, int have_group) pat = arg + 1; } else { for (pat = arg; *pat && *pat != '|' && !ascii_iswhite(*pat); pat = p) { - if ((int)event_name2nr(pat, &p) >= (int)NUM_EVENTS) { + if ((int)event_name2nr(pat, &p) >= NUM_EVENTS) { if (have_group) { EMSG2(_("E216: No such event: %s"), pat); } else { @@ -701,7 +701,7 @@ void do_autocmd(char_u *arg_in, int forceit) if (!forceit && *cmd != NUL) { EMSG(_(e_cannot_define_autocommands_for_all_events)); } else { - for (event_T event = (event_T)0; event < (int)NUM_EVENTS; + for (event_T event = (event_T)0; event < NUM_EVENTS; event = (event_T)(event + 1)) { if (do_autocmd_event(event, pat, once, nested, cmd, forceit, group) == FAIL) { diff --git a/src/nvim/buffer.c b/src/nvim/buffer.c index 3c86f55260..20dd94622f 100644 --- a/src/nvim/buffer.c +++ b/src/nvim/buffer.c @@ -117,7 +117,7 @@ static int read_buffer(int read_stdin, exarg_T *eap, int flags) line_count = curbuf->b_ml.ml_line_count; retval = readfile(read_stdin ? NULL : curbuf->b_ffname, read_stdin ? NULL : curbuf->b_fname, - (linenr_T)line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap, + line_count, (linenr_T)0, (linenr_T)MAXLNUM, eap, flags | READ_BUFFER); if (retval == OK) { // Delete the binary lines. diff --git a/src/nvim/charset.c b/src/nvim/charset.c index f899ebf57c..d2f95ad81c 100644 --- a/src/nvim/charset.c +++ b/src/nvim/charset.c @@ -412,7 +412,7 @@ char *transstr(const char *const s, bool untab) { // Compute the length of the result, taking account of unprintable // multi-byte characters. - const size_t len = transstr_len((const char *)s, untab) + 1; + const size_t len = transstr_len(s, untab) + 1; char *const buf = xmalloc(len); transstr_buf(s, buf, len, untab); return buf; diff --git a/src/nvim/debugger.c b/src/nvim/debugger.c index 0ddf163176..58b1d9ce7f 100644 --- a/src/nvim/debugger.c +++ b/src/nvim/debugger.c @@ -398,7 +398,7 @@ void dbg_check_breakpoint(exarg_T *eap) // replace K_SNR with "<SNR>" if (debug_breakpoint_name[0] == K_SPECIAL && debug_breakpoint_name[1] == KS_EXTRA - && debug_breakpoint_name[2] == (int)KE_SNR) { + && debug_breakpoint_name[2] == KE_SNR) { p = (char_u *)"<SNR>"; } else { p = (char_u *)""; diff --git a/src/nvim/decoration.c b/src/nvim/decoration.c index 561be9968a..4e80528c74 100644 --- a/src/nvim/decoration.c +++ b/src/nvim/decoration.c @@ -421,11 +421,11 @@ int decor_virtual_lines(win_T *wp, linenr_T lnum) return 0; } if (buf->b_virt_line_pos < 0) { - mtpos_t pos = marktree_lookup(buf->b_marktree, buf->b_virt_line_mark, NULL); - if (pos.row < 0) { - buf->b_virt_line_mark = 0; - } - buf->b_virt_line_pos = pos.row + (buf->b_virt_line_above ? 0 : 1); + mtpos_t pos = marktree_lookup(buf->b_marktree, buf->b_virt_line_mark, NULL); + if (pos.row < 0) { + buf->b_virt_line_mark = 0; + } + buf->b_virt_line_pos = pos.row + (buf->b_virt_line_above ? 0 : 1); } return (lnum-1 == buf->b_virt_line_pos) ? (int)kv_size(buf->b_virt_lines) : 0; diff --git a/src/nvim/diff.c b/src/nvim/diff.c index 5c43b2498e..3a7bd21c70 100644 --- a/src/nvim/diff.c +++ b/src/nvim/diff.c @@ -1110,7 +1110,7 @@ static int diff_file(diffio_T *dio) // Build the diff command and execute it. Always use -a, binary // differences are of no use. Ignore errors, diff returns // non-zero when differences have been found. - vim_snprintf((char *)cmd, len, "diff %s%s%s%s%s%s%s%s %s", + vim_snprintf(cmd, len, "diff %s%s%s%s%s%s%s%s %s", diff_a_works == kFalse ? "" : "-a ", "", (diff_flags & DIFF_IWHITE) ? "-b " : "", diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 45edbec4a6..5ac733285d 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -116,7 +116,7 @@ static char *ctrl_x_msgs[] = static char *ctrl_x_mode_names[] = { "keyword", "ctrl_x", - "unknown", // CTRL_X_SCROLL + "scroll", "whole_line", "files", "tags", @@ -3329,7 +3329,7 @@ void get_complete_info(list_T *what_list, dict_T *retdict) // Return Insert completion mode name string static char_u *ins_compl_mode(void) { - if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || compl_started) { + if (ctrl_x_mode == CTRL_X_NOT_DEFINED_YET || ctrl_x_mode == CTRL_X_SCROLL || compl_started) { return (char_u *)ctrl_x_mode_names[ctrl_x_mode & ~CTRL_X_WANT_IDENT]; } return (char_u *)""; diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 768b82b464..a281c09042 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -514,8 +514,8 @@ int var_redir_start(char_u *name, int append) ga_init(&redir_ga, (int)sizeof(char), 500); // Parse the variable name (can be a dict or list entry). - redir_endp = (char_u *)get_lval(redir_varname, NULL, redir_lval, false, false, - 0, FNE_CHECK_START); + redir_endp = get_lval(redir_varname, NULL, redir_lval, false, false, + 0, FNE_CHECK_START); if (redir_endp == NULL || redir_lval->ll_name == NULL || *redir_endp != NUL) { clear_lval(redir_lval); @@ -597,8 +597,8 @@ void var_redir_stop(void) tv.vval.v_string = redir_ga.ga_data; // Call get_lval() again, if it's inside a Dict or List it may // have changed. - redir_endp = (char_u *)get_lval(redir_varname, NULL, redir_lval, - false, false, 0, FNE_CHECK_START); + redir_endp = get_lval(redir_varname, NULL, redir_lval, + false, false, 0, FNE_CHECK_START); if (redir_endp != NULL && redir_lval->ll_name != NULL) { set_var_lval(redir_lval, redir_endp, &tv, false, false, "."); } @@ -1711,7 +1711,7 @@ static const char *list_arg_vars(exarg_T *eap, const char *arg, int *first) if (tofree != NULL) { name = tofree; } - if (get_var_tv((const char *)name, len, &tv, NULL, true, false) + if (get_var_tv(name, len, &tv, NULL, true, false) == FAIL) { error = true; } else { @@ -2023,7 +2023,7 @@ char_u *get_lval(char_u *const name, typval_T *const rettv, lval_T *const lp, co } lp->ll_exp_name = (char *)make_expanded_name(name, expr_start, expr_end, - (char_u *)p); + p); lp->ll_name = lp->ll_exp_name; if (lp->ll_exp_name == NULL) { /* Report an invalid expression in braces, unless the @@ -2419,7 +2419,7 @@ static void set_var_lval(lval_T *lp, char_u *endp, typval_T *rettv, int copy, co // handle +=, -=, *=, /=, %= and .= di = NULL; - if (get_var_tv((const char *)lp->ll_name, (int)STRLEN(lp->ll_name), + if (get_var_tv(lp->ll_name, (int)STRLEN(lp->ll_name), &tv, &di, true, false) == OK) { if ((di == NULL || (!var_check_ro(di->di_flags, lp->ll_name, TV_CSTRING) @@ -3004,12 +3004,12 @@ int do_unlet(const char *const name, const size_t name_len, const bool forceit) hashitem_T *hi = hash_find(ht, (const char_u *)varname); if (HASHITEM_EMPTY(hi)) { - hi = find_hi_in_scoped_ht((const char *)name, &ht); + hi = find_hi_in_scoped_ht(name, &ht); } if (hi != NULL && !HASHITEM_EMPTY(hi)) { dictitem_T *const di = TV_DICT_HI2DI(hi); - if (var_check_fixed(di->di_flags, (const char *)name, TV_CSTRING) - || var_check_ro(di->di_flags, (const char *)name, TV_CSTRING) + if (var_check_fixed(di->di_flags, name, TV_CSTRING) + || var_check_ro(di->di_flags, name, TV_CSTRING) || var_check_lock(d->dv_lock, name, TV_CSTRING)) { return FAIL; } @@ -3069,7 +3069,7 @@ static int do_lock_var(lval_T *lp, char_u *name_end FUNC_ATTR_UNUSED, exarg_T *e ret = FAIL; } else { // Normal name or expanded name. - dictitem_T *const di = find_var((const char *)lp->ll_name, lp->ll_name_len, NULL, + dictitem_T *const di = find_var(lp->ll_name, lp->ll_name_len, NULL, true); if (di == NULL) { ret = FAIL; @@ -4348,7 +4348,7 @@ static int call_func_rettv(char_u **const arg, typval_T *const rettv, const bool funcexe.selfdict = selfdict; funcexe.basetv = basetv; const int ret = get_func_tv(funcname, is_lua ? *arg - funcname : -1, rettv, - (char_u **)arg, &funcexe); + arg, &funcexe); // Clear the funcref afterwards, so that deleting it while // evaluating the arguments is possible (see test55). @@ -9444,7 +9444,7 @@ static void set_var_const(const char *name, const size_t name_len, typval_T *con // Search in parent scope which is possible to reference from lambda if (v == NULL) { - v = find_var_in_scoped_ht((const char *)name, name_len, true); + v = find_var_in_scoped_ht(name, name_len, true); } if (tv_is_func(*tv) && !var_check_func_name(name, v == NULL)) { @@ -9654,7 +9654,7 @@ bool var_check_func_name(const char *const name, const bool new_var) // Don't allow hiding a function. When "v" is not NULL we might be // assigning another function to the same var, the type is checked // below. - if (new_var && function_exists((const char *)name, false)) { + if (new_var && function_exists(name, false)) { EMSG2(_("E705: Variable name conflicts with existing function: %s"), name); return false; @@ -11325,7 +11325,7 @@ bool var_exists(const char *var) // get_name_len() takes care of expanding curly braces const char *name = var; - const int len = get_name_len((const char **)&var, &tofree, true, false); + const int len = get_name_len(&var, &tofree, true, false); if (len > 0) { typval_T tv; diff --git a/src/nvim/eval/encode.c b/src/nvim/eval/encode.c index 1c0afc89f5..5ef0045659 100644 --- a/src/nvim/eval/encode.c +++ b/src/nvim/eval/encode.c @@ -268,9 +268,8 @@ int encode_read_from_list(ListReaderState *const state, char *const buf, const s || TV_LIST_ITEM_TV(state->li)->vval.v_string != NULL); for (size_t i = state->offset; i < state->li_length && p < buf_end; i++) { assert(TV_LIST_ITEM_TV(state->li)->vval.v_string != NULL); - const char ch = (char)( - TV_LIST_ITEM_TV(state->li)->vval.v_string[state->offset++]); - *p++ = (char)((char)ch == (char)NL ? (char)NUL : (char)ch); + const char ch = (char)(TV_LIST_ITEM_TV(state->li)->vval.v_string[state->offset++]); + *p++ = (char)(ch == (char)NL ? (char)NUL : ch); } if (p < buf_end) { state->li = TV_LIST_ITEM_NEXT(state->list, state->li); diff --git a/src/nvim/eval/funcs.c b/src/nvim/eval/funcs.c index 5569d74413..50e0b0b258 100644 --- a/src/nvim/eval/funcs.c +++ b/src/nvim/eval/funcs.c @@ -5149,7 +5149,7 @@ static void f_islocked(typval_T *argvars, typval_T *rettv, FunPtr fptr) EMSG(_(e_trailing)); } else { if (lv.ll_tv == NULL) { - di = find_var((const char *)lv.ll_name, lv.ll_name_len, NULL, true); + di = find_var(lv.ll_name, lv.ll_name_len, NULL, true); if (di != NULL) { // Consider a variable locked when: // 1. the variable itself is locked @@ -5984,7 +5984,7 @@ static void get_maparg(typval_T *argvars, typval_T *rettv, int exact) static void f_luaeval(typval_T *argvars, typval_T *rettv, FunPtr fptr) FUNC_ATTR_NONNULL_ALL { - const char *const str = (const char *)tv_get_string_chk(&argvars[0]); + const char *const str = tv_get_string_chk(&argvars[0]); if (str == NULL) { return; } @@ -11358,7 +11358,7 @@ static void f_termopen(typval_T *argvars, typval_T *rettv, FunPtr fptr) if (new_cwd && *new_cwd != NUL) { cwd = new_cwd; // The new cwd must be a directory. - if (!os_isdir_executable((const char *)cwd)) { + if (!os_isdir_executable(cwd)) { EMSG2(_(e_invarg2), "expected valid directory"); shell_free_argv(argv); return; diff --git a/src/nvim/eval/typval.c b/src/nvim/eval/typval.c index 075b50a366..4c8789964f 100644 --- a/src/nvim/eval/typval.c +++ b/src/nvim/eval/typval.c @@ -3260,7 +3260,7 @@ const char *tv_get_string(const typval_T *const tv) const char *tv_get_string_buf(const typval_T *const tv, char *const buf) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_NONNULL_RET FUNC_ATTR_WARN_UNUSED_RESULT { - const char *const res = (const char *)tv_get_string_buf_chk(tv, buf); + const char *const res = tv_get_string_buf_chk(tv, buf); return res != NULL ? res : ""; } diff --git a/src/nvim/ex_getln.c b/src/nvim/ex_getln.c index a9990df58f..f4f07e0680 100644 --- a/src/nvim/ex_getln.c +++ b/src/nvim/ex_getln.c @@ -230,7 +230,22 @@ static int compl_match_arraysize; static int compl_startcol; static int compl_selected; +/// |:checkhealth| completion items +/// +/// Regenerates on every new command line prompt, to accomodate changes on the +/// runtime files. +typedef struct { + garray_T names; // healthcheck names + unsigned last_gen; // last_prompt_id where names were generated +} CheckhealthComp; + +/// Cookie used when converting filepath to name +struct healthchecks_cookie { + garray_T *names; // global healthchecks + bool is_lua; // true if the current entry is a Lua healthcheck +}; +static CheckhealthComp healthchecks = { GA_INIT(sizeof(char_u *), 10), 0 }; #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ex_getln.c.generated.h" @@ -273,6 +288,68 @@ static void init_incsearch_state(incsearch_state_T *s) save_viewstate(&s->old_viewstate); } +/// Completion for |:checkhealth| command. +/// +/// Given to ExpandGeneric() to obtain all available heathcheck names. +/// @param[in] idx Index of the healthcheck item. +/// @param[in] xp Not used. +static char_u *get_healthcheck_names(expand_T *xp, int idx) +{ + // Generate the first time or on new prompt. + if (healthchecks.last_gen == 0 || healthchecks.last_gen != last_prompt_id) { + ga_clear_strings(&healthchecks.names); + char *patterns[3] = { "autoload/health/**.vim", "lua/**/**/health/init.lua", // NOLINT + "lua/**/**/health.lua" }; // NOLINT + for (int i = 0; i < 3; i++) { + struct healthchecks_cookie hcookie = { .names = &healthchecks.names, .is_lua = i != 0 }; + do_in_runtimepath((char_u *)patterns[i], DIP_ALL, get_healthcheck_cb, &hcookie); + + if (healthchecks.names.ga_len > 0) { + ga_remove_duplicate_strings(&healthchecks.names); + } + } + // Tracked to regenerate items on next prompt. + healthchecks.last_gen = last_prompt_id; + } + return idx < + (int)healthchecks.names.ga_len ? ((char_u **)(healthchecks.names.ga_data))[idx] : NULL; +} + +/// Transform healthcheck file path into it's name. +/// +/// Used as a callback for do_in_runtimepath +/// @param[in] path Expanded path to a possible healthcheck. +/// @param[out] cookie Array where names will be inserted. +static void get_healthcheck_cb(char_u *path, void *cookie) +{ + if (path != NULL) { + struct healthchecks_cookie *hcookie = (struct healthchecks_cookie *)cookie; + char *pattern; + char *sub = "\\1"; + char_u *res; + + if (hcookie->is_lua) { + // Lua: transform "../lua/vim/lsp/health.lua" into "vim.lsp" + pattern = ".*lua[\\/]\\(.\\{-}\\)[\\/]health\\([\\/]init\\)\\?\\.lua$"; + } else { + // Vim: transform "../autoload/health/provider.vim" into "provider" + pattern = ".*[\\/]\\([^\\/]*\\)\\.vim$"; + } + + res = do_string_sub(path, (char_u *)pattern, (char_u *)sub, NULL, (char_u *)"g"); + if (hcookie->is_lua && res != NULL) { + // Replace slashes with dots as represented by the healthcheck plugin. + char_u *ares = do_string_sub(res, (char_u *)"[\\/]", (char_u *)".", NULL, (char_u *)"g"); + xfree(res); + res = ares; + } + + if (res != NULL) { + GA_APPEND(char_u *, hcookie->names, res); + } + } +} + // Return true when 'incsearch' highlighting is to be done. // Sets search_first_line and search_last_line to the address range. static bool do_incsearch_highlighting(int firstc, int *search_delim, incsearch_state_T *s, @@ -3037,7 +3114,7 @@ static void ui_ext_cmdline_show(CmdlineInfo *line) line->cmdindent, line->level); if (line->special_char) { - ui_call_cmdline_special_char(cchar_to_string((char)(line->special_char)), + ui_call_cmdline_special_char(cchar_to_string(line->special_char), line->special_shift, line->level); } @@ -3135,7 +3212,7 @@ void putcmdline(char c, int shift) } msg_no_more = false; } else if (ccline.redraw_state != kCmdRedrawAll) { - ui_call_cmdline_special_char(cchar_to_string((char)(c)), shift, + ui_call_cmdline_special_char(cchar_to_string(c), shift, ccline.level); } cursorcmd(); @@ -4902,10 +4979,6 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u ** char *directories[] = { "syntax", "indent", "ftplugin", NULL }; return ExpandRTDir(pat, DIP_LUA, num_file, file, directories); } - if (xp->xp_context == EXPAND_CHECKHEALTH) { - char *directories[] = { "autoload/health", NULL }; - return ExpandRTDir(pat, 0, num_file, file, directories); - } if (xp->xp_context == EXPAND_USER_LIST) { return ExpandUserList(xp, num_file, file); } @@ -4982,6 +5055,7 @@ static int ExpandFromContext(expand_T *xp, char_u *pat, int *num_file, char_u ** { EXPAND_ENV_VARS, get_env_name, true, true }, { EXPAND_USER, get_users, true, false }, { EXPAND_ARGLIST, get_arglist_name, true, false }, + { EXPAND_CHECKHEALTH, get_healthcheck_names, true, false }, }; int i; diff --git a/src/nvim/generators/c_grammar.lua b/src/nvim/generators/c_grammar.lua index c9ab0cf709..a5f76e1c6a 100644 --- a/src/nvim/generators/c_grammar.lua +++ b/src/nvim/generators/c_grammar.lua @@ -17,7 +17,7 @@ local fill = ws ^ 0 local c_comment = P('//') * (not_nl ^ 0) local c_preproc = P('#') * (not_nl ^ 0) local typed_container = - (P('ArrayOf(') + P('DictionaryOf(')) * ((any - P(')')) ^ 1) * P(')') + (P('ArrayOf(') + P('DictionaryOf(') + P('Dict(')) * ((any - P(')')) ^ 1) * P(')') local c_id = ( typed_container + (letter * (alpha ^ 0)) diff --git a/src/nvim/generators/gen_api_dispatch.lua b/src/nvim/generators/gen_api_dispatch.lua index 99d80cdebc..e38a0af0ec 100644 --- a/src/nvim/generators/gen_api_dispatch.lua +++ b/src/nvim/generators/gen_api_dispatch.lua @@ -33,6 +33,10 @@ local function_names = {} local c_grammar = require('generators.c_grammar') +local function startswith(String,Start) + return string.sub(String,1,string.len(Start))==Start +end + -- read each input file, parse and append to the api metadata for i = 6, #arg do local full_path = arg[i] @@ -47,7 +51,8 @@ for i = 6, #arg do local tmp = c_grammar.grammar:match(input:read('*all')) for j = 1, #tmp do local fn = tmp[j] - if not fn.noexport then + local public = startswith(fn.name, "nvim_") or fn.deprecated_since + if public and not fn.noexport then functions[#functions + 1] = tmp[j] function_names[fn.name] = true if #fn.parameters ~= 0 and fn.parameters[1][2] == 'channel_id' then @@ -76,10 +81,6 @@ local function shallowcopy(orig) return copy end -local function startswith(String,Start) - return string.sub(String,1,string.len(Start))==Start -end - -- Export functions under older deprecated names. -- These will be removed eventually. local deprecated_aliases = require("api.dispatch_deprecated") @@ -108,9 +109,10 @@ for _,f in ipairs(shallowcopy(functions)) do f.lua = f.lua_only or not f.remote_only f.eval = (not f.lua_only) and (not f.remote_only) else + f.deprecated_since = tonumber(f.deprecated_since) + assert(f.deprecated_since == 1) f.remote = true f.since = 0 - f.deprecated_since = 1 end f.method = ismethod local newname = deprecated_aliases[f.name] @@ -152,6 +154,8 @@ for _,f in ipairs(functions) do for i,param in ipairs(f.parameters) do if param[1] == "DictionaryOf(LuaRef)" then param = {"Dictionary", param[2]} + elseif startswith(param[1], "Dict(") then + param = {"Dictionary", param[2]} end f_exported.parameters[i] = param end @@ -173,7 +177,10 @@ local output = io.open(dispatch_outputf, 'wb') local function real_type(type) local rv = type - if c_grammar.typed_container:match(rv) then + local rmatch = string.match(type, "Dict%(([_%w]+)%)") + if rmatch then + return "KeyDict_"..rmatch + elseif c_grammar.typed_container:match(rv) then if rv:match('Array') then rv = 'Array' else @@ -209,8 +216,9 @@ for i = 1, #functions do -- Declare/initialize variables that will hold converted arguments for j = 1, #fn.parameters do local param = fn.parameters[j] + local rt = real_type(param[1]) local converted = 'arg_'..j - output:write('\n '..param[1]..' '..converted..';') + output:write('\n '..rt..' '..converted..';') end output:write('\n') output:write('\n if (args.size != '..#fn.parameters..') {') @@ -225,7 +233,24 @@ for i = 1, #functions do param = fn.parameters[j] converted = 'arg_'..j local rt = real_type(param[1]) - if rt ~= 'Object' then + if rt == 'Object' then + output:write('\n '..converted..' = args.items['..(j - 1)..'];\n') + elseif rt:match('^KeyDict_') then + converted = '&' .. converted + output:write('\n if (args.items['..(j - 1)..'].type == kObjectTypeDictionary) {') --luacheck: ignore 631 + output:write('\n memset('..converted..', 0, sizeof(*'..converted..'));') -- TODO: neeeee + output:write('\n if (!api_dict_to_keydict('..converted..', '..rt..'_get_field, args.items['..(j - 1)..'].data.dictionary, error)) {') + output:write('\n goto cleanup;') + output:write('\n }') + output:write('\n } else if (args.items['..(j - 1)..'].type == kObjectTypeArray && args.items['..(j - 1)..'].data.array.size == 0) {') --luacheck: ignore 631 + output:write('\n memset('..converted..', 0, sizeof(*'..converted..'));') + + output:write('\n } else {') + output:write('\n api_set_error(error, kErrorTypeException, \ + "Wrong type for argument '..j..' when calling '..fn.name..', expecting '..param[1]..'");') + output:write('\n goto cleanup;') + output:write('\n }\n') + else if rt:match('^Buffer$') or rt:match('^Window$') or rt:match('^Tabpage$') then -- Buffer, Window, and Tabpage have a specific type, but are stored in integer output:write('\n if (args.items['.. @@ -257,10 +282,7 @@ for i = 1, #functions do "Wrong type for argument '..j..' when calling '..fn.name..', expecting '..param[1]..'");') output:write('\n goto cleanup;') output:write('\n }\n') - else - output:write('\n '..converted..' = args.items['..(j - 1)..'];\n') end - args[#args + 1] = converted end @@ -423,13 +445,24 @@ local function process_function(fn) if param[1] == "DictionaryOf(LuaRef)" then extra = "true, " end + local errshift = 0 + if string.match(param_type, '^KeyDict_') then + write_shifted_output(output, string.format([[ + %s %s = { 0 }; nlua_pop_keydict(lstate, &%s, %s_get_field, %s&err);]], param_type, cparam, cparam, param_type, extra)) + cparam = '&'..cparam + errshift = 1 -- free incomplete dict on error + else + write_shifted_output(output, string.format([[ + const %s %s = nlua_pop_%s(lstate, %s&err);]], param[1], cparam, param_type, extra)) + end + write_shifted_output(output, string.format([[ - const %s %s = nlua_pop_%s(lstate, %s&err); if (ERROR_SET(&err)) { goto exit_%u; } - ]], param[1], cparam, param_type, extra, #fn.parameters - j)) + + ]], #fn.parameters - j + errshift)) free_code[#free_code + 1] = ('api_free_%s(%s);'):format( lc_param_type, cparam) cparams = cparam .. ', ' .. cparams @@ -446,7 +479,7 @@ local function process_function(fn) for i = 1, #free_code do local rev_i = #free_code - i + 1 local code = free_code[rev_i] - if i == 1 then + if i == 1 and not string.match(real_type(fn.parameters[1][1]), '^KeyDict_') then free_at_exit_code = free_at_exit_code .. ('\n %s'):format(code) else free_at_exit_code = free_at_exit_code .. ('\n exit_%u:\n %s'):format( diff --git a/src/nvim/generators/gen_declarations.lua b/src/nvim/generators/gen_declarations.lua index 0782c8115d..97491679a4 100755 --- a/src/nvim/generators/gen_declarations.lua +++ b/src/nvim/generators/gen_declarations.lua @@ -60,7 +60,7 @@ local right_word = concat( ) local word = branch( concat( - branch(lit('ArrayOf('), lit('DictionaryOf(')), -- typed container macro + branch(lit('ArrayOf('), lit('DictionaryOf('), lit('Dict(')), -- typed container macro one_or_more(any_character - lit(')')), lit(')') ), diff --git a/src/nvim/generators/gen_keysets.lua b/src/nvim/generators/gen_keysets.lua new file mode 100644 index 0000000000..63ef202fe1 --- /dev/null +++ b/src/nvim/generators/gen_keysets.lua @@ -0,0 +1,67 @@ + +local nvimsrcdir = arg[1] +local shared_file = arg[2] +local funcs_file = arg[3] +local defs_file = arg[4] + +_G.vim = loadfile(shared_file)() + +if nvimsrcdir == '--help' then + print([[ +Usage: + lua gen_keyset.lua TODOFIXUPDATETHIS + +Will generate build/src/nvim/auto/keyset.generated.h with definition of functions +static const array. +]]) + os.exit(0) +end + + +package.path = nvimsrcdir .. '/?.lua;' .. package.path +local hashy = require'generators.hashy' + +local funcspipe = io.open(funcs_file, 'wb') +local defspipe = io.open(defs_file, 'wb') + +local keysets = require'api.keysets' + +for name, keys in pairs(keysets) do + local neworder, hashfun = hashy.hashy_hash(name, keys, function (idx) + return name.."_table["..idx.."].str" + end) + + defspipe:write("typedef struct {\n") + for _, key in ipairs(neworder) do + defspipe:write(" Object "..key..";\n") + end + defspipe:write("} KeyDict_"..name..";\n\n") + + defspipe:write("extern KeySetLink "..name.."_table[];\n") + + funcspipe:write("KeySetLink "..name.."_table[] = {\n") + for _, key in ipairs(neworder) do + funcspipe:write(' {"'..key..'", offsetof(KeyDict_'..name..", "..key..")},\n") + end + funcspipe:write(' {NULL, 0},\n') + funcspipe:write("};\n\n") + + funcspipe:write(hashfun) + + funcspipe:write([[ +Object *KeyDict_]]..name..[[_get_field(void *retval, const char *str, size_t len) +{ + int hash = ]]..name..[[_hash(str, len); + if (hash == -1) { + return NULL; + } + + return (Object *)((char *)retval + ]]..name..[[_table[hash].ptr_off); +} + +]]) + defspipe:write("#define api_free_keydict_"..name.."(x) api_free_keydict(x, "..name.."_table)\n") +end + +funcspipe:close() +defspipe:close() diff --git a/src/nvim/generators/hashy.lua b/src/nvim/generators/hashy.lua new file mode 100644 index 0000000000..fac24c810a --- /dev/null +++ b/src/nvim/generators/hashy.lua @@ -0,0 +1,122 @@ +-- HASHY McHASHFACE + +local M = {} +_G.d = M + + +local function setdefault(table, key) + local val = table[key] + if val == nil then + val = {} + table[key] = val + end + return val +end + +function M.build_pos_hash(strings) + local len_buckets = {} + local maxlen = 0 + for _,s in ipairs(strings) do + table.insert(setdefault(len_buckets, #s),s) + if #s > maxlen then maxlen = #s end + end + + local len_pos_buckets = {} + local worst_buck_size = 0 + + for len = 1,maxlen do + local strs = len_buckets[len] + if strs then + -- the best position so far generates `best_bucket` + -- with `minsize` worst case collisions + local bestpos, minsize, best_bucket = nil, #strs*2, nil + for pos = 1,len do + local try_bucket = {} + for _,str in ipairs(strs) do + local poschar = string.sub(str, pos, pos) + table.insert(setdefault(try_bucket, poschar), str) + end + local maxsize = 1 + for _,pos_strs in pairs(try_bucket) do + maxsize = math.max(maxsize, #pos_strs) + end + if maxsize < minsize then + bestpos = pos + minsize = maxsize + best_bucket = try_bucket + end + end + len_pos_buckets[len] = {bestpos, best_bucket} + worst_buck_size = math.max(worst_buck_size, minsize) + end + end + return len_pos_buckets, maxlen, worst_buck_size +end + +function M.switcher(put, tab, maxlen, worst_buck_size) + local neworder = {} + put " switch (len) {\n" + local bucky = worst_buck_size > 1 + for len = 1,maxlen do + local vals = tab[len] + if vals then + put(" case "..len..": ") + local pos, posbuck = unpack(vals) + local keys = vim.tbl_keys(posbuck) + if #keys > 1 then + table.sort(keys) + put("switch (str["..(pos-1).."]) {\n") + for _,c in ipairs(keys) do + local buck = posbuck[c] + local startidx = #neworder + vim.list_extend(neworder, buck) + local endidx = #neworder + put(" case '"..c.."': ") + put("low = "..startidx.."; ") + if bucky then put("high = "..endidx.."; ") end + put "break;\n" + end + put " default: break;\n" + put " }\n " + else + local startidx = #neworder + table.insert(neworder, posbuck[keys[1]][1]) + local endidx = #neworder + put("low = "..startidx.."; ") + if bucky then put("high = "..endidx.."; ") end + end + put " break;\n" + end + end + put " default: break;\n" + put " }\n" + return neworder +end + +function M.hashy_hash(name, strings, access) + local stats = {} + local put = function(str) table.insert(stats, str) end + local len_pos_buckets, maxlen, worst_buck_size = M.build_pos_hash(strings) + put("int "..name.."_hash(const char *str, size_t len)\n{\n") + if worst_buck_size > 1 then + put(" int low = 0, high = 0;\n") + else + put(" int low = -1;\n") + end + local neworder = M.switcher(put, len_pos_buckets, maxlen, worst_buck_size) + if worst_buck_size > 1 then + error [[ not implemented yet ]] -- TODO(bfredl) + else + put [[ + if (low < 0) { + return -1; + } + ]] + put("if(memcmp(str, "..access("low")..", len)) {\n return -1;\n }\n") + put " return low;\n" + put "}\n\n" + end + return neworder, table.concat(stats) +end + +return M diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index beb4ff4da6..f5f8a307d1 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -523,7 +523,7 @@ void restoreRedobuff(save_redo_T *save_redo) void AppendToRedobuff(const char *s) { if (!block_redo) { - add_buff(&redobuff, (const char *)s, -1L); + add_buff(&redobuff, s, -1L); } } @@ -1000,6 +1000,18 @@ void ins_char_typebuf(int c) buf[3] = NUL; } else { buf[utf_char2bytes(c, buf)] = NUL; + char_u *p = buf; + while (*p) { + if ((uint8_t)(*p) == CSI || (uint8_t)(*p) == K_SPECIAL) { + bool is_csi = (uint8_t)(*p) == CSI; + memmove(p + 3, p + 1, STRLEN(p + 1) + 1); + *p++ = K_SPECIAL; + *p++ = is_csi ? KS_EXTRA : KS_SPECIAL; + *p++ = is_csi ? KE_CSI : KE_FILLER; + } else { + p++; + } + } } (void)ins_typebuf(buf, KeyNoremap, 0, !KeyTyped, cmd_silent); } @@ -1558,7 +1570,7 @@ int vgetc(void) // a CSI (0x9B), // of a K_SPECIAL - KS_EXTRA - KE_CSI, which is CSI too. c = vgetorpeek(true); - if (vgetorpeek(true) == (int)KE_CSI && c == KS_EXTRA) { + if (vgetorpeek(true) == KE_CSI && c == KS_EXTRA) { buf[i] = CSI; } } @@ -1573,9 +1585,9 @@ int vgetc(void) if (!no_mapping && KeyTyped && (mod_mask == MOD_MASK_ALT || mod_mask == MOD_MASK_META)) { mod_mask = 0; - stuffcharReadbuff(c); - u_sync(false); - c = ESC; + ins_char_typebuf(c); + ins_char_typebuf(ESC); + continue; } break; @@ -1934,7 +1946,7 @@ static int vgetorpeek(bool advance) && (mp->m_keys[0] != K_SPECIAL || mp->m_keys[1] != KS_EXTRA || mp->m_keys[2] - != (int)KE_SNR)) { + != KE_SNR)) { continue; } /* @@ -2216,7 +2228,7 @@ static int vgetorpeek(bool advance) if (!ascii_iswhite(ptr[col])) { curwin->w_wcol = vcol; } - vcol += lbr_chartabsize(ptr, ptr + col, (colnr_T)vcol); + vcol += lbr_chartabsize(ptr, ptr + col, vcol); col += utfc_ptr2len(ptr + col); } curwin->w_wrow = curwin->w_cline_row @@ -2849,7 +2861,7 @@ int buf_do_map(int maptype, MapArguments *args, int mode, bool is_abbrev, buf_T } char_u *lhs = (char_u *)&args->lhs; - char_u *rhs = (char_u *)args->rhs; + char_u *rhs = args->rhs; char_u *orig_rhs = args->orig_rhs; // check arguments and translate function keys diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h index f0b52079aa..83fa00977f 100644 --- a/src/nvim/getchar.h +++ b/src/nvim/getchar.h @@ -56,6 +56,8 @@ struct map_arguments { size_t orig_rhs_len; }; typedef struct map_arguments MapArguments; +#define MAP_ARGUMENTS_INIT { false, false, false, false, false, false, false, \ + { 0 }, 0, NULL, 0, false, NULL, 0 } #define KEYLEN_PART_KEY -1 // keylen value for incomplete key-code #define KEYLEN_PART_MAP -2 // keylen value for incomplete mapping diff --git a/src/nvim/hardcopy.c b/src/nvim/hardcopy.c index df2c494ace..9d9ffa550a 100644 --- a/src/nvim/hardcopy.c +++ b/src/nvim/hardcopy.c @@ -643,12 +643,8 @@ void ex_hardcopy(exarg_T *eap) * PS.) */ if (mch_print_init(&settings, - curbuf->b_fname == NULL - ? (char_u *)buf_spname(curbuf) - : curbuf->b_sfname == NULL - ? curbuf->b_fname - : curbuf->b_sfname, - eap->forceit) == FAIL) { + curbuf->b_fname == NULL ? buf_spname(curbuf) : curbuf->b_sfname == + NULL ? curbuf->b_fname : curbuf->b_sfname, eap->forceit) == FAIL) { return; } diff --git a/src/nvim/if_cscope.c b/src/nvim/if_cscope.c index 31615e744a..76dcb58236 100644 --- a/src/nvim/if_cscope.c +++ b/src/nvim/if_cscope.c @@ -9,31 +9,29 @@ * might be a few lines of code that look similar to what Nvi has. */ -#include <stdbool.h> - #include <assert.h> #include <errno.h> -#include <inttypes.h> #include <fcntl.h> +#include <inttypes.h> +#include <stdbool.h> +#include <sys/stat.h> +#include <sys/types.h> -#include "nvim/buffer.h" #include "nvim/ascii.h" -#include "nvim/if_cscope.h" +#include "nvim/buffer.h" #include "nvim/charset.h" +#include "nvim/event/stream.h" #include "nvim/fileio.h" -#include "nvim/message.h" +#include "nvim/if_cscope.h" #include "nvim/memory.h" +#include "nvim/message.h" +#include "nvim/os/input.h" +#include "nvim/os/os.h" #include "nvim/os/time.h" #include "nvim/path.h" #include "nvim/quickfix.h" #include "nvim/strings.h" #include "nvim/tag.h" -#include "nvim/os/os.h" -#include "nvim/os/input.h" -#include "nvim/event/stream.h" - -#include <sys/types.h> -#include <sys/stat.h> #if defined(UNIX) # include <sys/wait.h> #endif @@ -90,19 +88,20 @@ char_u *get_cscope_name(expand_T *xp, int idx) // Complete with sub-commands of ":cscope": // add, find, help, kill, reset, show return (char_u *)cs_cmds[idx].name; - case EXP_SCSCOPE_SUBCMD: - { + case EXP_SCSCOPE_SUBCMD: { // Complete with sub-commands of ":scscope": same sub-commands as // ":cscope" but skip commands which don't support split windows int i; - for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++) - if (cs_cmds[i].cansplit) - if (current_idx++ == idx) + for (i = 0, current_idx = 0; cs_cmds[i].name != NULL; i++) { + if (cs_cmds[i].cansplit) { + if (current_idx++ == idx) { break; + } + } + } return (char_u *)cs_cmds[i].name; } - case EXP_CSCOPE_FIND: - { + case EXP_CSCOPE_FIND: { const char *query_type[] = { "a", "c", "d", "e", "f", "g", "i", "s", "t", NULL @@ -114,8 +113,7 @@ char_u *get_cscope_name(expand_T *xp, int idx) // redundant. return (char_u *)query_type[idx]; } - case EXP_CSCOPE_KILL: - { + case EXP_CSCOPE_KILL: { static char connection[5]; // ":cscope kill" accepts connection numbers or partial names of @@ -124,8 +122,9 @@ char_u *get_cscope_name(expand_T *xp, int idx) // connections. size_t i; for (i = 0, current_idx = 0; i < csinfo_size; i++) { - if (csinfo[i].fname == NULL) + if (csinfo[i].fname == NULL) { continue; + } if (current_idx++ == idx) { vim_snprintf(connection, sizeof(connection), "%zu", i); return (char_u *)connection; @@ -172,11 +171,9 @@ void set_context_in_cscope_cmd(expand_T *xp, const char *arg, cmdidx_T cmdidx) /// Find the command, print help if invalid, and then call the corresponding /// command function. -static void -do_cscope_general( - exarg_T *eap, - int make_split // whether to split window -) +/// +/// @param make_split whether to split window +static void do_cscope_general(exarg_T *eap, int make_split) { cscmd_T *cmdp; @@ -187,8 +184,7 @@ do_cscope_general( if (make_split) { if (!cmdp->cansplit) { - (void)MSG_PUTS(_( - "This cscope command does not support splitting the window.\n")); + (void)MSG_PUTS(_("This cscope command does not support splitting the window.\n")); return; } postponed_split = -1; @@ -228,14 +224,16 @@ void ex_cstag(exarg_T *eap) case 0: if (cs_check_for_connections()) { ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE, - FALSE, *eap->cmdlinep); + FALSE, *eap->cmdlinep); if (ret == FALSE) { cs_free_tags(); - if (msg_col) + if (msg_col) { msg_putchar('\n'); + } - if (cs_check_for_tags()) + if (cs_check_for_tags()) { ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE); + } } } else if (cs_check_for_tags()) { ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE); @@ -245,21 +243,24 @@ void ex_cstag(exarg_T *eap) if (cs_check_for_tags()) { ret = do_tag(eap->arg, DT_JUMP, 0, eap->forceit, FALSE); if (ret == FALSE) { - if (msg_col) + if (msg_col) { msg_putchar('\n'); + } if (cs_check_for_connections()) { ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, - FALSE, FALSE, *eap->cmdlinep); - if (ret == FALSE) + FALSE, FALSE, *eap->cmdlinep); + if (ret == FALSE) { cs_free_tags(); + } } } } else if (cs_check_for_connections()) { ret = cs_find_common("g", (char *)(eap->arg), eap->forceit, FALSE, - FALSE, *eap->cmdlinep); - if (ret == FALSE) + FALSE, *eap->cmdlinep); + if (ret == FALSE) { cs_free_tags(); + } } break; default: @@ -306,29 +307,29 @@ void cs_print_tags(void) /* * "cscope_connection([{num} , {dbpath} [, {prepend}]])" function * - * Checks for the existence of a |cscope| connection. If no - * parameters are specified, then the function returns: + * Checks for the existence of a |cscope| connection. If no + * parameters are specified, then the function returns: * - * 0, if cscope was not available (not compiled in), or if there - * are no cscope connections; or - * 1, if there is at least one cscope connection. + * 0, if cscope was not available (not compiled in), or if there + * are no cscope connections; or + * 1, if there is at least one cscope connection. * - * If parameters are specified, then the value of {num} - * determines how existence of a cscope connection is checked: + * If parameters are specified, then the value of {num} + * determines how existence of a cscope connection is checked: * - * {num} Description of existence check - * ----- ------------------------------ - * 0 Same as no parameters (e.g., "cscope_connection()"). - * 1 Ignore {prepend}, and use partial string matches for - * {dbpath}. - * 2 Ignore {prepend}, and use exact string matches for - * {dbpath}. - * 3 Use {prepend}, use partial string matches for both - * {dbpath} and {prepend}. - * 4 Use {prepend}, use exact string matches for both - * {dbpath} and {prepend}. + * {num} Description of existence check + * ----- ------------------------------ + * 0 Same as no parameters (e.g., "cscope_connection()"). + * 1 Ignore {prepend}, and use partial string matches for + * {dbpath}. + * 2 Ignore {prepend}, and use exact string matches for + * {dbpath}. + * 3 Use {prepend}, use partial string matches for both + * {dbpath} and {prepend}. + * 4 Use {prepend}, use exact string matches for both + * {dbpath} and {prepend}. * - * Note: All string comparisons are case sensitive! + * Note: All string comparisons are case sensitive! */ bool cs_connection(int num, char_u *dbpath, char_u *ppath) { @@ -393,8 +394,9 @@ static int cs_add(exarg_T *eap) cs_usage_msg(Add); return CSCOPE_FAILURE; } - if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL) + if ((ppath = strtok((char *)NULL, (const char *)" ")) != NULL) { flags = strtok((char *)NULL, (const char *)" "); + } return cs_add_common(fname, ppath, flags); } @@ -413,18 +415,16 @@ static void cs_stat_emsg(char *fname) /// The common routine to add a new cscope connection. Called by /// cs_add() and cs_reset(). I really don't like to do this, but this /// routine uses a number of goto statements. -static int -cs_add_common( - char *arg1, // filename - may contain environment variables - char *arg2, // prepend path - may contain environment variables - char *flags -) +/// +/// @param arg1 filename - may contain environment variables +/// @param arg2 prepend path - may contain environment variables +static int cs_add_common(char *arg1, char *arg2, char *flags) { - char *fname = NULL; - char *fname2 = NULL; - char *ppath = NULL; + char *fname = NULL; + char *fname2 = NULL; + char *ppath = NULL; size_t usedlen = 0; - char_u *fbuf = NULL; + char_u *fbuf = NULL; // get the filename (arg1), expand it, and try to stat it fname = xmalloc(MAXPATHL + 1); @@ -443,8 +443,9 @@ cs_add_common( bool file_info_ok = os_fileinfo(fname, &file_info); if (!file_info_ok) { staterr: - if (p_csverbose) + if (p_csverbose) { cs_stat_emsg(fname); + } goto add_err; } @@ -465,31 +466,32 @@ staterr: while (fname[strlen(fname)-1] == '/' ) { fname[strlen(fname)-1] = '\0'; - if (fname[0] == '\0') + if (fname[0] == '\0') { break; + } } - if (fname[0] == '\0') + if (fname[0] == '\0') { (void)sprintf(fname2, "/%s", CSCOPE_DBFILE); - else + } else { (void)sprintf(fname2, "%s/%s", fname, CSCOPE_DBFILE); + } file_info_ok = os_fileinfo(fname2, &file_info); if (!file_info_ok) { - if (p_csverbose) + if (p_csverbose) { cs_stat_emsg(fname2); + } goto add_err; } i = cs_insert_filelist(fname2, ppath, flags, &file_info); - } - else if (S_ISREG(file_info.stat.st_mode) || S_ISLNK(file_info.stat.st_mode)) - { + } else if (S_ISREG(file_info.stat.st_mode) || S_ISLNK(file_info.stat.st_mode)) { i = cs_insert_filelist(fname, ppath, flags, &file_info); } else { - if (p_csverbose) - (void)EMSG2( - _("E564: %s is not a directory or a valid cscope database"), - fname); + if (p_csverbose) { + (void)EMSG2(_("E564: %s is not a directory or a valid cscope database"), + fname); + } goto add_err; } @@ -538,15 +540,15 @@ static size_t cs_cnt_connections(void) size_t cnt = 0; for (size_t i = 0; i < csinfo_size; i++) { - if (csinfo[i].fname != NULL) + if (csinfo[i].fname != NULL) { cnt++; + } } return cnt; } -static void cs_reading_emsg( - size_t idx // connection index -) +/// @param idx connection index +static void cs_reading_emsg(size_t idx) { EMSGU(_("E262: error reading cscope connection %" PRIu64), idx); } @@ -582,7 +584,7 @@ static int cs_cnt_matches(size_t idx) // Accept "\S*cscope: X lines", also matches "mlcscope". // Bail out for the "Unable to search" error. if (strstr((const char *)buf, "Unable to search database") != NULL) { - break; + break; } if ((stok = strtok(buf, (const char *)" ")) == NULL) { continue; @@ -591,18 +593,21 @@ static int cs_cnt_matches(size_t idx) continue; } - if ((stok = strtok(NULL, (const char *)" ")) == NULL) + if ((stok = strtok(NULL, (const char *)" ")) == NULL) { continue; + } nlines = atoi(stok); if (nlines < 0) { nlines = 0; break; } - if ((stok = strtok(NULL, (const char *)" ")) == NULL) + if ((stok = strtok(NULL, (const char *)" ")) == NULL) { continue; - if (strncmp((const char *)stok, "lines", 5)) + } + if (strncmp((const char *)stok, "lines", 5)) { continue; + } break; } @@ -620,31 +625,40 @@ static char *cs_create_cmd(char *csoption, char *pattern) char *pat; switch (csoption[0]) { - case '0': case 's': + case '0': + case 's': search = 0; break; - case '1': case 'g': + case '1': + case 'g': search = 1; break; - case '2': case 'd': + case '2': + case 'd': search = 2; break; - case '3': case 'c': + case '3': + case 'c': search = 3; break; - case '4': case 't': + case '4': + case 't': search = 4; break; - case '6': case 'e': + case '6': + case 'e': search = 6; break; - case '7': case 'f': + case '7': + case 'f': search = 7; break; - case '8': case 'i': + case '8': + case 'i': search = 8; break; - case '9': case 'a': + case '9': + case 'a': search = 9; break; default: @@ -656,9 +670,11 @@ static char *cs_create_cmd(char *csoption, char *pattern) // Skip white space before the patter, except for text and pattern search, // they may want to use the leading white space. pat = pattern; - if (search != 4 && search != 6) - while (ascii_iswhite(*pat)) + if (search != 4 && search != 6) { + while (ascii_iswhite(*pat)) { ++pat; + } + } cmd = xmalloc(strlen(pat) + 2); @@ -675,7 +691,7 @@ static int cs_create_connection(size_t i) #ifdef UNIX int to_cs[2], from_cs[2]; #endif - char *prog, *cmd, *ppath = NULL; + char *prog, *cmd, *ppath = NULL; #if defined(UNIX) /* @@ -686,14 +702,18 @@ static int cs_create_connection(size_t i) if (pipe(to_cs) < 0 || pipe(from_cs) < 0) { (void)EMSG(_("E566: Could not create cscope pipes")); err_closing: - if (to_cs[0] != -1) + if (to_cs[0] != -1) { (void)close(to_cs[0]); - if (to_cs[1] != -1) + } + if (to_cs[1] != -1) { (void)close(to_cs[1]); - if (from_cs[0] != -1) + } + if (from_cs[0] != -1) { (void)close(from_cs[0]); - if (from_cs[1] != -1) + } + if (from_cs[1] != -1) { (void)close(from_cs[1]); + } return CSCOPE_FAILURE; } @@ -759,8 +779,9 @@ err_closing: len += strlen(ppath); } - if (csinfo[i].flags) + if (csinfo[i].flags) { len += strlen(csinfo[i].flags); + } cmd = xmalloc(len); @@ -779,10 +800,10 @@ err_closing: (void)strcat(cmd, " "); (void)strcat(cmd, csinfo[i].flags); } -# ifdef UNIX +#ifdef UNIX // on Win32 we still need prog xfree(prog); -# endif +#endif xfree(ppath); #if defined(UNIX) @@ -791,12 +812,14 @@ err_closing: # if defined(HAVE_SETSID) (void)setsid(); # else - if (setpgid(0, 0) == -1) + if (setpgid(0, 0) == -1) { PERROR(_("cs_create_connection setpgid failed")); + } # endif # endif - if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1) + if (execl("/bin/sh", "sh", "-c", cmd, (char *)NULL) == -1) { PERROR(_("cs_create_connection exec failed")); + } exit(127); // NOTREACHED @@ -827,7 +850,7 @@ err_closing: si.hStdError = stdout_wr; si.hStdInput = stdin_rd; created = CreateProcess(NULL, cmd, NULL, NULL, TRUE, CREATE_NEW_CONSOLE, - NULL, NULL, &si, &pi); + NULL, NULL, &si, &pi); xfree(prog); xfree(cmd); @@ -888,9 +911,11 @@ static int cs_find(exarg_T *eap) * Let's replace the NULs written by strtok() with spaces - we need the * spaces to correctly display the quickfix/location list window's title. */ - for (int i = 0; i < eap_arg_len; ++i) - if (NUL == eap->arg[i]) + for (int i = 0; i < eap_arg_len; ++i) { + if (NUL == eap->arg[i]) { eap->arg[i] = ' '; + } + } return cs_find_common(opt, pat, eap->forceit, true, eap->cmdidx == CMD_lcscope, *eap->cmdlinep); @@ -898,8 +923,8 @@ static int cs_find(exarg_T *eap) /// Common code for cscope find, shared by cs_find() and ex_cstag(). -static int cs_find_common(char *opt, char *pat, int forceit, int verbose, - int use_ll, char_u *cmdline) +static int cs_find_common(char *opt, char *pat, int forceit, int verbose, int use_ll, + char_u *cmdline) { char *cmd; int *nummatches; @@ -966,8 +991,9 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, // create the actual command to send to cscope cmd = cs_create_cmd(opt, pat); - if (cmd == NULL) + if (cmd == NULL) { return FALSE; + } nummatches = xmalloc(sizeof(int) * csinfo_size); @@ -978,8 +1004,9 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, } totmatches = 0; for (size_t i = 0; i < csinfo_size; i++) { - if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL) + if (csinfo[i].fname == NULL || csinfo[i].to_fp == NULL) { continue; + } // send cmd to cscope (void)fprintf(csinfo[i].to_fp, "%s\n", cmd); @@ -987,11 +1014,13 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, nummatches[i] = cs_cnt_matches(i); - if (nummatches[i] > -1) + if (nummatches[i] > -1) { totmatches += (size_t)nummatches[i]; + } - if (nummatches[i] == 0) + if (nummatches[i] == 0) { (void)cs_read_prompt(i); + } } xfree(cmd); @@ -1014,10 +1043,10 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, if (qfpos != NULL && *qfpos != '0') { // Fill error list. - FILE *f; - char_u *tmp = vim_tempname(); - qf_info_T *qi = NULL; - win_T *wp = NULL; + FILE *f; + char_u *tmp = vim_tempname(); + qf_info_T *qi = NULL; + win_T *wp = NULL; f = os_fopen((char *)tmp, "w"); if (f == NULL) { @@ -1039,14 +1068,15 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, } apply_autocmds(EVENT_QUICKFIXCMDPOST, (char_u *)"cscope", - curbuf->b_fname, TRUE, curbuf); - if (use_ll) + curbuf->b_fname, TRUE, curbuf); + if (use_ll) { /* * In the location list window, use the displayed location * list. Otherwise, use the location list for the window. */ qi = (bt_quickfix(wp->w_buffer) && wp->w_llist_ref != NULL) ? wp->w_llist_ref : wp->w_llist; + } qf_jump(qi, 0, 0, forceit); } } @@ -1059,11 +1089,11 @@ static int cs_find_common(char *opt, char *pat, int forceit, int verbose, size_t matched = 0; // read output - cs_fill_results((char *)pat, totmatches, nummatches, &matches, - &contexts, &matched); + cs_fill_results(pat, totmatches, nummatches, &matches, &contexts, &matched); xfree(nummatches); - if (matches == NULL) + if (matches == NULL) { return FALSE; + } (void)cs_manage_matches(matches, contexts, matched, Store); @@ -1086,10 +1116,10 @@ static int cs_help(exarg_T *eap) space_cnt = 0; } (void)smsg(_("%-5s: %s%*s (Usage: %s)"), - cmdp->name, - help, space_cnt, " ", - cmdp->usage); - if (strcmp(cmdp->name, "find") == 0) + cmdp->name, + help, space_cnt, " ", + cmdp->usage); + if (strcmp(cmdp->name, "find") == 0) { MSG_PUTS(_("\n" " a: Find assignments to this symbol\n" " c: Find functions calling this function\n" @@ -1100,6 +1130,7 @@ static int cs_help(exarg_T *eap) " i: Find files #including this file\n" " s: Find this C symbol\n" " t: Find this text string\n")); + } cmdp++; } @@ -1121,8 +1152,7 @@ static void clear_csinfo(size_t i) } /// Insert a new cscope database filename into the filelist. -static int cs_insert_filelist(char *fname, char *ppath, char *flags, - FileInfo *file_info) +static int cs_insert_filelist(char *fname, char *ppath, char *flags, FileInfo *file_info) { size_t i = 0; bool empty_found = false; @@ -1130,8 +1160,9 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, for (size_t j = 0; j < csinfo_size; j++) { if (csinfo[j].fname != NULL && os_fileid_equal_fileinfo(&(csinfo[j].file_id), file_info)) { - if (p_csverbose) + if (p_csverbose) { (void)EMSG(_("E568: duplicate cscope database not added")); + } return CSCOPE_FAILURE; } @@ -1154,8 +1185,9 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, csinfo_size *= 2; csinfo = xrealloc(csinfo, sizeof(csinfo_T)*csinfo_size); } - for (size_t j = csinfo_size/2; j < csinfo_size; j++) + for (size_t j = csinfo_size/2; j < csinfo_size; j++) { clear_csinfo(j); + } } csinfo[i].fname = xmalloc(strlen(fname) + 1); @@ -1165,14 +1197,16 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, if (ppath != NULL) { csinfo[i].ppath = xmalloc(strlen(ppath) + 1); (void)strcpy(csinfo[i].ppath, (const char *)ppath); - } else + } else { csinfo[i].ppath = NULL; + } if (flags != NULL) { csinfo[i].flags = xmalloc(strlen(flags) + 1); (void)strcpy(csinfo[i].flags, (const char *)flags); - } else + } else { csinfo[i].flags = NULL; + } os_fileinfo_id(file_info, &(csinfo[i].file_id)); assert(i <= INT_MAX); @@ -1181,25 +1215,28 @@ static int cs_insert_filelist(char *fname, char *ppath, char *flags, /// Find cscope command in command table. -static cscmd_T * cs_lookup_cmd(exarg_T *eap) +static cscmd_T *cs_lookup_cmd(exarg_T *eap) { cscmd_T *cmdp; char *stok; size_t len; - if (eap->arg == NULL) + if (eap->arg == NULL) { return NULL; + } // Store length of eap->arg before it gets modified by strtok(). eap_arg_len = (int)STRLEN(eap->arg); - if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL) + if ((stok = strtok((char *)(eap->arg), (const char *)" ")) == NULL) { return NULL; + } len = strlen(stok); for (cmdp = cs_cmds; cmdp->name != NULL; ++cmdp) { - if (strncmp((const char *)(stok), cmdp->name, len) == 0) + if (strncmp((const char *)(stok), cmdp->name, len) == 0) { return cmdp; + } } return NULL; } @@ -1224,21 +1261,23 @@ static int cs_kill(exarg_T *eap) || (strlen(stok) < 3 && stok[0] == '-' && ascii_isdigit((int)(stok[1])))) { num = atoi(stok); - if (num == -1) + if (num == -1) { killall = true; - else if (num >= 0) { + } else if (num >= 0) { i = (size_t)num; } else { // All negative values besides -1 are invalid. - if (p_csverbose) + if (p_csverbose) { (void)EMSG2(_("E261: cscope connection %s not found"), stok); + } return CSCOPE_FAILURE; } } else { // Else it must be part of a name. We will try to find a match // within all the names in the csinfo data structure for (i = 0; i < csinfo_size; i++) { - if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok)) + if (csinfo[i].fname != NULL && strstr(csinfo[i].fname, stok)) { break; + } } } @@ -1250,8 +1289,9 @@ static int cs_kill(exarg_T *eap) } else { if (killall) { for (i = 0; i < csinfo_size; i++) { - if (csinfo[i].fname) + if (csinfo[i].fname) { cs_kill_execute(i, csinfo[i].fname); + } } } else { cs_kill_execute((size_t)i, stok); @@ -1263,10 +1303,10 @@ static int cs_kill(exarg_T *eap) /// Actually kills a specific cscope connection. -static void cs_kill_execute( - size_t i, // cscope table index - char *cname // cscope database name -) +/// +/// @param i cscope table index +/// @param cname cscope database name +static void cs_kill_execute(size_t i, char *cname) { if (p_csverbose) { msg_clr_eos(); @@ -1293,8 +1333,7 @@ static void cs_kill_execute( /// Besides, even if this particular case didn't happen, the search pattern /// would still have to be modified to escape all the special regular expression /// characters to comply with ctags formatting. -static char *cs_make_vim_style_matches(char *fname, char *slno, char *search, - char *tagstr) +static char *cs_make_vim_style_matches(char *fname, char *slno, char *search, char *tagstr) { // vim style is ctags: // @@ -1339,8 +1378,7 @@ static char *cs_make_vim_style_matches(char *fname, char *slno, char *search, /// Free: frees up everything and resets /// /// Print: prints the tags -static char *cs_manage_matches(char **matches, char **contexts, - size_t totmatches, mcmd_e cmd) +static char *cs_manage_matches(char **matches, char **contexts, size_t totmatches, mcmd_e cmd) { static char **mp = NULL; static char **cp = NULL; @@ -1352,16 +1390,18 @@ static char *cs_manage_matches(char **matches, char **contexts, case Store: assert(matches != NULL); assert(totmatches > 0); - if (mp != NULL || cp != NULL) + if (mp != NULL || cp != NULL) { (void)cs_manage_matches(NULL, NULL, 0, Free); + } mp = matches; cp = contexts; cnt = totmatches; next = 0; break; case Get: - if (next >= cnt) + if (next >= cnt) { return NULL; + } p = mp[next]; next++; @@ -1370,8 +1410,9 @@ static char *cs_manage_matches(char **matches, char **contexts, if (mp != NULL) { while (cnt--) { xfree(mp[cnt]); - if (cp != NULL) + if (cp != NULL) { xfree(cp[cnt]); + } } xfree(mp); xfree(cp); @@ -1396,8 +1437,8 @@ static char *cs_manage_matches(char **matches, char **contexts, /// Parse cscope output. -static char *cs_parse_results(size_t cnumber, char *buf, int bufsize, - char **context, char **linenumber, char **search) +static char *cs_parse_results(size_t cnumber, char *buf, int bufsize, char **context, + char **linenumber, char **search) { int ch; char *p; @@ -1421,8 +1462,9 @@ retry: // If the line's too long for the buffer, discard it. if ((p = strchr(buf, '\n')) == NULL) { - while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n') + while ((ch = getc(csinfo[cnumber].fr_fp)) != EOF && ch != '\n') { ; + } return NULL; } *p = '\0'; @@ -1430,14 +1472,18 @@ retry: /* * cscope output is in the following format: * - * <filename> <context> <line number> <pattern> + * <filename> <context> <line number> <pattern> */ - if ((name = strtok((char *)buf, (const char *)" ")) == NULL) + char *saveptr = NULL; + if ((name = os_strtok(buf, (const char *)" ", &saveptr)) == NULL) { return NULL; - if ((*context = strtok(NULL, (const char *)" ")) == NULL) + } + if ((*context = os_strtok(NULL, (const char *)" ", &saveptr)) == NULL) { return NULL; - if ((*linenumber = strtok(NULL, (const char *)" ")) == NULL) + } + if ((*linenumber = os_strtok(NULL, (const char *)" ", &saveptr)) == NULL) { return NULL; + } *search = *linenumber + strlen(*linenumber) + 1; // +1 to skip \0 // --- nvi --- @@ -1463,25 +1509,29 @@ static void cs_file_results(FILE *f, int *nummatches_a) char *buf = xmalloc(CSREAD_BUFSIZE); for (size_t i = 0; i < csinfo_size; i++) { - if (nummatches_a[i] < 1) + if (nummatches_a[i] < 1) { continue; + } for (int j = 0; j < nummatches_a[i]; j++) { if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx, - &slno, &search)) == NULL) + &slno, &search)) == NULL) { continue; + } context = xmalloc(strlen(cntx) + 5); - if (strcmp(cntx, "<global>")==0) + if (strcmp(cntx, "<global>")==0) { strcpy(context, "<<global>>"); - else + } else { sprintf(context, "<<%s>>", cntx); + } - if (search == NULL) + if (search == NULL) { fprintf(f, "%s\t%s\t%s\n", fullname, slno, context); - else + } else { fprintf(f, "%s\t%s\t%s %s\n", fullname, slno, context, search); + } xfree(context); xfree(fullname); @@ -1495,9 +1545,8 @@ static void cs_file_results(FILE *f, int *nummatches_a) /// Get parsed cscope output and calls cs_make_vim_style_matches to convert /// into ctags format. /// When there are no matches sets "*matches_p" to NULL. -static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a, - char ***matches_p, char ***cntxts_p, - size_t *matched) +static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a, char ***matches_p, + char ***cntxts_p, size_t *matched) { char *buf; char *search, *slno; @@ -1514,22 +1563,24 @@ static void cs_fill_results(char *tagstr, size_t totmatches, int *nummatches_a, cntxts = xmalloc(sizeof(char *) * (size_t)totmatches); for (size_t i = 0; i < csinfo_size; i++) { - if (nummatches_a[i] < 1) + if (nummatches_a[i] < 1) { continue; + } for (int j = 0; j < nummatches_a[i]; j++) { if ((fullname = cs_parse_results(i, buf, CSREAD_BUFSIZE, &cntx, - &slno, &search)) == NULL) + &slno, &search)) == NULL) { continue; + } matches[totsofar] = cs_make_vim_style_matches(fullname, slno, search, tagstr); xfree(fullname); - if (strcmp(cntx, "<global>") == 0) + if (strcmp(cntx, "<global>") == 0) { cntxts[totsofar] = NULL; - else { + } else { cntxts[totsofar] = xstrdup(cntx); } @@ -1691,9 +1742,9 @@ static void cs_print_tags_priv(char **matches, char **cntxts, static int cs_read_prompt(size_t i) { int ch; - char *buf = NULL; // buffer for possible error message from cscope + char *buf = NULL; // buffer for possible error message from cscope size_t bufpos = 0; - char *cs_emsg = _("E609: Cscope error: %s"); + char *cs_emsg = _("E609: Cscope error: %s"); size_t cs_emsg_len = strlen(cs_emsg); static char *eprompt = "Press the RETURN key to continue:"; size_t epromptlen = strlen(eprompt); @@ -1886,10 +1937,12 @@ static void cs_release_csp(size_t i, bool freefnpp) } #endif - if (csinfo[i].fr_fp != NULL) + if (csinfo[i].fr_fp != NULL) { (void)fclose(csinfo[i].fr_fp); - if (csinfo[i].to_fp != NULL) + } + if (csinfo[i].to_fp != NULL) { (void)fclose(csinfo[i].to_fp); + } if (freefnpp) { xfree(csinfo[i].fname); @@ -1904,11 +1957,12 @@ static void cs_release_csp(size_t i, bool freefnpp) /// Calls cs_kill on all cscope connections then reinits. static int cs_reset(exarg_T *eap) { - char **dblist = NULL, **pplist = NULL, **fllist = NULL; + char **dblist = NULL, **pplist = NULL, **fllist = NULL; char buf[25]; // for snprintf " (#%zu)" - if (csinfo_size == 0) + if (csinfo_size == 0) { return CSCOPE_SUCCESS; + } // malloc our db and ppath list dblist = xmalloc(csinfo_size * sizeof(char *)); @@ -1919,8 +1973,9 @@ static int cs_reset(exarg_T *eap) dblist[i] = csinfo[i].fname; pplist[i] = csinfo[i].ppath; fllist[i] = csinfo[i].flags; - if (csinfo[i].fname != NULL) + if (csinfo[i].fname != NULL) { cs_release_csp(i, FALSE); + } } // rebuild the cscope connection list @@ -1959,8 +2014,8 @@ static int cs_reset(exarg_T *eap) /// Contrast this with my development system (Digital Unix), which does. static char *cs_resolve_file(size_t i, char *name) { - char *fullname; - char_u *csdir = NULL; + char *fullname; + char_u *csdir = NULL; /* * Ppath is freed when we destroy the cscope connection. @@ -1975,8 +2030,8 @@ static char *cs_resolve_file(size_t i, char *name) // path in path resolution. csdir = xmalloc(MAXPATHL); STRLCPY(csdir, csinfo[i].fname, - path_tail((char_u *)csinfo[i].fname) - - (char_u *)csinfo[i].fname + 1); + path_tail((char_u *)csinfo[i].fname) + - (char_u *)csinfo[i].fname + 1); len += STRLEN(csdir); } @@ -1985,8 +2040,7 @@ static char *cs_resolve_file(size_t i, char *name) // happens, you are screwed up and need to fix how you're using cscope. if (csinfo[i].ppath != NULL && (strncmp(name, csinfo[i].ppath, strlen(csinfo[i].ppath)) != 0) - && (name[0] != '/') - ) { + && (name[0] != '/')) { fullname = xmalloc(len); (void)sprintf(fullname, "%s/%s", csinfo[i].ppath, name); } else if (csdir != NULL && csinfo[i].fname != NULL && *csdir != NUL) { @@ -2005,15 +2059,15 @@ static char *cs_resolve_file(size_t i, char *name) /// Show all cscope connections. static int cs_show(exarg_T *eap) { - if (cs_cnt_connections() == 0) + if (cs_cnt_connections() == 0) { MSG_PUTS(_("no cscope connections\n")); - else { - MSG_PUTS_ATTR( - _(" # pid database name prepend path\n"), - HL_ATTR(HLF_T)); + } else { + MSG_PUTS_ATTR(_(" # pid database name prepend path\n"), + HL_ATTR(HLF_T)); for (size_t i = 0; i < csinfo_size; i++) { - if (csinfo[i].fname == NULL) + if (csinfo[i].fname == NULL) { continue; + } if (csinfo[i].ppath != NULL) { (void)smsg("%2zu %-5" PRId64 " %-34s %-32s", i, @@ -2033,8 +2087,9 @@ static int cs_show(exarg_T *eap) /// Only called when VIM exits to quit any cscope sessions. void cs_end(void) { - for (size_t i = 0; i < csinfo_size; i++) + for (size_t i = 0; i < csinfo_size; i++) { cs_release_csp(i, true); + } xfree(csinfo); csinfo_size = 0; } diff --git a/src/nvim/lua/converter.c b/src/nvim/lua/converter.c index fac5bab664..fd4cfc4c31 100644 --- a/src/nvim/lua/converter.c +++ b/src/nvim/lua/converter.c @@ -1299,3 +1299,25 @@ void nlua_init_types(lua_State *const lstate) lua_rawset(lstate, -3); } + + +void nlua_pop_keydict(lua_State *L, void *retval, field_hash hashy, Error *err) +{ + lua_pushnil(L); // [dict, nil] + while (lua_next(L, -2)) { + // [dict, key, value] + size_t len; + const char *s = lua_tolstring(L, -2, &len); + Object *field = hashy(retval, s, len); + if (!field) { + api_set_error(err, kErrorTypeValidation, "invalid key: %.*s", (int)len, s); + lua_pop(L, 3); // [] + return; + } + + *field = nlua_pop_Object(L, true, err); + } + // [dict] + lua_pop(L, 1); + // [] +} diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index 9333d781cd..3f93bb9a09 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -5,6 +5,7 @@ #include <lua.h> #include <lualib.h> +#include "cjson/lua_cjson.h" #include "luv/luv.h" #include "mpack/lmpack.h" #include "nvim/api/private/defs.h" @@ -40,7 +41,6 @@ #include "nvim/undo.h" #include "nvim/version.h" #include "nvim/vim.h" -#include "cjson/lua_cjson.h" static int in_fast_callback = 0; diff --git a/src/nvim/lua/vim.lua b/src/nvim/lua/vim.lua index 7a209f2d79..5ca4cc82a5 100644 --- a/src/nvim/lua/vim.lua +++ b/src/nvim/lua/vim.lua @@ -433,6 +433,7 @@ function vim.notify(msg, log_level, _opts) end +---@private function vim.register_keystroke_callback() error('vim.register_keystroke_callback is deprecated, instead use: vim.on_key') end diff --git a/src/nvim/lua/xdiff.c b/src/nvim/lua/xdiff.c index 2a1f39083c..3955fbe72c 100644 --- a/src/nvim/lua/xdiff.c +++ b/src/nvim/lua/xdiff.c @@ -53,8 +53,8 @@ static int write_string(void *priv, mmbuffer_t *mb, int nbuf) static int hunk_locations_cb(long start_a, long count_a, long start_b, long count_b, void *cb_data) { // Mimic extra offsets done by xdiff, see: - // src/nvim/xdiff/xemit.c:284 - // src/nvim/xdiff/xutils.c:(356,368) + // src/xdiff/xemit.c:284 + // src/xdiff/xutils.c:(356,368) if (count_a > 0) { start_a += 1; } @@ -83,8 +83,8 @@ static int hunk_locations_cb(long start_a, long count_a, long start_b, long coun static int call_on_hunk_cb(long start_a, long count_a, long start_b, long count_b, void *cb_data) { // Mimic extra offsets done by xdiff, see: - // src/nvim/xdiff/xemit.c:284 - // src/nvim/xdiff/xutils.c:(356,368) + // src/xdiff/xemit.c:284 + // src/xdiff/xutils.c:(356,368) if (count_a > 0) { start_a += 1; } diff --git a/src/nvim/main.c b/src/nvim/main.c index d977589ad7..069c253bff 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -345,7 +345,8 @@ int main(int argc, char **argv) // Reset 'loadplugins' for "-u NONE" before "--cmd" arguments. // Allows for setting 'loadplugins' there. if (params.use_vimrc != NULL && strequal(params.use_vimrc, "NONE")) { - p_lpl = false; + // When using --clean we still want to load plugins + p_lpl = params.clean; } // Execute --cmd arguments. @@ -1306,35 +1307,6 @@ static void set_window_layout(mparm_T *paramp) } } -/* - * Read all the plugin files. - * Only when compiled with +eval, since most plugins need it. - */ -static void load_plugins(void) -{ - if (p_lpl) { - char_u *rtp_copy = NULL; - char_u *const plugin_pattern_vim = (char_u *)"plugin/**/*.vim"; // NOLINT - char_u *const plugin_pattern_lua = (char_u *)"plugin/**/*.lua"; // NOLINT - - // don't use source_runtime() yet so we can check for :packloadall below - source_in_path(p_rtp, plugin_pattern_vim, DIP_ALL | DIP_NOAFTER); - source_in_path(p_rtp, plugin_pattern_lua, DIP_ALL | DIP_NOAFTER); - TIME_MSG("loading rtp plugins"); - xfree(rtp_copy); - - // Only source "start" packages if not done already with a :packloadall - // command. - if (!did_source_packages) { - load_start_packages(); - } - TIME_MSG("loading packages"); - - source_runtime(plugin_pattern_vim, DIP_ALL | DIP_AFTER); - source_runtime(plugin_pattern_lua, DIP_ALL | DIP_AFTER); - TIME_MSG("loading after plugins"); - } -} /* * "-q errorfile": Load the error file now. diff --git a/src/nvim/mark.c b/src/nvim/mark.c index b296bf39cf..edec85c0b2 100644 --- a/src/nvim/mark.c +++ b/src/nvim/mark.c @@ -1637,6 +1637,15 @@ void get_buf_local_marks(const buf_T *buf, list_T *l) add_mark(l, "'>", &buf->b_visual.vi_end, buf->b_fnum, NULL); } +/// Get a global mark +/// +/// @param[in] Name of named mark +/// @param[out] Global/file mark +xfmark_T get_global_mark(char name) +{ + return namedfm[mark_global_index(name)]; +} + /// Get information about global marks ('A' to 'Z' and '0' to '9') /// /// @param[out] l List to store global marks diff --git a/src/nvim/menu.c b/src/nvim/menu.c index 2b1a250604..de8503f9d0 100644 --- a/src/nvim/menu.c +++ b/src/nvim/menu.c @@ -64,7 +64,7 @@ static vimmenu_T **get_root_menu(const char_u *const name) /// @param eap Ex command arguments void ex_menu(exarg_T *eap) { - char_u *menu_path; + char *menu_path; int modes; char_u *map_to; // command mapped to the menu entry int noremap; @@ -166,7 +166,7 @@ void ex_menu(exarg_T *eap) } - menu_path = arg; + menu_path = (char *)arg; if (*menu_path == '.') { EMSG2(_(e_invarg2), menu_path); goto theend; @@ -178,25 +178,25 @@ void ex_menu(exarg_T *eap) * If there is only a menu name, display menus with that name. */ if (*map_to == NUL && !unmenu && enable == kNone) { - show_menus(menu_path, modes); + show_menus((char_u *)menu_path, modes); goto theend; } else if (*map_to != NUL && (unmenu || enable != kNone)) { EMSG(_(e_trailing)); goto theend; } - vimmenu_T **root_menu_ptr = get_root_menu(menu_path); + vimmenu_T **root_menu_ptr = get_root_menu((char_u *)menu_path); if (enable != kNone) { // Change sensitivity of the menu. // For the PopUp menu, remove a menu for each mode separately. // Careful: menu_enable_recurse() changes menu_path. if (STRCMP(menu_path, "*") == 0) { // meaning: do all menus - menu_path = (char_u *)""; + menu_path = ""; } if (menu_is_popup(menu_path)) { - for (i = 0; i < MENU_INDEX_TIP; ++i) { + for (i = 0; i < MENU_INDEX_TIP; i++) { if (modes & (1 << i)) { p = popup_mode_name(menu_path, i); menu_enable_recurse(*root_menu_ptr, p, MENU_ALL_MODES, enable); @@ -204,20 +204,20 @@ void ex_menu(exarg_T *eap) } } } - menu_enable_recurse(*root_menu_ptr, menu_path, modes, enable); + menu_enable_recurse(*root_menu_ptr, (char_u *)menu_path, modes, enable); } else if (unmenu) { /* * Delete menu(s). */ if (STRCMP(menu_path, "*") == 0) { // meaning: remove all menus - menu_path = (char_u *)""; + menu_path = ""; } /* * For the PopUp menu, remove a menu for each mode separately. */ if (menu_is_popup(menu_path)) { - for (i = 0; i < MENU_INDEX_TIP; ++i) { + for (i = 0; i < MENU_INDEX_TIP; i++) { if (modes & (1 << i)) { p = popup_mode_name(menu_path, i); remove_menu(root_menu_ptr, p, MENU_ALL_MODES, true); @@ -227,7 +227,7 @@ void ex_menu(exarg_T *eap) } // Careful: remove_menu() changes menu_path - remove_menu(root_menu_ptr, menu_path, modes, false); + remove_menu(root_menu_ptr, (char_u *)menu_path, modes, false); } else { /* * Add menu(s). @@ -245,13 +245,13 @@ void ex_menu(exarg_T *eap) menuarg.modes = modes; menuarg.noremap[0] = noremap; menuarg.silent[0] = silent; - add_menu_path(menu_path, &menuarg, pri_tab, map_to); + add_menu_path((char_u *)menu_path, &menuarg, pri_tab, map_to); /* * For the PopUp menu, add a menu for each mode separately. */ if (menu_is_popup(menu_path)) { - for (i = 0; i < MENU_INDEX_TIP; ++i) { + for (i = 0; i < MENU_INDEX_TIP; i++) { if (modes & (1 << i)) { p = popup_mode_name(menu_path, i); // Include all modes, to make ":amenu" work @@ -1273,12 +1273,12 @@ int get_menu_cmd_modes(const char *cmd, bool forceit, int *noremap, int *unmenu) * Modify a menu name starting with "PopUp" to include the mode character. * Returns the name in allocated memory. */ -static char_u *popup_mode_name(char_u *name, int idx) +static char_u *popup_mode_name(char *name, int idx) { size_t len = STRLEN(name); assert(len >= 4); - char_u *p = vim_strnsave(name, len + 1); + char_u *p = vim_strnsave((char_u *)name, len + 1); memmove(p + 6, p + 5, len - 4); p[5] = menu_mode_chars[idx]; @@ -1337,14 +1337,14 @@ static char_u *menu_text(const char_u *str, int *mnemonic, char_u **actext) bool menu_is_menubar(const char_u *const name) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { - return !menu_is_popup(name) + return !menu_is_popup((char *)name) && !menu_is_toolbar(name) && !menu_is_winbar(name) && *name != MNU_HIDDEN_CHAR; } // Return true if "name" is a popup menu name. -bool menu_is_popup(const char_u *const name) +bool menu_is_popup(const char *const name) FUNC_ATTR_PURE FUNC_ATTR_WARN_UNUSED_RESULT FUNC_ATTR_NONNULL_ALL { return STRNCMP(name, "PopUp", 5) == 0; @@ -1374,7 +1374,7 @@ int menu_is_separator(char_u *name) static int menu_is_hidden(char_u *name) { return (name[0] == MNU_HIDDEN_CHAR) - || (menu_is_popup(name) && name[5] != NUL); + || (menu_is_popup((char *)name) && name[5] != NUL); } // Execute "menu". Use by ":emenu" and the window toolbar. @@ -1383,25 +1383,25 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu) FUNC_ATTR_NONNULL_ARG(2) { int idx = -1; - char_u *mode; + char *mode; // Use the Insert mode entry when returning to Insert mode. if (((State & INSERT) || restart_edit) && !current_sctx.sc_sid) { - mode = (char_u *)"Insert"; + mode = "Insert"; idx = MENU_INDEX_INSERT; } else if (State & CMDLINE) { - mode = (char_u *)"Command"; + mode = "Command"; idx = MENU_INDEX_CMDLINE; } else if (get_real_state() & VISUAL) { /* Detect real visual mode -- if we are really in visual mode we * don't need to do any guesswork to figure out what the selection * is. Just execute the visual binding for the menu. */ - mode = (char_u *)"Visual"; + mode = "Visual"; idx = MENU_INDEX_VISUAL; } else if (eap != NULL && eap->addr_count) { pos_T tpos; - mode = (char_u *)"Visual"; + mode = "Visual"; idx = MENU_INDEX_VISUAL; /* GEDDES: This is not perfect - but it is a @@ -1442,7 +1442,7 @@ static void execute_menu(const exarg_T *eap, vimmenu_T *menu) } if (idx == -1 || eap == NULL) { - mode = (char_u *)"Normal"; + mode = "Normal"; idx = MENU_INDEX_NORMAL; } diff --git a/src/nvim/message.c b/src/nvim/message.c index ed673b52d3..edde51e770 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -3191,7 +3191,7 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen) size_t len = maxlen == -1 ? STRLEN(s) : (size_t)maxlen; if (capture_ga) { - ga_concat_len(capture_ga, (const char *)str, len); + ga_concat_len(capture_ga, str, len); } if (redir_reg) { write_reg_contents(redir_reg, s, len, true); diff --git a/src/nvim/mouse.c b/src/nvim/mouse.c index cf463fd40a..f02c000e82 100644 --- a/src/nvim/mouse.c +++ b/src/nvim/mouse.c @@ -236,6 +236,11 @@ retnomove: redraw_curbuf_later(INVERTED); // delete the inversion } + if (grid == 0) { + row -= curwin->w_grid_alloc.comp_row+curwin->w_grid.row_offset; + col -= curwin->w_grid_alloc.comp_col+curwin->w_grid.col_offset; + } + // When clicking beyond the end of the window, scroll the screen. // Scroll by however many rows outside the window we are. if (row < 0) { @@ -476,7 +481,7 @@ win_T *mouse_find_win(int *gridp, int *rowp, int *colp) static win_T *mouse_find_grid_win(int *gridp, int *rowp, int *colp) { if (*gridp == msg_grid.handle) { - // rowp += msg_grid_pos; // PVS: dead store #11612 + *rowp += msg_grid_pos; *gridp = DEFAULT_GRID_HANDLE; } else if (*gridp > 1) { win_T *wp = get_win_by_grid_handle(*gridp); @@ -677,8 +682,8 @@ static int mouse_adjust_click(win_T *wp, int row, int col) vcol = offset; -#define incr() nudge++; ptr_end += utfc_ptr2len(ptr_end) -#define decr() nudge--; ptr_end -= utfc_ptr2len(ptr_end) +#define INCR() nudge++; ptr_end += utfc_ptr2len(ptr_end) +#define DECR() nudge--; ptr_end -= utfc_ptr2len(ptr_end) while (ptr < ptr_end && *ptr != NUL) { cwidth = win_chartabsize(curwin, ptr, vcol); @@ -687,7 +692,7 @@ static int mouse_adjust_click(win_T *wp, int row, int col) // A tab will "absorb" any previous adjustments. cwidth = MIN(cwidth, nudge); while (cwidth > 0) { - decr(); + DECR(); cwidth--; } } @@ -695,20 +700,20 @@ static int mouse_adjust_click(win_T *wp, int row, int col) matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); if (matchid != 0) { if (wp->w_p_cole == 3) { - incr(); + INCR(); } else { if (!(row > 0 && ptr == ptr_row_offset) && (wp->w_p_cole == 1 || (wp->w_p_cole == 2 && (wp->w_p_lcs_chars.conceal != NUL || syn_get_sub_char() != NUL)))) { // At least one placeholder character will be displayed. - decr(); + DECR(); } prev_matchid = matchid; while (prev_matchid == matchid && *ptr != NUL) { - incr(); + INCR(); ptr += utfc_ptr2len(ptr); matchid = syn_get_concealed_id(wp, lnum, (colnr_T)(ptr - line)); } diff --git a/src/nvim/move.c b/src/nvim/move.c index ca3dd34204..c4f8e81fa3 100644 --- a/src/nvim/move.c +++ b/src/nvim/move.c @@ -794,7 +794,7 @@ void curs_columns(win_T *wp, int may_scroll) // column char_u *const sbr = get_showbreak_value(wp); if (*sbr && *get_cursor_pos_ptr() == NUL - && wp->w_wcol == (int)vim_strsize(sbr)) { + && wp->w_wcol == vim_strsize(sbr)) { wp->w_wcol = 0; } } diff --git a/src/nvim/msgpack_rpc/helpers.c b/src/nvim/msgpack_rpc/helpers.c index b1b9c77953..549016e751 100644 --- a/src/nvim/msgpack_rpc/helpers.c +++ b/src/nvim/msgpack_rpc/helpers.c @@ -15,6 +15,7 @@ #include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS +# include "keysets.generated.h" # include "msgpack_rpc/helpers.c.generated.h" #endif diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index bbf70a4830..9675cfbb0f 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -134,7 +134,7 @@ bool os_isdir(const char_u *name) bool os_isdir_executable(const char *name) FUNC_ATTR_NONNULL_ALL { - int32_t mode = os_getperm((const char *)name); + int32_t mode = os_getperm(name); if (mode < 0) { return false; } diff --git a/src/nvim/os/os_win_console.c b/src/nvim/os/os_win_console.c index 2c9cb699fc..18e2e02b81 100644 --- a/src/nvim/os/os_win_console.c +++ b/src/nvim/os/os_win_console.c @@ -46,29 +46,3 @@ void os_replace_stdout_and_stderr_to_conout(void) const int conerr_fd = _open_osfhandle((intptr_t)conout_handle, 0); assert(conerr_fd == STDERR_FILENO); } - -void os_set_vtp(bool enable) -{ - static TriState is_legacy = kNone; - if (is_legacy == kNone) { - uv_tty_vtermstate_t state; - uv_tty_get_vterm_state(&state); - is_legacy = (state == UV_TTY_UNSUPPORTED) ? kTrue : kFalse; - } - if (!is_legacy && !os_has_vti()) { - uv_tty_set_vterm_state(enable ? UV_TTY_SUPPORTED : UV_TTY_UNSUPPORTED); - } -} - -static bool os_has_vti(void) -{ - static TriState has_vti = kNone; - if (has_vti == kNone) { - HANDLE handle = (HANDLE)_get_osfhandle(input_global_fd()); - DWORD dwMode; - if (handle != INVALID_HANDLE_VALUE && GetConsoleMode(handle, &dwMode)) { - has_vti = !!(dwMode & ENABLE_VIRTUAL_TERMINAL_INPUT) ? kTrue : kFalse; - } - } - return has_vti == kTrue; -} diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index eb0ba874f4..046e6dbd12 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -1823,7 +1823,7 @@ static int qf_add_entry(qf_list_T *qfl, char_u *dir, char_u *fname, char_u *modu if (type != 1 && !vim_isprintc(type)) { // only printable chars allowed type = 0; } - qfp->qf_type = (char_u)type; + qfp->qf_type = type; qfp->qf_valid = valid; lastp = &qfl->qf_last; diff --git a/src/nvim/runtime.c b/src/nvim/runtime.c index 7b72efce23..0e2d23e69b 100644 --- a/src/nvim/runtime.c +++ b/src/nvim/runtime.c @@ -5,8 +5,8 @@ /// /// Management of runtime files (including packages) -#include "nvim/ascii.h" #include "nvim/api/private/helpers.h" +#include "nvim/ascii.h" #include "nvim/charset.h" #include "nvim/eval.h" #include "nvim/ex_cmds.h" @@ -169,9 +169,9 @@ int do_in_path(char_u *path, char_u *name, int flags, DoInRuntimepathCB callback int do_in_cached_path(char_u *name, int flags, DoInRuntimepathCB callback, void *cookie) { runtime_search_path_validate(); - char_u *tail; + char_u *tail; int num_files; - char_u **files; + char_u **files; int i; bool did_one = false; @@ -332,40 +332,56 @@ int do_in_path_and_pp(char_u *path, char_u *name, int flags, DoInRuntimepathCB c return done; } -static void push_path(RuntimeSearchPath *search_path, char *entry, bool after) +static void push_path(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used, + char *entry, bool after) { - kv_push(*search_path, ((SearchPathItem){ entry, after })); + handle_T h = map_get(String, handle_T)(rtp_used, cstr_as_string(entry)); + if (h == 0) { + char *allocated = xstrdup(entry); + map_put(String, handle_T)(rtp_used, cstr_as_string(allocated), 1); + kv_push(*search_path, ((SearchPathItem){ allocated, after })); + } } -static void expand_pack_entry(RuntimeSearchPath *search_path, CharVec *after_path, - char_u *pack_entry) +static void expand_rtp_entry(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used, + char *entry, bool after) { - static char_u buf[MAXPATHL], buf2[MAXPATHL]; - char *start_dir = "/pack/*/start/*"; // NOLINT - if (STRLEN(pack_entry) + STRLEN(start_dir) + 1 < MAXPATHL) { - xstrlcpy((char *)buf, (char *)pack_entry, MAXPATHL); - xstrlcpy((char *)buf2, (char *)pack_entry, MAXPATHL); - xstrlcat((char *)buf, start_dir, sizeof buf); - xstrlcat((char *)buf2, "/start/*", sizeof buf); // NOLINT - int num_files; - char_u **files; - - char_u *(pat[]) = { buf, buf2 }; - if (gen_expand_wildcards(2, pat, &num_files, &files, EW_DIR) == OK) { - for (int i = 0; i < num_files; i++) { - push_path(search_path, xstrdup((char *)files[i]), false); - size_t after_size = STRLEN(files[i])+7; - char *after = xmallocz(after_size); - xstrlcpy(after, (char *)files[i], after_size); - xstrlcat(after, "/after", after_size); - if (os_isdir((char_u *)after)) { - kv_push(*after_path, after); - } else { - xfree(after); - } - } - FreeWild(num_files, files); + if (map_get(String, handle_T)(rtp_used, cstr_as_string(entry))) { + return; + } + + if (!*entry) { + push_path(search_path, rtp_used, entry, after); + } + + int num_files; + char_u **files; + char_u *(pat[]) = { (char_u *)entry }; + if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR) == OK) { + for (int i = 0; i < num_files; i++) { + push_path(search_path, rtp_used, (char *)files[i], after); } + FreeWild(num_files, files); + } +} + +static void expand_pack_entry(RuntimeSearchPath *search_path, Map(String, handle_T) *rtp_used, + CharVec *after_path, char_u *pack_entry) +{ + static char buf[MAXPATHL]; + char *(start_pat[]) = { "/pack/*/start/*", "/start/*" }; // NOLINT + for (int i = 0; i < 2; i++) { + if (STRLEN(pack_entry) + STRLEN(start_pat[i]) + 1 > MAXPATHL) { + continue; + } + xstrlcpy(buf, (char *)pack_entry, MAXPATHL); + xstrlcat(buf, start_pat[i], sizeof buf); + expand_rtp_entry(search_path, rtp_used, buf, false); + size_t after_size = STRLEN(buf)+7; + char *after = xmallocz(after_size); + xstrlcpy(after, buf, after_size); + xstrlcat(after, "/after", after_size); + kv_push(*after_path, after); } } @@ -382,8 +398,10 @@ static bool path_is_after(char_u *buf, size_t buflen) RuntimeSearchPath runtime_search_path_build(void) { kvec_t(String) pack_entries = KV_INITIAL_VALUE; + // TODO(bfredl): these should just be sets, when Set(String) is do merge to + // master. Map(String, handle_T) pack_used = MAP_INIT; - // TODO(bfredl): add a set of existing rtp entries to not duplicate those + Map(String, handle_T) rtp_used = MAP_INIT; RuntimeSearchPath search_path = KV_INITIAL_VALUE; CharVec after_path = KV_INITIAL_VALUE; @@ -410,37 +428,40 @@ RuntimeSearchPath runtime_search_path_build(void) break; } - push_path(&search_path, xstrdup((char *)buf), false); + // fact: &rtp entries can contain wild chars + expand_rtp_entry(&search_path, &rtp_used, (char *)buf, false); handle_T *h = map_ref(String, handle_T)(&pack_used, cstr_as_string((char *)buf), false); if (h) { (*h)++; - expand_pack_entry(&search_path, &after_path, buf); + expand_pack_entry(&search_path, &rtp_used, &after_path, buf); } } for (size_t i = 0; i < kv_size(pack_entries); i++) { handle_T h = map_get(String, handle_T)(&pack_used, kv_A(pack_entries, i)); if (h == 0) { - expand_pack_entry(&search_path, &after_path, (char_u *)kv_A(pack_entries, i).data); + expand_pack_entry(&search_path, &rtp_used, &after_path, (char_u *)kv_A(pack_entries, i).data); } } // "after" packages for (size_t i = 0; i < kv_size(after_path); i++) { - push_path(&search_path, kv_A(after_path, i), true); + expand_rtp_entry(&search_path, &rtp_used, kv_A(after_path, i), true); + xfree(kv_A(after_path, i)); } // "after" dirs in rtp for (; *rtp_entry != NUL;) { copy_option_part((char_u **)&rtp_entry, buf, MAXPATHL, ","); - push_path(&search_path, xstrdup((char *)buf), path_is_after(buf, STRLEN(buf))); + expand_rtp_entry(&search_path, &rtp_used, (char *)buf, path_is_after(buf, STRLEN(buf))); } // strings are not owned kv_destroy(pack_entries); kv_destroy(after_path); map_destroy(String, handle_T)(&pack_used); + map_destroy(String, handle_T)(&rtp_used); return search_path; } @@ -452,11 +473,11 @@ void runtime_search_path_invalidate(void) void runtime_search_path_free(RuntimeSearchPath path) { - for (size_t j = 0; j < kv_size(path); j++) { - SearchPathItem item = kv_A(path, j); - xfree(item.path); - } - kv_destroy(path); + for (size_t j = 0; j < kv_size(path); j++) { + SearchPathItem item = kv_A(path, j); + xfree(item.path); + } + kv_destroy(path); } void runtime_search_path_validate(void) @@ -521,7 +542,10 @@ static void source_all_matches(char_u *pat) } /// Add the package directory to 'runtimepath' -static int add_pack_dir_to_rtp(char_u *fname) +/// +/// @param fname the package path +/// @param is_pack whether the added dir is a "pack/*/start/*/" style package +static int add_pack_dir_to_rtp(char_u *fname, bool is_pack) { char_u *p4, *p3, *p2, *p1, *p; char_u *buf = NULL; @@ -599,7 +623,7 @@ static int add_pack_dir_to_rtp(char_u *fname) // check if rtp/pack/name/start/name/after exists afterdir = concat_fnames((char *)fname, "after", true); size_t afterlen = 0; - if (os_isdir((char_u *)afterdir)) { + if (is_pack ? pack_has_entries((char_u *)afterdir) : os_isdir((char_u *)afterdir)) { afterlen = strlen(afterdir) + 1; // add one for comma } @@ -720,7 +744,7 @@ static void add_pack_plugin(bool opt, char_u *fname, void *cookie) xfree(buf); if (!found) { // directory is not yet in 'runtimepath', add it - if (add_pack_dir_to_rtp(fname) == FAIL) { + if (add_pack_dir_to_rtp(fname, false) == FAIL) { return; } } @@ -741,6 +765,41 @@ static void add_opt_pack_plugin(char_u *fname, void *cookie) add_pack_plugin(true, fname, cookie); } + +/// Add all packages in the "start" directory to 'runtimepath'. +void add_pack_start_dirs(void) +{ + do_in_path(p_pp, NULL, DIP_ALL + DIP_DIR, add_pack_start_dir, NULL); +} + +static bool pack_has_entries(char_u *buf) +{ + int num_files; + char_u **files; + char_u *(pat[]) = { buf }; + if (gen_expand_wildcards(1, pat, &num_files, &files, EW_DIR) == OK) { + FreeWild(num_files, files); + } + return num_files > 0; +} + +static void add_pack_start_dir(char_u *fname, void *cookie) +{ + static char_u buf[MAXPATHL]; + char *(start_pat[]) = { "/start/*", "/pack/*/start/*" }; // NOLINT + for (int i = 0; i < 2; i++) { + if (STRLEN(fname) + STRLEN(start_pat[i]) + 1 > MAXPATHL) { + continue; + } + xstrlcpy((char *)buf, (char *)fname, MAXPATHL); + xstrlcat((char *)buf, start_pat[i], sizeof buf); + if (pack_has_entries(buf)) { + add_pack_dir_to_rtp(buf, true); + } + } +} + + /// Load plugins from all packages in the "start" directory. void load_start_packages(void) { @@ -759,10 +818,43 @@ void ex_packloadall(exarg_T *eap) // First do a round to add all directories to 'runtimepath', then load // the plugins. This allows for plugins to use an autoload directory // of another plugin. + add_pack_start_dirs(); load_start_packages(); } } +/// Read all the plugin files at startup +void load_plugins(void) +{ + if (p_lpl) { + char_u *rtp_copy = p_rtp; + char_u *const plugin_pattern_vim = (char_u *)"plugin/**/*.vim"; // NOLINT + char_u *const plugin_pattern_lua = (char_u *)"plugin/**/*.lua"; // NOLINT + + if (!did_source_packages) { + rtp_copy = vim_strsave(p_rtp); + add_pack_start_dirs(); + } + + // don't use source_runtime() yet so we can check for :packloadall below + source_in_path(rtp_copy, plugin_pattern_vim, DIP_ALL | DIP_NOAFTER); + source_in_path(rtp_copy, plugin_pattern_lua, DIP_ALL | DIP_NOAFTER); + TIME_MSG("loading rtp plugins"); + + // Only source "start" packages if not done already with a :packloadall + // command. + if (!did_source_packages) { + xfree(rtp_copy); + load_start_packages(); + } + TIME_MSG("loading packages"); + + source_runtime(plugin_pattern_vim, DIP_ALL | DIP_AFTER); + source_runtime(plugin_pattern_lua, DIP_ALL | DIP_AFTER); + TIME_MSG("loading after plugins"); + } +} + /// ":packadd[!] {name}" void ex_packadd(exarg_T *eap) { diff --git a/src/nvim/screen.c b/src/nvim/screen.c index 98d8722ec8..fcd8fb1118 100644 --- a/src/nvim/screen.c +++ b/src/nvim/screen.c @@ -4545,8 +4545,8 @@ void draw_virt_text(buf_T *buf, int col_off, int *end_col, int max_col) } } -static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, - int max_col, int vcol) +static int draw_virt_text_item(buf_T *buf, int col, VirtText vt, HlMode hl_mode, int max_col, + int vcol) { LineState s = LINE_STATE(""); int virt_attr = 0; diff --git a/src/nvim/shada.c b/src/nvim/shada.c index bf245bec51..0cec28c4de 100644 --- a/src/nvim/shada.c +++ b/src/nvim/shada.c @@ -65,26 +65,6 @@ KHASH_SET_INIT_INT64(bufset) KHASH_MAP_INIT_STR(fnamebufs, buf_T *) KHASH_SET_INIT_STR(strset) -#define copy_option_part(src, dest, ...) \ - ((char *)copy_option_part((char_u **)src, (char_u *)dest, __VA_ARGS__)) -#define find_shada_parameter(...) \ - ((const char *)find_shada_parameter(__VA_ARGS__)) -#define home_replace_save(a, b) \ - ((char *)home_replace_save(a, (char_u *)b)) -#define home_replace(a, b, c, d, e) \ - home_replace(a, (char_u *)b, (char_u *)c, d, e) -#define vim_rename(a, b) \ - (vim_rename((char_u *)a, (char_u *)b)) -#define mb_strnicmp(a, b, c) \ - (mb_strnicmp((char_u *)a, (char_u *)b, c)) -#define path_try_shorten_fname(b) \ - ((char *)path_try_shorten_fname((char_u *)b)) -#define buflist_new(ffname, sfname, ...) \ - (buflist_new((char_u *)ffname, (char_u *)sfname, __VA_ARGS__)) -#define os_isdir(f) (os_isdir((char_u *)f)) -#define regtilde(s, m) ((char *)regtilde((char_u *)s, m)) -#define path_tail_with_sep(f) ((char *)path_tail_with_sep((char_u *)f)) - #define SEARCH_KEY_MAGIC "sm" #define SEARCH_KEY_SMARTCASE "sc" #define SEARCH_KEY_HAS_LINE_OFFSET "sl" @@ -624,20 +604,6 @@ static inline void hmll_insert(HMLList *const hmll, HMLListEntry *hmll_entry, co } } -/// Iterate over HMLList in backward direction -/// -/// @param hmll Pointer to the list. -/// @param cur_entry Name of the variable to iterate over, must be already -/// defined. -/// @param code Code to execute on each iteration. -/// -/// @return `for` cycle header (use `HMLL_FORALL(hmll, cur_entry) {body}`). -#define HMLL_ITER_BACK(hmll, cur_entry, code) \ - for (cur_entry = (hmll)->last; cur_entry != NULL; \ - cur_entry = cur_entry->prev) { \ - code \ - } - /// Free linked list /// /// @param[in] hmll List to free. @@ -981,11 +947,12 @@ static void hms_insert(HistoryMergerState *const hms_p, const ShadaEntry entry, } } HMLListEntry *insert_after; - HMLL_ITER_BACK(hmll, insert_after, { + // Iterate over HMLList in backward direction + for (insert_after = hmll->last; insert_after != NULL; insert_after = insert_after->prev) { if (insert_after->data.timestamp <= entry.timestamp) { break; } - }) + } hmll_insert(hmll, insert_after, entry, can_free_entry); } @@ -1271,7 +1238,7 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) // string is close to useless: you can only use it with :& or :~ and // that’s all because s//~ is not available until the first call to // regtilde. Vim was not calling this for some reason. - (void)regtilde(cur_entry.data.sub_string.sub, p_magic); + (void)(char *)regtilde((char_u *)cur_entry.data.sub_string.sub, p_magic); // Do not free shada entry: its allocated memory was saved above. break; case kSDItemHistoryEntry: @@ -1361,9 +1328,11 @@ static void shada_read(ShaDaReadDef *const sd_reader, const int flags) } case kSDItemBufferList: for (size_t i = 0; i < cur_entry.data.buffer_list.size; i++) { - char *const sfname = path_try_shorten_fname(cur_entry.data.buffer_list.buffers[i].fname); - buf_T *const buf = buflist_new(cur_entry.data.buffer_list.buffers[i].fname, sfname, 0, - BLN_LISTED); + char *const sfname = + (char *)path_try_shorten_fname((char_u *)cur_entry.data.buffer_list.buffers[i].fname); + buf_T *const buf = + buflist_new((char_u *)cur_entry.data.buffer_list.buffers[i].fname, (char_u *)sfname, 0, + BLN_LISTED); if (buf != NULL) { RESET_FMARK(&buf->b_last_cursor, cur_entry.data.buffer_list.buffers[i].pos, 0); @@ -1502,7 +1471,7 @@ static char *shada_filename(const char *file) if (p_shadafile != NULL && *p_shadafile != NUL) { file = p_shadafile; } else { - if ((file = find_shada_parameter('n')) == NULL || *file == NUL) { + if ((file = (char *)find_shada_parameter('n')) == NULL || *file == NUL) { file = shada_get_default_file(); } // XXX It used to be one level lower, so that whatever is in @@ -1522,14 +1491,6 @@ static char *shada_filename(const char *file) msgpack_pack_str(spacker, sizeof(s) - 1); \ msgpack_pack_str_body(spacker, s, sizeof(s) - 1); \ } while (0) -#define PACK_STRING(s) \ - do { \ - const String s_ = (s); \ - msgpack_pack_str(spacker, s_.size); \ - if (s_.size) { \ - msgpack_pack_str_body(spacker, s_.data, s_.size); \ - } \ - } while (0) #define PACK_BIN(s) \ do { \ const String s_ = (s); \ @@ -1810,7 +1771,11 @@ static ShaDaWriteResult shada_pack_entry(msgpack_packer *const packer, ShadaEntr case kSDItemHeader: msgpack_pack_map(spacker, entry.data.header.size); for (size_t i = 0; i < entry.data.header.size; i++) { - PACK_STRING(entry.data.header.items[i].key); + const String s = entry.data.header.items[i].key; + msgpack_pack_str(spacker, s.size); + if (s.size) { + msgpack_pack_str_body(spacker, s.data, s.size); + } const Object obj = entry.data.header.items[i].value; switch (obj.type) { case kObjectTypeString: @@ -1856,7 +1821,6 @@ shada_pack_entry_error: msgpack_sbuffer_destroy(&sbuf); return ret; } -#undef PACK_STRING /// Write single ShaDa entry and free it afterwards /// @@ -2694,7 +2658,7 @@ static ShaDaWriteResult shada_write(ShaDaWriteDef *const sd_writer, ShaDaReadDef .timestamp = sub.timestamp, .data = { .sub_string = { - .sub = (char *)sub.sub, + .sub = sub.sub, .additional_elements = sub.additional_elements, } } @@ -2957,7 +2921,6 @@ shada_write_exit: return ret; } -#undef IGNORE_BUF #undef PACK_STATIC_STR /// Write ShaDa file to a given location @@ -3037,11 +3000,11 @@ shada_write_file_open: {} } if (nomerge) { shada_write_file_nomerge: {} - char *const tail = path_tail_with_sep(fname); + char *const tail = (char *)path_tail_with_sep((char_u *)fname); if (tail != fname) { const char tail_save = *tail; *tail = NUL; - if (!os_isdir(fname)) { + if (!os_isdir((char_u *)fname)) { int ret; char *failed_dir; if ((ret = os_mkdir_recurse(fname, 0700, &failed_dir)) != 0) { @@ -3092,7 +3055,7 @@ shada_write_file_nomerge: {} // overwrite a user’s viminfo file after a "su root", with a // viminfo file that the user can't read. FileInfo old_info; - if (os_fileinfo((char *)fname, &old_info)) { + if (os_fileinfo(fname, &old_info)) { if (getuid() == ROOT_UID) { if (old_info.stat.st_uid != ROOT_UID || old_info.stat.st_gid != getgid()) { @@ -3116,7 +3079,7 @@ shada_write_file_nomerge: {} } } #endif - if (vim_rename(tempname, fname) == -1) { + if (vim_rename((char_u *)tempname, (char_u *)fname) == -1) { EMSG3(_(RNERR "Can't rename ShaDa file from %s to %s!"), tempname, fname); } else { @@ -3424,8 +3387,7 @@ static ShaDaReadResult msgpack_read_uint64(ShaDaReadDef *const sd_reader, const sizeof(*un.data.via.map.ptr)); \ ad_ga.ga_len++; \ } -#define CONVERTED(str, len) (xmemdupz((str), (len))) -#define BIN_CONVERTED(b) CONVERTED(b.ptr, b.size) +#define BIN_CONVERTED(b) (xmemdupz((b.ptr), (b.size))) #define SET_ADDITIONAL_DATA(tgt, name) \ do { \ if (ad_ga.ga_len) { \ @@ -3982,7 +3944,6 @@ shada_read_next_item_error: goto shada_read_next_item_end; } #undef BIN_CONVERTED -#undef CONVERTED #undef CHECK_KEY #undef BOOLEAN_KEY #undef CONVERTED_STRING_KEY @@ -4015,13 +3976,13 @@ static bool shada_removable(const char *name) char part[MAXPATHL + 1]; bool retval = false; - char *new_name = home_replace_save(NULL, name); + char *new_name = (char *)home_replace_save(NULL, (char_u *)name); for (p = (char *)p_shada; *p; ) { - (void)copy_option_part(&p, part, ARRAY_SIZE(part), ", "); + (void)(char *)copy_option_part((char_u **)&p, (char_u *)part, ARRAY_SIZE(part), ", "); if (part[0] == 'r') { - home_replace(NULL, part + 1, NameBuff, MAXPATHL, true); + home_replace(NULL, (char_u *)(part + 1), (char_u *)NameBuff, MAXPATHL, true); size_t n = STRLEN(NameBuff); - if (mb_strnicmp(NameBuff, new_name, n) == 0) { + if (mb_strnicmp((char_u *)NameBuff, (char_u *)new_name, n) == 0) { retval = true; break; } diff --git a/src/nvim/spell.c b/src/nvim/spell.c index 3e56ad561b..450ec891ad 100644 --- a/src/nvim/spell.c +++ b/src/nvim/spell.c @@ -6073,7 +6073,7 @@ static void spell_soundfold_wsal(slang_T *slang, char_u *inword, char_u *res) wordlen = 0; for (const char_u *s = inword; *s != NUL; ) { const char_u *t = s; - c = mb_cptr2char_adv((const char_u **)&s); + c = mb_cptr2char_adv(&s); if (slang->sl_rem_accents) { if (utf_class(c) == 0) { if (did_white) { diff --git a/src/nvim/state.c b/src/nvim/state.c index a9f3d67849..04271d750c 100644 --- a/src/nvim/state.c +++ b/src/nvim/state.c @@ -161,6 +161,11 @@ char *get_mode(void) if (State & VREPLACE_FLAG) { buf[0] = 'R'; buf[1] = 'v'; + if (ins_compl_active()) { + buf[2] = 'c'; + } else if (ctrl_x_mode_not_defined_yet()) { + buf[2] = 'x'; + } } else { if (State & REPLACE_FLAG) { buf[0] = 'R'; diff --git a/src/nvim/strings.c b/src/nvim/strings.c index 79a3db4843..11c1aa1760 100644 --- a/src/nvim/strings.c +++ b/src/nvim/strings.c @@ -1,28 +1,26 @@ // This is an open source non-commercial project. Dear PVS-Studio, please check // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com +#include <assert.h> #include <inttypes.h> +#include <math.h> #include <stdarg.h> #include <stdbool.h> #include <string.h> -#include <math.h> -#include <assert.h> -#include "nvim/assert.h" -#include "nvim/vim.h" #include "nvim/ascii.h" -#include "nvim/strings.h" -#include "nvim/file_search.h" +#include "nvim/assert.h" #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/diff.h" #include "nvim/edit.h" #include "nvim/eval.h" +#include "nvim/eval/encode.h" #include "nvim/ex_cmds.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" +#include "nvim/file_search.h" #include "nvim/fileio.h" -#include "nvim/func_attr.h" #include "nvim/fold.h" #include "nvim/func_attr.h" #include "nvim/getchar.h" @@ -35,8 +33,10 @@ #include "nvim/message.h" #include "nvim/misc1.h" #include "nvim/move.h" -#include "nvim/option.h" #include "nvim/ops.h" +#include "nvim/option.h" +#include "nvim/os/os.h" +#include "nvim/os/shell.h" #include "nvim/os_unix.h" #include "nvim/path.h" #include "nvim/quickfix.h" @@ -44,12 +44,11 @@ #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/spell.h" +#include "nvim/strings.h" #include "nvim/syntax.h" #include "nvim/tag.h" +#include "nvim/vim.h" #include "nvim/window.h" -#include "nvim/os/os.h" -#include "nvim/os/shell.h" -#include "nvim/eval/encode.h" /// Copy "string" into newly allocated memory. char_u *vim_strsave(const char_u *string) @@ -84,8 +83,7 @@ char_u *vim_strsave_escaped(const char_u *string, const char_u *esc_chars) * characters where rem_backslash() would remove the backslash. * Escape the characters with "cc". */ -char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, - char_u cc, bool bsl) +char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, char_u cc, bool bsl) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { /* @@ -100,9 +98,10 @@ char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, p += l - 1; continue; } - if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) - ++length; /* count a backslash */ - ++length; /* count an ordinary char */ + if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) { + ++length; // count a backslash + } + ++length; // count an ordinary char } char_u *escaped_string = xmalloc(length); @@ -112,11 +111,12 @@ char_u *vim_strsave_escaped_ext(const char_u *string, const char_u *esc_chars, if (l > 1) { memcpy(p2, p, l); p2 += l; - p += l - 1; /* skip multibyte char */ + p += l - 1; // skip multibyte char continue; } - if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) + if (vim_strchr(esc_chars, *p) != NULL || (bsl && rem_backslash(p))) { *p2++ = cc; + } *p2++ = *p; } *p2 = NUL; @@ -182,12 +182,11 @@ char *vim_strnsave_unquoted(const char *const string, const size_t length) * When "do_newline" is false do not escape newline unless it is csh shell. * Returns the result in allocated memory. */ -char_u *vim_strsave_shellescape(const char_u *string, - bool do_special, bool do_newline) +char_u *vim_strsave_shellescape(const char_u *string, bool do_special, bool do_newline) FUNC_ATTR_NONNULL_RET FUNC_ATTR_MALLOC FUNC_ATTR_NONNULL_ALL { - char_u *d; - char_u *escaped_string; + char_u *d; + char_u *escaped_string; size_t l; int csh_like; bool fish_like; @@ -202,7 +201,7 @@ char_u *vim_strsave_shellescape(const char_u *string, // itself must be escaped to get a literal '\'. fish_like = fish_like_shell(); - /* First count the number of extra bytes required. */ + // First count the number of extra bytes required. size_t length = STRLEN(string) + 3; // two quotes and a trailing NUL for (const char_u *p = string; *p != NUL; MB_PTR_ADV(p)) { #ifdef WIN32 @@ -217,12 +216,13 @@ char_u *vim_strsave_shellescape(const char_u *string, } if ((*p == '\n' && (csh_like || do_newline)) || (*p == '!' && (csh_like || do_special))) { - ++length; /* insert backslash */ - if (csh_like && do_special) - ++length; /* insert backslash */ + ++length; // insert backslash + if (csh_like && do_special) { + ++length; // insert backslash + } } if (do_special && find_cmdline_var(p, &l) >= 0) { - ++length; /* insert backslash */ + ++length; // insert backslash p += l - 1; } if (*p == '\\' && fish_like) { @@ -230,7 +230,7 @@ char_u *vim_strsave_shellescape(const char_u *string, } } - /* Allocate memory for the result and fill it. */ + // Allocate memory for the result and fill it. escaped_string = xmalloc(length); d = escaped_string; @@ -264,15 +264,17 @@ char_u *vim_strsave_shellescape(const char_u *string, if ((*p == '\n' && (csh_like || do_newline)) || (*p == '!' && (csh_like || do_special))) { *d++ = '\\'; - if (csh_like && do_special) + if (csh_like && do_special) { *d++ = '\\'; + } *d++ = *p++; continue; } if (do_special && find_cmdline_var(p, &l) >= 0) { - *d++ = '\\'; /* insert backslash */ - while (--l != SIZE_MAX) /* copy the var */ + *d++ = '\\'; // insert backslash + while (--l != SIZE_MAX) { // copy the var *d++ = *p++; + } continue; } if (*p == '\\' && fish_like) { @@ -285,11 +287,11 @@ char_u *vim_strsave_shellescape(const char_u *string, } // add terminating quote and finish with a NUL -# ifdef WIN32 +#ifdef WIN32 if (!p_ssl) { *d++ = '"'; } else -# endif +#endif *d++ = '\''; *d = NUL; @@ -384,11 +386,12 @@ char *strcase_save(const char *const orig, bool upper) void del_trailing_spaces(char_u *ptr) FUNC_ATTR_NONNULL_ALL { - char_u *q; + char_u *q; q = ptr + STRLEN(ptr); - while (--q > ptr && ascii_iswhite(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V) + while (--q > ptr && ascii_iswhite(q[0]) && q[-1] != '\\' && q[-1] != Ctrl_V) { *q = NUL; + } } #if (!defined(HAVE_STRCASECMP) && !defined(HAVE_STRICMP)) @@ -404,14 +407,16 @@ int vim_stricmp(const char *s1, const char *s2) for (;; ) { i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2); - if (i != 0) - return i; /* this character different */ - if (*s1 == NUL) - break; /* strings match until NUL */ + if (i != 0) { + return i; // this character different + } + if (*s1 == NUL) { + break; // strings match until NUL + } ++s1; ++s2; } - return 0; /* strings match */ + return 0; // strings match } #endif @@ -428,15 +433,17 @@ int vim_strnicmp(const char *s1, const char *s2, size_t len) while (len > 0) { i = (int)TOLOWER_LOC(*s1) - (int)TOLOWER_LOC(*s2); - if (i != 0) - return i; /* this character different */ - if (*s1 == NUL) - break; /* strings match until NUL */ + if (i != 0) { + return i; // this character different + } + if (*s1 == NUL) { + break; // strings match until NUL + } ++s1; ++s2; --len; } - return 0; /* strings match */ + return 0; // strings match } #endif @@ -490,10 +497,13 @@ bool has_non_ascii(const char_u *s) { const char_u *p; - if (s != NULL) - for (p = s; *p != NUL; ++p) - if (*p >= 128) + if (s != NULL) { + for (p = s; *p != NUL; ++p) { + if (*p >= 128) { return true; + } + } + } return false; } @@ -504,7 +514,7 @@ bool has_non_ascii_len(const char *const s, const size_t len) { if (s != NULL) { for (size_t i = 0; i < len; i++) { - if ((uint8_t) s[i] >= 128) { + if ((uint8_t)s[i] >= 128) { return true; } } @@ -527,7 +537,7 @@ char_u *concat_str(const char_u *restrict str1, const char_u *restrict str2) static const char *const e_printf = - N_("E766: Insufficient arguments for printf()"); + N_("E766: Insufficient arguments for printf()"); /// Get number argument from idxp entry in tvs /// @@ -606,15 +616,14 @@ static const void *tv_ptr(const typval_T *const tvs, int *const idxp) FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT { #define OFF(attr) offsetof(union typval_vval_union, attr) - STATIC_ASSERT( - OFF(v_string) == OFF(v_list) - && OFF(v_string) == OFF(v_dict) - && OFF(v_string) == OFF(v_partial) - && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list) - && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict) - && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial), - "Strings, dictionaries, lists and partials are expected to be pointers, " - "so that all three of them can be accessed via v_string"); + STATIC_ASSERT(OFF(v_string) == OFF(v_list) + && OFF(v_string) == OFF(v_dict) + && OFF(v_string) == OFF(v_partial) + && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_list) + && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_dict) + && sizeof(tvs[0].vval.v_string) == sizeof(tvs[0].vval.v_partial), + "Strings, dictionaries, lists and partials are expected to be pointers, " + "so that all three of them can be accessed via v_string"); #undef OFF const int idx = *idxp - 1; if (tvs[idx].v_type == VAR_UNKNOWN) { @@ -735,8 +744,8 @@ int vim_snprintf(char *str, size_t str_m, const char *fmt, ...) // Return the representation of infinity for printf() function: // "-inf", "inf", "+inf", " inf", "-INF", "INF", "+INF" or " INF". -static const char *infinity_str(bool positive, char fmt_spec, - int force_sign, int space_for_positive) +static const char *infinity_str(bool positive, char fmt_spec, int force_sign, + int space_for_positive) { static const char *table[] = { "-inf", "inf", "+inf", " inf", @@ -765,8 +774,7 @@ int vim_vsnprintf(char *str, size_t str_m, const char *fmt, va_list ap) /// /// @return Number of bytes excluding NUL byte that would be written to the /// string if str_m was greater or equal to the return value. -int vim_vsnprintf_typval( - char *str, size_t str_m, const char *fmt, va_list ap, typval_T *const tvs) +int vim_vsnprintf_typval(char *str, size_t str_m, const char *fmt, va_list ap, typval_T *const tvs) { size_t str_l = 0; bool str_avail = str_l < str_m; @@ -800,7 +808,7 @@ int vim_vsnprintf_typval( char length_modifier = '\0'; // temporary buffer for simple numeric->string conversion -# define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable +#define TMP_LEN 350 // 1e308 seems reasonable as the maximum printable char tmp[TMP_LEN]; // string address in case of string argument @@ -832,15 +840,22 @@ int vim_vsnprintf_typval( // parse flags while (true) { switch (*p) { - case '0': zero_padding = 1; p++; continue; - case '-': justify_left = 1; p++; continue; - // if both '0' and '-' flags appear, '0' should be ignored - case '+': force_sign = 1; space_for_positive = 0; p++; continue; - case ' ': force_sign = 1; p++; continue; - // if both ' ' and '+' flags appear, ' ' should be ignored - case '#': alternate_form = 1; p++; continue; - case '\'': p++; continue; - default: break; + case '0': + zero_padding = 1; p++; continue; + case '-': + justify_left = 1; p++; continue; + // if both '0' and '-' flags appear, '0' should be ignored + case '+': + force_sign = 1; space_for_positive = 0; p++; continue; + case ' ': + force_sign = 1; p++; continue; + // if both ' ' and '+' flags appear, ' ' should be ignored + case '#': + alternate_form = 1; p++; continue; + case '\'': + p++; continue; + default: + break; } break; } @@ -905,444 +920,447 @@ int vim_vsnprintf_typval( // common synonyms switch (fmt_spec) { - case 'i': fmt_spec = 'd'; break; - case 'D': fmt_spec = 'd'; length_modifier = 'l'; break; - case 'U': fmt_spec = 'u'; length_modifier = 'l'; break; - case 'O': fmt_spec = 'o'; length_modifier = 'l'; break; - default: break; + case 'i': + fmt_spec = 'd'; break; + case 'D': + fmt_spec = 'd'; length_modifier = 'l'; break; + case 'U': + fmt_spec = 'u'; length_modifier = 'l'; break; + case 'O': + fmt_spec = 'o'; length_modifier = 'l'; break; + default: + break; } switch (fmt_spec) { - case 'b': case 'B': - case 'd': case 'u': case 'o': case 'x': case 'X': - if (tvs && length_modifier == '\0') { - length_modifier = '2'; - } + case 'b': + case 'B': + case 'd': + case 'u': + case 'o': + case 'x': + case 'X': + if (tvs && length_modifier == '\0') { + length_modifier = '2'; + } } // get parameter value, do initial processing switch (fmt_spec) { - // '%' and 'c' behave similar to 's' regarding flags and field widths - case '%': case 'c': case 's': case 'S': - str_arg_l = 1; - switch (fmt_spec) { - case '%': - str_arg = p; - break; - - case 'c': { - const int j = tvs ? (int)tv_nr(tvs, &arg_idx) : va_arg(ap, int); - // standard demands unsigned char - uchar_arg = (unsigned char)j; - str_arg = (char *)&uchar_arg; - break; - } + // '%' and 'c' behave similar to 's' regarding flags and field widths + case '%': + case 'c': + case 's': + case 'S': + str_arg_l = 1; + switch (fmt_spec) { + case '%': + str_arg = p; + break; - case 's': - case 'S': - str_arg = tvs ? tv_str(tvs, &arg_idx, &tofree) - : va_arg(ap, const char *); - if (!str_arg) { - str_arg = "[NULL]"; - str_arg_l = 6; - } else if (!precision_specified) { - // make sure not to address string beyond the specified - // precision - str_arg_l = strlen(str_arg); - } else if (precision == 0) { - // truncate string if necessary as requested by precision - str_arg_l = 0; - } else { - // memchr on HP does not like n > 2^31 - // TODO(elmart): check if this still holds / is relevant - str_arg_l = (size_t)((char *)xmemscan(str_arg, - NUL, - MIN(precision, - 0x7fffffff)) - - str_arg); - } - if (fmt_spec == 'S') { - if (min_field_width != 0) { - min_field_width += (strlen(str_arg) - - mb_string2cells((char_u *)str_arg)); - } - if (precision) { - char_u *p1; - size_t i = 0; - - for (p1 = (char_u *)str_arg; *p1; - p1 += mb_ptr2len(p1)) { - i += (size_t)utf_ptr2cells(p1); - if (i > precision) { - break; - } - } - str_arg_l = (size_t)(p1 - (char_u *)str_arg); + case 'c': { + const int j = tvs ? (int)tv_nr(tvs, &arg_idx) : va_arg(ap, int); + // standard demands unsigned char + uchar_arg = (unsigned char)j; + str_arg = (char *)&uchar_arg; + break; + } + + case 's': + case 'S': + str_arg = tvs ? tv_str(tvs, &arg_idx, &tofree) + : va_arg(ap, const char *); + if (!str_arg) { + str_arg = "[NULL]"; + str_arg_l = 6; + } else if (!precision_specified) { + // make sure not to address string beyond the specified + // precision + str_arg_l = strlen(str_arg); + } else if (precision == 0) { + // truncate string if necessary as requested by precision + str_arg_l = 0; + } else { + // memchr on HP does not like n > 2^31 + // TODO(elmart): check if this still holds / is relevant + str_arg_l = (size_t)((char *)xmemscan(str_arg, + NUL, + MIN(precision, + 0x7fffffff)) + - str_arg); + } + if (fmt_spec == 'S') { + if (min_field_width != 0) { + min_field_width += (strlen(str_arg) + - mb_string2cells((char_u *)str_arg)); + } + if (precision) { + char_u *p1; + size_t i = 0; + + for (p1 = (char_u *)str_arg; *p1; + p1 += mb_ptr2len(p1)) { + i += (size_t)utf_ptr2cells(p1); + if (i > precision) { + break; } } - break; - - default: - break; + str_arg_l = (size_t)(p1 - (char_u *)str_arg); + } } break; - case 'd': - case 'u': - case 'b': case 'B': - case 'o': - case 'x': case 'X': - case 'p': { - // u, b, B, o, x, X and p conversion specifiers imply - // the value is unsigned; d implies a signed value - - // 0 if numeric argument is zero (or if pointer is NULL for 'p'), - // +1 if greater than zero (or non NULL for 'p'), - // -1 if negative (unsigned argument is never negative) - int arg_sign = 0; - - intmax_t arg = 0; - uintmax_t uarg = 0; - - // only defined for p conversion - const void *ptr_arg = NULL; - - if (fmt_spec == 'p') { - ptr_arg = tvs ? tv_ptr(tvs, &arg_idx) : va_arg(ap, void *); - if (ptr_arg) { - arg_sign = 1; - } - } else if (fmt_spec == 'd') { - // signed - switch (length_modifier) { - case '\0': { - arg = (int)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int)); - break; - } - case 'h': { - // char and short arguments are passed as int16_t - arg = (int16_t)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int)); - break; - } - case 'l': { - arg = (tvs ? (long)tv_nr(tvs, &arg_idx) : va_arg(ap, long)); - break; - } - case '2': { - arg = ( - tvs + default: + break; + } + break; + + case 'd': + case 'u': + case 'b': + case 'B': + case 'o': + case 'x': + case 'X': + case 'p': { + // u, b, B, o, x, X and p conversion specifiers imply + // the value is unsigned; d implies a signed value + + // 0 if numeric argument is zero (or if pointer is NULL for 'p'), + // +1 if greater than zero (or non NULL for 'p'), + // -1 if negative (unsigned argument is never negative) + int arg_sign = 0; + + intmax_t arg = 0; + uintmax_t uarg = 0; + + // only defined for p conversion + const void *ptr_arg = NULL; + + if (fmt_spec == 'p') { + ptr_arg = tvs ? tv_ptr(tvs, &arg_idx) : va_arg(ap, void *); + if (ptr_arg) { + arg_sign = 1; + } + } else if (fmt_spec == 'd') { + // signed + switch (length_modifier) { + case '\0': + arg = (int)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int)); + break; + case 'h': + // char and short arguments are passed as int16_t + arg = (int16_t)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, int)); + break; + case 'l': + arg = (tvs ? (long)tv_nr(tvs, &arg_idx) : va_arg(ap, long)); + break; + case '2': + arg = ( + tvs ? (long long)tv_nr(tvs, &arg_idx) // NOLINT (runtime/int) : va_arg(ap, long long)); // NOLINT (runtime/int) - break; - } - case 'z': { - arg = (tvs + break; + case 'z': + arg = (tvs ? (ptrdiff_t)tv_nr(tvs, &arg_idx) : va_arg(ap, ptrdiff_t)); - break; - } - } - if (arg > 0) { - arg_sign = 1; - } else if (arg < 0) { - arg_sign = -1; - } - } else { - // unsigned - switch (length_modifier) { - case '\0': { - uarg = (unsigned int)(tvs + break; + } + if (arg > 0) { + arg_sign = 1; + } else if (arg < 0) { + arg_sign = -1; + } + } else { + // unsigned + switch (length_modifier) { + case '\0': + uarg = (unsigned int)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, unsigned int)); - break; - } - case 'h': { - uarg = (uint16_t)(tvs + break; + case 'h': + uarg = (uint16_t)(tvs ? tv_nr(tvs, &arg_idx) : va_arg(ap, unsigned int)); - break; - } - case 'l': { - uarg = (tvs + break; + case 'l': + uarg = (tvs ? (unsigned long)tv_nr(tvs, &arg_idx) : va_arg(ap, unsigned long)); - break; - } - case '2': { - uarg = (uintmax_t)(unsigned long long)( // NOLINT (runtime/int) - tvs + break; + case '2': + uarg = (uintmax_t)(unsigned long long)( // NOLINT (runtime/int) + tvs ? ((unsigned long long) // NOLINT (runtime/int) tv_nr(tvs, &arg_idx)) : va_arg(ap, unsigned long long)); // NOLINT (runtime/int) - break; - } - case 'z': { - uarg = (tvs + break; + case 'z': + uarg = (tvs ? (size_t)tv_nr(tvs, &arg_idx) : va_arg(ap, size_t)); - break; - } - } - arg_sign = (uarg != 0); + break; } + arg_sign = (uarg != 0); + } - str_arg = tmp; - str_arg_l = 0; + str_arg = tmp; + str_arg_l = 0; - // For d, i, u, o, x, and X conversions, if precision is specified, - // '0' flag should be ignored. This is so with Solaris 2.6, Digital - // UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. - if (precision_specified) { - zero_padding = 0; - } + // For d, i, u, o, x, and X conversions, if precision is specified, + // '0' flag should be ignored. This is so with Solaris 2.6, Digital + // UNIX 4.0, HPUX 10, Linux, FreeBSD, NetBSD; but not with Perl. + if (precision_specified) { + zero_padding = 0; + } - if (fmt_spec == 'd') { - if (force_sign && arg_sign >= 0) { - tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; - } - // leave negative numbers for snprintf to handle, to - // avoid handling tricky cases like (short int)-32768 - } else if (alternate_form) { - if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X' - || fmt_spec == 'b' || fmt_spec == 'B')) { - tmp[str_arg_l++] = '0'; - tmp[str_arg_l++] = fmt_spec; - } - // alternate form should have no effect for p * conversion, but ... + if (fmt_spec == 'd') { + if (force_sign && arg_sign >= 0) { + tmp[str_arg_l++] = space_for_positive ? ' ' : '+'; } - - zero_padding_insertion_ind = str_arg_l; - if (!precision_specified) { - precision = 1; // default precision is 1 + // leave negative numbers for snprintf to handle, to + // avoid handling tricky cases like (short int)-32768 + } else if (alternate_form) { + if (arg_sign != 0 && (fmt_spec == 'x' || fmt_spec == 'X' + || fmt_spec == 'b' || fmt_spec == 'B')) { + tmp[str_arg_l++] = '0'; + tmp[str_arg_l++] = fmt_spec; } - if (precision == 0 && arg_sign == 0) { - // when zero value is formatted with an explicit precision 0, - // resulting formatted string is empty (d, i, u, b, B, o, x, X, p) - } else { - switch (fmt_spec) { - case 'p': { // pointer - str_arg_l += (size_t)snprintf(tmp + str_arg_l, - sizeof(tmp) - str_arg_l, - "%p", ptr_arg); - break; - } - case 'd': { // signed - str_arg_l += (size_t)snprintf(tmp + str_arg_l, - sizeof(tmp) - str_arg_l, - "%" PRIdMAX, arg); - break; - } - case 'b': case 'B': { // binary - size_t bits = 0; - for (bits = sizeof(uintmax_t) * 8; bits > 0; bits--) { - if ((uarg >> (bits - 1)) & 0x1) { - break; - } - } + // alternate form should have no effect for p * conversion, but ... + } - while (bits > 0) { - tmp[str_arg_l++] = ((uarg >> --bits) & 0x1) ? '1' : '0'; - } - break; - } - default: { // unsigned - // construct a simple format string for snprintf - char f[] = "%" PRIuMAX; - f[sizeof("%" PRIuMAX) - 1 - 1] = fmt_spec; - assert(PRIuMAX[sizeof(PRIuMAX) - 1 - 1] == 'u'); - str_arg_l += (size_t)snprintf(tmp + str_arg_l, - sizeof(tmp) - str_arg_l, - f, uarg); + zero_padding_insertion_ind = str_arg_l; + if (!precision_specified) { + precision = 1; // default precision is 1 + } + if (precision == 0 && arg_sign == 0) { + // when zero value is formatted with an explicit precision 0, + // resulting formatted string is empty (d, i, u, b, B, o, x, X, p) + } else { + switch (fmt_spec) { + case 'p': // pointer + str_arg_l += (size_t)snprintf(tmp + str_arg_l, + sizeof(tmp) - str_arg_l, + "%p", ptr_arg); + break; + case 'd': // signed + str_arg_l += (size_t)snprintf(tmp + str_arg_l, + sizeof(tmp) - str_arg_l, + "%" PRIdMAX, arg); + break; + case 'b': + case 'B': { // binary + size_t bits = 0; + for (bits = sizeof(uintmax_t) * 8; bits > 0; bits--) { + if ((uarg >> (bits - 1)) & 0x1) { break; } } - assert(str_arg_l < sizeof(tmp)); - // include the optional minus sign and possible "0x" in the region - // before the zero padding insertion point - if (zero_padding_insertion_ind < str_arg_l - && tmp[zero_padding_insertion_ind] == '-') { - zero_padding_insertion_ind++; - } - if (zero_padding_insertion_ind + 1 < str_arg_l - && tmp[zero_padding_insertion_ind] == '0' - && (tmp[zero_padding_insertion_ind + 1] == 'x' - || tmp[zero_padding_insertion_ind + 1] == 'X' - || tmp[zero_padding_insertion_ind + 1] == 'b' - || tmp[zero_padding_insertion_ind + 1] == 'B')) { - zero_padding_insertion_ind += 2; + while (bits > 0) { + tmp[str_arg_l++] = ((uarg >> --bits) & 0x1) ? '1' : '0'; } + break; + } + default: { // unsigned + // construct a simple format string for snprintf + char f[] = "%" PRIuMAX; + f[sizeof("%" PRIuMAX) - 1 - 1] = fmt_spec; + assert(PRIuMAX[sizeof(PRIuMAX) - 1 - 1] == 'u'); + str_arg_l += (size_t)snprintf(tmp + str_arg_l, + sizeof(tmp) - str_arg_l, + f, uarg); + break; + } } + assert(str_arg_l < sizeof(tmp)); - { - size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; - - if (alternate_form && fmt_spec == 'o' - // unless zero is already the first character - && !(zero_padding_insertion_ind < str_arg_l - && tmp[zero_padding_insertion_ind] == '0')) { - // assure leading zero for alternate-form octal numbers - if (!precision_specified - || precision < num_of_digits + 1) { - // precision is increased to force the first character to be - // zero, except if a zero value is formatted with an explicit - // precision of zero - precision = num_of_digits + 1; - } - } - // zero padding to specified precision? - if (num_of_digits < precision) { - number_of_zeros_to_pad = precision - num_of_digits; - } + // include the optional minus sign and possible "0x" in the region + // before the zero padding insertion point + if (zero_padding_insertion_ind < str_arg_l + && tmp[zero_padding_insertion_ind] == '-') { + zero_padding_insertion_ind++; } - // zero padding to specified minimal field width? - if (!justify_left && zero_padding) { - const int n = (int)(min_field_width - (str_arg_l - + number_of_zeros_to_pad)); - if (n > 0) { - number_of_zeros_to_pad += (size_t)n; - } + if (zero_padding_insertion_ind + 1 < str_arg_l + && tmp[zero_padding_insertion_ind] == '0' + && (tmp[zero_padding_insertion_ind + 1] == 'x' + || tmp[zero_padding_insertion_ind + 1] == 'X' + || tmp[zero_padding_insertion_ind + 1] == 'b' + || tmp[zero_padding_insertion_ind + 1] == 'B')) { + zero_padding_insertion_ind += 2; } - break; } - case 'f': - case 'F': - case 'e': - case 'E': - case 'g': - case 'G': - { - // floating point - char format[40]; - int remove_trailing_zeroes = false; - - double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double); - double abs_f = f < 0 ? -f : f; - - if (fmt_spec == 'g' || fmt_spec == 'G') { - // can't use %g directly, cause it prints "1.0" as "1" - if ((abs_f >= 0.001 && abs_f < 10000000.0) || abs_f == 0.0) { - fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f'; - } else { - fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; - } - remove_trailing_zeroes = true; + { + size_t num_of_digits = str_arg_l - zero_padding_insertion_ind; + + if (alternate_form && fmt_spec == 'o' + // unless zero is already the first character + && !(zero_padding_insertion_ind < str_arg_l + && tmp[zero_padding_insertion_ind] == '0')) { + // assure leading zero for alternate-form octal numbers + if (!precision_specified + || precision < num_of_digits + 1) { + // precision is increased to force the first character to be + // zero, except if a zero value is formatted with an explicit + // precision of zero + precision = num_of_digits + 1; } + } + // zero padding to specified precision? + if (num_of_digits < precision) { + number_of_zeros_to_pad = precision - num_of_digits; + } + } + // zero padding to specified minimal field width? + if (!justify_left && zero_padding) { + const int n = (int)(min_field_width - (str_arg_l + + number_of_zeros_to_pad)); + if (n > 0) { + number_of_zeros_to_pad += (size_t)n; + } + } + break; + } - if (xisinf(f) - || (strchr("fF", fmt_spec) != NULL && abs_f > 1.0e307)) { - xstrlcpy(tmp, infinity_str(f > 0.0, fmt_spec, - force_sign, space_for_positive), - sizeof(tmp)); - str_arg_l = strlen(tmp); - zero_padding = 0; - } else if (xisnan(f)) { - // Not a number: nan or NAN - memmove(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" : "nan", 4); - str_arg_l = 3; - zero_padding = 0; - } else { - // Regular float number - format[0] = '%'; - size_t l = 1; - if (force_sign) { - format[l++] = space_for_positive ? ' ' : '+'; - } - if (precision_specified) { - size_t max_prec = TMP_LEN - 10; + case 'f': + case 'F': + case 'e': + case 'E': + case 'g': + case 'G': { + // floating point + char format[40]; + int remove_trailing_zeroes = false; + + double f = tvs ? tv_float(tvs, &arg_idx) : va_arg(ap, double); + double abs_f = f < 0 ? -f : f; + + if (fmt_spec == 'g' || fmt_spec == 'G') { + // can't use %g directly, cause it prints "1.0" as "1" + if ((abs_f >= 0.001 && abs_f < 10000000.0) || abs_f == 0.0) { + fmt_spec = ASCII_ISUPPER(fmt_spec) ? 'F' : 'f'; + } else { + fmt_spec = fmt_spec == 'g' ? 'e' : 'E'; + } + remove_trailing_zeroes = true; + } - // make sure we don't get more digits than we have room for - if ((fmt_spec == 'f' || fmt_spec == 'F') && abs_f > 1.0) { - max_prec -= (size_t)log10(abs_f); - } - if (precision > max_prec) { - precision = max_prec; - } - l += (size_t)snprintf(format + l, sizeof(format) - l, ".%d", - (int)precision); - } + if (xisinf(f) + || (strchr("fF", fmt_spec) != NULL && abs_f > 1.0e307)) { + xstrlcpy(tmp, infinity_str(f > 0.0, fmt_spec, + force_sign, space_for_positive), + sizeof(tmp)); + str_arg_l = strlen(tmp); + zero_padding = 0; + } else if (xisnan(f)) { + // Not a number: nan or NAN + memmove(tmp, ASCII_ISUPPER(fmt_spec) ? "NAN" : "nan", 4); + str_arg_l = 3; + zero_padding = 0; + } else { + // Regular float number + format[0] = '%'; + size_t l = 1; + if (force_sign) { + format[l++] = space_for_positive ? ' ' : '+'; + } + if (precision_specified) { + size_t max_prec = TMP_LEN - 10; - // Cast to char to avoid a conversion warning on Ubuntu 12.04. - assert(l + 1 < sizeof(format)); - format[l] = (char)(fmt_spec == 'F' ? 'f' : fmt_spec); - format[l + 1] = NUL; + // make sure we don't get more digits than we have room for + if ((fmt_spec == 'f' || fmt_spec == 'F') && abs_f > 1.0) { + max_prec -= (size_t)log10(abs_f); + } + if (precision > max_prec) { + precision = max_prec; + } + l += (size_t)snprintf(format + l, sizeof(format) - l, ".%d", + (int)precision); + } - str_arg_l = (size_t)snprintf(tmp, sizeof(tmp), format, f); - assert(str_arg_l < sizeof(tmp)); + // Cast to char to avoid a conversion warning on Ubuntu 12.04. + assert(l + 1 < sizeof(format)); + format[l] = (char)(fmt_spec == 'F' ? 'f' : fmt_spec); + format[l + 1] = NUL; - if (remove_trailing_zeroes) { - int i; - char *tp; + str_arg_l = (size_t)snprintf(tmp, sizeof(tmp), format, f); + assert(str_arg_l < sizeof(tmp)); - // using %g or %G: remove superfluous zeroes - if (fmt_spec == 'f' || fmt_spec == 'F') { - tp = tmp + str_arg_l - 1; - } else { - tp = (char *)vim_strchr((char_u *)tmp, - fmt_spec == 'e' ? 'e' : 'E'); - if (tp) { - // remove superfluous '+' and leading zeroes from exponent - if (tp[1] == '+') { - // change "1.0e+07" to "1.0e07" - STRMOVE(tp + 1, tp + 2); - str_arg_l--; - } - i = (tp[1] == '-') ? 2 : 1; - while (tp[i] == '0') { - // change "1.0e07" to "1.0e7" - STRMOVE(tp + i, tp + i + 1); - str_arg_l--; - } - tp--; - } - } + if (remove_trailing_zeroes) { + int i; + char *tp; - if (tp != NULL && !precision_specified) { - // remove trailing zeroes, but keep the one just after a dot - while (tp > tmp + 2 && *tp == '0' && tp[-1] != '.') { - STRMOVE(tp, tp + 1); - tp--; - str_arg_l--; - } + // using %g or %G: remove superfluous zeroes + if (fmt_spec == 'f' || fmt_spec == 'F') { + tp = tmp + str_arg_l - 1; + } else { + tp = (char *)vim_strchr((char_u *)tmp, + fmt_spec == 'e' ? 'e' : 'E'); + if (tp) { + // remove superfluous '+' and leading zeroes from exponent + if (tp[1] == '+') { + // change "1.0e+07" to "1.0e07" + STRMOVE(tp + 1, tp + 2); + str_arg_l--; } - } else { - // Be consistent: some printf("%e") use 1.0e+12 and some - // 1.0e+012; remove one zero in the last case. - char *tp = (char *)vim_strchr((char_u *)tmp, - fmt_spec == 'e' ? 'e' : 'E'); - if (tp && (tp[1] == '+' || tp[1] == '-') && tp[2] == '0' - && ascii_isdigit(tp[3]) && ascii_isdigit(tp[4])) { - STRMOVE(tp + 2, tp + 3); + i = (tp[1] == '-') ? 2 : 1; + while (tp[i] == '0') { + // change "1.0e07" to "1.0e7" + STRMOVE(tp + i, tp + i + 1); str_arg_l--; } + tp--; } } - if (zero_padding && min_field_width > str_arg_l - && (tmp[0] == '-' || force_sign)) { - // Padding 0's should be inserted after the sign. - number_of_zeros_to_pad = min_field_width - str_arg_l; - zero_padding_insertion_ind = 1; + + if (tp != NULL && !precision_specified) { + // remove trailing zeroes, but keep the one just after a dot + while (tp > tmp + 2 && *tp == '0' && tp[-1] != '.') { + STRMOVE(tp, tp + 1); + tp--; + str_arg_l--; + } + } + } else { + // Be consistent: some printf("%e") use 1.0e+12 and some + // 1.0e+012; remove one zero in the last case. + char *tp = (char *)vim_strchr((char_u *)tmp, + fmt_spec == 'e' ? 'e' : 'E'); + if (tp && (tp[1] == '+' || tp[1] == '-') && tp[2] == '0' + && ascii_isdigit(tp[3]) && ascii_isdigit(tp[4])) { + STRMOVE(tp + 2, tp + 3); + str_arg_l--; } - str_arg = tmp; - break; } + } + if (zero_padding && min_field_width > str_arg_l + && (tmp[0] == '-' || force_sign)) { + // Padding 0's should be inserted after the sign. + number_of_zeros_to_pad = min_field_width - str_arg_l; + zero_padding_insertion_ind = 1; + } + str_arg = tmp; + break; + } - default: - // unrecognized conversion specifier, keep format string as-is - zero_padding = 0; // turn zero padding off for non-numeric conversion - justify_left = 1; - min_field_width = 0; // reset flags - - // discard the unrecognized conversion, just keep - // the unrecognized conversion character - str_arg = p; - str_arg_l = 0; - if (*p) { - str_arg_l++; // include invalid conversion specifier - } - // unchanged if not at end-of-string - break; + default: + // unrecognized conversion specifier, keep format string as-is + zero_padding = 0; // turn zero padding off for non-numeric conversion + justify_left = 1; + min_field_width = 0; // reset flags + + // discard the unrecognized conversion, just keep + // the unrecognized conversion character + str_arg = p; + str_arg_l = 0; + if (*p) { + str_arg_l++; // include invalid conversion specifier + } + // unchanged if not at end-of-string + break; } if (*p) { diff --git a/src/nvim/syntax.c b/src/nvim/syntax.c index d2c94d9fe8..49f54dcfe1 100644 --- a/src/nvim/syntax.c +++ b/src/nvim/syntax.c @@ -6217,6 +6217,26 @@ static const char *highlight_init_both[] = { "default link Delimiter Special", "default link SpecialComment Special", "default link Debug Special", + "default DiagnosticError ctermfg=1 guifg=Red", + "default DiagnosticWarn ctermfg=3 guifg=Orange", + "default DiagnosticInfo ctermfg=4 guifg=LightBlue", + "default DiagnosticHint ctermfg=7 guifg=LightGrey", + "default DiagnosticUnderlineError cterm=underline gui=underline guisp=Red", + "default DiagnosticUnderlineWarn cterm=underline gui=underline guisp=Orange", + "default DiagnosticUnderlineInfo cterm=underline gui=underline guisp=LightBlue", + "default DiagnosticUnderlineHint cterm=underline gui=underline guisp=LightGrey", + "default link DiagnosticVirtualTextError DiagnosticError", + "default link DiagnosticVirtualTextWarn DiagnosticWarn", + "default link DiagnosticVirtualTextInfo DiagnosticInfo", + "default link DiagnosticVirtualTextHint DiagnosticHint", + "default link DiagnosticFloatingError DiagnosticError", + "default link DiagnosticFloatingWarn DiagnosticWarn", + "default link DiagnosticFloatingInfo DiagnosticInfo", + "default link DiagnosticFloatingHint DiagnosticHint", + "default link DiagnosticSignError DiagnosticError", + "default link DiagnosticSignWarn DiagnosticWarn", + "default link DiagnosticSignInfo DiagnosticInfo", + "default link DiagnosticSignHint DiagnosticHint", NULL }; diff --git a/src/nvim/tag.c b/src/nvim/tag.c index c63cdad098..768cca284b 100644 --- a/src/nvim/tag.c +++ b/src/nvim/tag.c @@ -10,9 +10,7 @@ #include <stdbool.h> #include <string.h> -#include "nvim/vim.h" #include "nvim/ascii.h" -#include "nvim/tag.h" #include "nvim/buffer.h" #include "nvim/charset.h" #include "nvim/cursor.h" @@ -22,18 +20,21 @@ #include "nvim/ex_cmds2.h" #include "nvim/ex_docmd.h" #include "nvim/ex_getln.h" +#include "nvim/file_search.h" #include "nvim/fileio.h" #include "nvim/fold.h" +#include "nvim/garray.h" #include "nvim/if_cscope.h" #include "nvim/mark.h" #include "nvim/mbyte.h" +#include "nvim/memory.h" #include "nvim/message.h" #include "nvim/misc1.h" -#include "nvim/file_search.h" -#include "nvim/garray.h" -#include "nvim/memory.h" #include "nvim/move.h" #include "nvim/option.h" +#include "nvim/os/input.h" +#include "nvim/os/os.h" +#include "nvim/os/time.h" #include "nvim/os_unix.h" #include "nvim/path.h" #include "nvim/quickfix.h" @@ -41,30 +42,29 @@ #include "nvim/screen.h" #include "nvim/search.h" #include "nvim/strings.h" +#include "nvim/tag.h" #include "nvim/ui.h" +#include "nvim/vim.h" #include "nvim/window.h" -#include "nvim/os/os.h" -#include "nvim/os/time.h" -#include "nvim/os/input.h" /* * Structure to hold pointers to various items in a tag line. */ typedef struct tag_pointers { // filled in by parse_tag_line(): - char_u *tagname; // start of tag name (skip "file:") - char_u *tagname_end; // char after tag name - char_u *fname; // first char of file name - char_u *fname_end; // char after file name - char_u *command; // first char of command + char_u *tagname; // start of tag name (skip "file:") + char_u *tagname_end; // char after tag name + char_u *fname; // first char of file name + char_u *fname_end; // char after file name + char_u *command; // first char of command // filled in by parse_match(): - char_u *command_end; // first char after command - char_u *tag_fname; // file name of the tags file. This is used + char_u *command_end; // first char after command + char_u *tag_fname; // file name of the tags file. This is used // when 'tr' is set. - char_u *tagkind; // "kind:" value - char_u *tagkind_end; // end of tagkind - char_u *user_data; // user_data string - char_u *user_data_end; // end of user_data + char_u *tagkind; // "kind:" value + char_u *tagkind_end; // end of tagkind + char_u *user_data; // user_data string + char_u *user_data_end; // end of user_data linenr_T tagline; // "line:" value } tagptrs_T; @@ -72,11 +72,11 @@ typedef struct tag_pointers { * Structure to hold info about the tag pattern being used. */ typedef struct { - char_u *pat; /* the pattern */ - int len; /* length of pat[] */ - char_u *head; /* start of pattern head */ - int headlen; /* length of head[] */ - regmatch_T regmatch; /* regexp program, may be NULL */ + char_u *pat; // the pattern + int len; // length of pat[] + char_u *head; // start of pattern head + int headlen; // length of head[] + regmatch_T regmatch; // regexp program, may be NULL } pat_T; // The matching tags are first stored in one of the hash tables. In @@ -93,11 +93,11 @@ typedef struct { #define MT_MASK 7 // mask for printing priority #define MT_COUNT 16 -static char *mt_names[MT_COUNT/2] = -{"FSC", "F C", "F ", "FS ", " SC", " C", " ", " S "}; +static char *mt_names[MT_COUNT/2] = +{ "FSC", "F C", "F ", "FS ", " SC", " C", " ", " S " }; -#define NOTAGFILE 99 /* return value for jumpto_tag */ -static char_u *nofile_fname = NULL; /* fname for NOTAGFILE error */ +#define NOTAGFILE 99 // return value for jumpto_tag +static char_u *nofile_fname = NULL; // fname for NOTAGFILE error #ifdef INCLUDE_GENERATED_DECLARATIONS @@ -111,7 +111,7 @@ static char_u *recurmsg static char_u *tfu_inv_ret_msg = (char_u *)N_("E987: invalid return value from tagfunc"); -static char_u *tagmatchname = NULL; /* name of last used tag */ +static char_u *tagmatchname = NULL; // name of last used tag /* * Tag for preview window is remembered separately, to avoid messing up the @@ -124,36 +124,31 @@ static int tfu_in_use = false; // disallow recursive call of tagfunc // Used instead of NUL to separate tag fields in the growarrays. #define TAG_SEP 0x02 -/* - * Jump to tag; handling of tag commands and tag stack - * - * *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack - * - * type == DT_TAG: ":tag [tag]", jump to newer position or same tag again - * type == DT_HELP: like DT_TAG, but don't use regexp. - * type == DT_POP: ":pop" or CTRL-T, jump to old position - * type == DT_NEXT: jump to next match of same tag - * type == DT_PREV: jump to previous match of same tag - * type == DT_FIRST: jump to first match of same tag - * type == DT_LAST: jump to last match of same tag - * type == DT_SELECT: ":tselect [tag]", select tag from a list of all matches - * type == DT_JUMP: ":tjump [tag]", jump to tag or select tag from a list - * type == DT_CSCOPE: use cscope to find the tag - * type == DT_LTAG: use location list for displaying tag matches - * type == DT_FREE: free cached matches - * - * for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise - */ -int -do_tag( - char_u *tag, // tag (pattern) to jump to - int type, - int count, - int forceit, // :ta with ! - int verbose // print "tag not found" message -) +/// Jump to tag; handling of tag commands and tag stack +/// +/// *tag != NUL: ":tag {tag}", jump to new tag, add to tag stack +/// +/// type == DT_TAG: ":tag [tag]", jump to newer position or same tag again +/// type == DT_HELP: like DT_TAG, but don't use regexp. +/// type == DT_POP: ":pop" or CTRL-T, jump to old position +/// type == DT_NEXT: jump to next match of same tag +/// type == DT_PREV: jump to previous match of same tag +/// type == DT_FIRST: jump to first match of same tag +/// type == DT_LAST: jump to last match of same tag +/// type == DT_SELECT: ":tselect [tag]", select tag from a list of all matches +/// type == DT_JUMP: ":tjump [tag]", jump to tag or select tag from a list +/// type == DT_CSCOPE: use cscope to find the tag +/// type == DT_LTAG: use location list for displaying tag matches +/// type == DT_FREE: free cached matches +/// +/// for cscope, returns TRUE if we jumped to tag or aborted, FALSE otherwise +/// +/// @param tag tag (pattern) to jump to +/// @param forceit :ta with ! +/// @param verbose print "tag not found" message +int do_tag(char_u *tag, int type, int count, int forceit, int verbose) { - taggy_T *tagstack = curwin->w_tagstack; + taggy_T *tagstack = curwin->w_tagstack; int tagstackidx = curwin->w_tagstackidx; int tagstacklen = curwin->w_tagstacklen; int cur_match = 0; @@ -170,16 +165,16 @@ do_tag( fmark_T saved_fmark; int jumped_to_tag = false; int new_num_matches; - char_u **new_matches; + char_u **new_matches; int use_tagstack; int skip_msg = false; char_u *buf_ffname = curbuf->b_ffname; // name for priority computation int use_tfu = 1; - /* remember the matches for the last used tag */ + // remember the matches for the last used tag static int num_matches = 0; - static int max_num_matches = 0; /* limit used for match search */ - static char_u **matches = NULL; + static int max_num_matches = 0; // limit used for match search + static char_u **matches = NULL; static int flags; if (tfu_in_use) { @@ -189,7 +184,7 @@ do_tag( #ifdef EXITFREE if (type == DT_FREE) { - /* remove the list of matches */ + // remove the list of matches FreeWild(num_matches, matches); cs_free_tags(); num_matches = 0; @@ -207,7 +202,7 @@ do_tag( free_string_option(nofile_fname); nofile_fname = NULL; - clearpos(&saved_fmark.mark); /* shutup gcc 4.0 */ + clearpos(&saved_fmark.mark); // shutup gcc 4.0 saved_fmark.fnum = 0; // Don't add a tag to the tagstack if 'tagstack' has been reset. @@ -226,7 +221,7 @@ do_tag( use_tagstack = true; } - /* new pattern, add to the tag stack */ + // new pattern, add to the tag stack if (*tag != NUL && (type == DT_TAG || type == DT_SELECT || type == DT_JUMP || type == DT_LTAG @@ -252,7 +247,7 @@ do_tag( tagstack_clear_entry(&tagstack[--tagstacklen]); } - /* if the tagstack is full: remove oldest entry */ + // if the tagstack is full: remove oldest entry if (++tagstacklen > TAGSTACKSIZE) { tagstacklen = TAGSTACKSIZE; tagstack_clear_entry(&tagstack[0]); @@ -293,7 +288,7 @@ do_tag( * way to the bottom now. */ tagstackidx = 0; - } else if (tagstackidx >= tagstacklen) { // count == 0? + } else if (tagstackidx >= tagstacklen) { // count == 0? EMSG(_(topmsg)); goto end_do_tag; } @@ -321,8 +316,9 @@ do_tag( curwin->w_cursor.col = saved_fmark.mark.col; curwin->w_set_curswant = true; check_cursor(); - if ((fdo_flags & FDO_TAG) && old_KeyTyped) + if ((fdo_flags & FDO_TAG) && old_KeyTyped) { foldOpenCursor(); + } // remove the old list of matches FreeWild(num_matches, matches); @@ -333,8 +329,7 @@ do_tag( } if (type == DT_TAG - || type == DT_LTAG - ) { + || type == DT_LTAG) { if (g_do_tagpreview != 0) { cur_match = ptag_entry.cur_match; cur_fnum = ptag_entry.cur_fnum; @@ -350,7 +345,7 @@ do_tag( tagstackidx = tagstacklen - 1; EMSG(_(topmsg)); save_pos = false; - } else if (tagstackidx < 0) { // must have been count == 0 + } else if (tagstackidx < 0) { // must have been count == 0 EMSG(_(bottommsg)); tagstackidx = 0; goto end_do_tag; @@ -367,23 +362,28 @@ do_tag( cur_match = ptag_entry.cur_match; cur_fnum = ptag_entry.cur_fnum; } else { - if (--tagstackidx < 0) + if (--tagstackidx < 0) { tagstackidx = 0; + } cur_match = tagstack[tagstackidx].cur_match; cur_fnum = tagstack[tagstackidx].cur_fnum; } switch (type) { - case DT_FIRST: cur_match = count - 1; break; + case DT_FIRST: + cur_match = count - 1; break; case DT_SELECT: case DT_JUMP: case DT_CSCOPE: - case DT_LAST: cur_match = MAXCOL - 1; break; - case DT_NEXT: cur_match += count; break; - case DT_PREV: cur_match -= count; break; + case DT_LAST: + cur_match = MAXCOL - 1; break; + case DT_NEXT: + cur_match += count; break; + case DT_PREV: + cur_match -= count; break; } - if (cur_match >= MAXCOL) + if (cur_match >= MAXCOL) { cur_match = MAXCOL - 1; - else if (cur_match < 0) { + } else if (cur_match < 0) { EMSG(_("E425: Cannot go before first matching tag")); skip_msg = true; cur_match = 0; @@ -424,8 +424,9 @@ do_tag( if (cur_fnum != curbuf->b_fnum) { buf_T *buf = buflist_findnr(cur_fnum); - if (buf != NULL) + if (buf != NULL) { buf_ffname = buf->b_ffname; + } } /* @@ -433,7 +434,7 @@ do_tag( */ for (;; ) { int other_name; - char_u *name; + char_u *name; // When desired match not found yet, try to find it (and others). if (use_tagstack) { @@ -466,8 +467,9 @@ do_tag( if (!no_regexp && *name == '/') { flags = TAG_REGEXP; ++name; - } else + } else { flags = TAG_NOIC; + } if (type == DT_CSCOPE) { flags = TAG_CSCOPE; @@ -490,9 +492,9 @@ do_tag( * to the start. Avoids that the order changes when using * ":tnext" and jumping to another file. */ if (!new_tag && !other_name) { - int j, k; - int idx = 0; - tagptrs_T tagp, tagp2; + int j, k; + int idx = 0; + tagptrs_T tagp, tagp2; // Find the position of each old match in the new list. Need // to use parse_match() to find the tag line. @@ -517,8 +519,9 @@ do_tag( } if (num_matches <= 0) { - if (verbose) + if (verbose) { EMSG2(_("E426: tag not found: %s"), name); + } g_do_tagpreview = 0; } else { bool ask_for_selection = false; @@ -533,7 +536,7 @@ do_tag( } else if (type == DT_SELECT || (type == DT_JUMP && num_matches > 1)) { print_tag_list(new_tag, use_tagstack, num_matches, matches); ask_for_selection = true; - } else if (type == DT_LTAG) { + } else if (type == DT_LTAG) { if (add_llist_tags(tag, num_matches, matches) == FAIL) { goto end_do_tag; } @@ -563,16 +566,17 @@ do_tag( * There will be an EMSG("file doesn't exist") below then. */ if ((type == DT_NEXT || type == DT_FIRST) && nofile_fname == NULL) { - if (num_matches == 1) + if (num_matches == 1) { EMSG(_("E427: There is only one matching tag")); - else + } else { EMSG(_("E428: Cannot go beyond last matching tag")); + } skip_msg = true; } cur_match = num_matches - 1; } if (use_tagstack) { - tagptrs_T tagp2; + tagptrs_T tagp2; tagstack[tagstackidx].cur_match = cur_match; tagstack[tagstackidx].cur_fnum = cur_fnum; @@ -581,12 +585,12 @@ do_tag( if (use_tfu && parse_match(matches[cur_match], &tagp2) == OK && tagp2.user_data) { XFREE_CLEAR(tagstack[tagstackidx].user_data); - tagstack[tagstackidx].user_data = vim_strnsave( - tagp2.user_data, tagp2.user_data_end - tagp2.user_data); + tagstack[tagstackidx].user_data = vim_strnsave(tagp2.user_data, + tagp2.user_data_end - tagp2.user_data); } tagstackidx++; - } else if (g_do_tagpreview != 0) { + } else if (g_do_tagpreview != 0) { ptag_entry.cur_match = cur_match; ptag_entry.cur_fnum = cur_fnum; } @@ -595,8 +599,9 @@ do_tag( * Only when going to try the next match, report that the previous * file didn't exist. Otherwise an EMSG() is given below. */ - if (nofile_fname != NULL && error_cur_match != cur_match) + if (nofile_fname != NULL && error_cur_match != cur_match) { smsg(_("File \"%s\" does not exist"), nofile_fname); + } ic = (matches[cur_match][0] & MT_IC_OFF); @@ -631,7 +636,7 @@ do_tag( // Let the SwapExists event know what tag we are jumping to. vim_snprintf((char *)IObuff, IOSIZE, ":ta %s\r", name); - set_vim_var_string(VV_SWAPCOMMAND, (char *) IObuff, -1); + set_vim_var_string(VV_SWAPCOMMAND, (char *)IObuff, -1); /* * Jump to the desired match. @@ -648,11 +653,12 @@ do_tag( && (max_num_matches != MAXCOL || cur_match < num_matches - 1))) { error_cur_match = cur_match; - if (use_tagstack) + if (use_tagstack) { --tagstackidx; - if (type == DT_PREV) + } + if (type == DT_PREV) { --cur_match; - else { + } else { type = DT_NEXT; ++cur_match; } @@ -662,8 +668,9 @@ do_tag( } else { /* We may have jumped to another window, check that * tagstackidx is still valid. */ - if (use_tagstack && tagstackidx > curwin->w_tagstacklen) + if (use_tagstack && tagstackidx > curwin->w_tagstacklen) { tagstackidx = curwin->w_tagstackidx; + } jumped_to_tag = true; } } @@ -684,331 +691,322 @@ end_do_tag: // // List all the matching tags. // -static void -print_tag_list( - int new_tag, - int use_tagstack, - int num_matches, - char_u **matches) +static void print_tag_list(int new_tag, int use_tagstack, int num_matches, char_u **matches) { - taggy_T *tagstack = curwin->w_tagstack; - int tagstackidx = curwin->w_tagstackidx; - int i; - char_u *p; - char_u *command_end; - tagptrs_T tagp; - int taglen; - int attr; - - // Assume that the first match indicates how long the tags can - // be, and align the file names to that. - parse_match(matches[0], &tagp); - taglen = (int)(tagp.tagname_end - tagp.tagname + 2); - if (taglen < 18) { - taglen = 18; - } - if (taglen > Columns - 25) { - taglen = MAXCOL; - } - if (msg_col == 0) { - msg_didout = false; // overwrite previous message - } - msg_start(); - msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T)); - msg_clr_eos(); + taggy_T *tagstack = curwin->w_tagstack; + int tagstackidx = curwin->w_tagstackidx; + int i; + char_u *p; + char_u *command_end; + tagptrs_T tagp; + int taglen; + int attr; + + // Assume that the first match indicates how long the tags can + // be, and align the file names to that. + parse_match(matches[0], &tagp); + taglen = (int)(tagp.tagname_end - tagp.tagname + 2); + if (taglen < 18) { + taglen = 18; + } + if (taglen > Columns - 25) { + taglen = MAXCOL; + } + if (msg_col == 0) { + msg_didout = false; // overwrite previous message + } + msg_start(); + msg_puts_attr(_(" # pri kind tag"), HL_ATTR(HLF_T)); + msg_clr_eos(); + taglen_advance(taglen); + msg_puts_attr(_("file\n"), HL_ATTR(HLF_T)); + + for (i = 0; i < num_matches && !got_int; i++) { + parse_match(matches[i], &tagp); + if (!new_tag && ( + (g_do_tagpreview != 0 + && i == ptag_entry.cur_match) + || (use_tagstack + && i == tagstack[tagstackidx].cur_match))) { + *IObuff = '>'; + } else { + *IObuff = ' '; + } + vim_snprintf((char *)IObuff + 1, IOSIZE - 1, + "%2d %s ", i + 1, + mt_names[matches[i][0] & MT_MASK]); + msg_puts((char *)IObuff); + if (tagp.tagkind != NULL) { + msg_outtrans_len(tagp.tagkind, + (int)(tagp.tagkind_end - tagp.tagkind)); + } + msg_advance(13); + msg_outtrans_len_attr(tagp.tagname, + (int)(tagp.tagname_end - tagp.tagname), + HL_ATTR(HLF_T)); + msg_putchar(' '); taglen_advance(taglen); - msg_puts_attr(_("file\n"), HL_ATTR(HLF_T)); - - for (i = 0; i < num_matches && !got_int; i++) { - parse_match(matches[i], &tagp); - if (!new_tag && ( - (g_do_tagpreview != 0 - && i == ptag_entry.cur_match) - || (use_tagstack - && i == tagstack[tagstackidx].cur_match))) { - *IObuff = '>'; - } else { - *IObuff = ' '; + + // Find out the actual file name. If it is long, truncate + // it and put "..." in the middle + p = tag_full_fname(&tagp); + if (p != NULL) { + msg_outtrans_attr(p, HL_ATTR(HLF_D)); + XFREE_CLEAR(p); + } + if (msg_col > 0) { + msg_putchar('\n'); + } + if (got_int) { + break; + } + msg_advance(15); + + // print any extra fields + command_end = tagp.command_end; + if (command_end != NULL) { + p = command_end + 3; + while (*p && *p != '\r' && *p != '\n') { + while (*p == TAB) { + p++; } - vim_snprintf((char *)IObuff + 1, IOSIZE - 1, - "%2d %s ", i + 1, - mt_names[matches[i][0] & MT_MASK]); - msg_puts((char *)IObuff); - if (tagp.tagkind != NULL) { - msg_outtrans_len(tagp.tagkind, - (int)(tagp.tagkind_end - tagp.tagkind)); + + // skip "file:" without a value (static tag) + if (STRNCMP(p, "file:", 5) == 0 && ascii_isspace(p[5])) { + p += 5; + continue; } - msg_advance(13); - msg_outtrans_len_attr(tagp.tagname, - (int)(tagp.tagname_end - tagp.tagname), - HL_ATTR(HLF_T)); - msg_putchar(' '); - taglen_advance(taglen); - - // Find out the actual file name. If it is long, truncate - // it and put "..." in the middle - p = tag_full_fname(&tagp); - if (p != NULL) { - msg_outtrans_attr(p, HL_ATTR(HLF_D)); - XFREE_CLEAR(p); + // skip "kind:<kind>" and "<kind>" + if (p == tagp.tagkind + || (p + 5 == tagp.tagkind + && STRNCMP(p, "kind:", 5) == 0)) { + p = tagp.tagkind_end; + continue; } - if (msg_col > 0) { + // print all other extra fields + attr = HL_ATTR(HLF_CM); + while (*p && *p != '\r' && *p != '\n') { + if (msg_col + ptr2cells(p) >= Columns) { msg_putchar('\n'); + if (got_int) { + break; + } + msg_advance(15); + } + p = msg_outtrans_one(p, attr); + if (*p == TAB) { + msg_puts_attr(" ", attr); + break; + } + if (*p == ':') { + attr = 0; + } } + } + if (msg_col > 15) { + msg_putchar('\n'); if (got_int) { - break; + break; } msg_advance(15); + } + } else { + for (p = tagp.command; + *p && *p != '\r' && *p != '\n'; + p++) { + } + command_end = p; + } - // print any extra fields - command_end = tagp.command_end; - if (command_end != NULL) { - p = command_end + 3; - while (*p && *p != '\r' && *p != '\n') { - while (*p == TAB) { - p++; - } - - // skip "file:" without a value (static tag) - if (STRNCMP(p, "file:", 5) == 0 && ascii_isspace(p[5])) { - p += 5; - continue; - } - // skip "kind:<kind>" and "<kind>" - if (p == tagp.tagkind - || (p + 5 == tagp.tagkind - && STRNCMP(p, "kind:", 5) == 0)) { - p = tagp.tagkind_end; - continue; - } - // print all other extra fields - attr = HL_ATTR(HLF_CM); - while (*p && *p != '\r' && *p != '\n') { - if (msg_col + ptr2cells(p) >= Columns) { - msg_putchar('\n'); - if (got_int) { - break; - } - msg_advance(15); - } - p = msg_outtrans_one(p, attr); - if (*p == TAB) { - msg_puts_attr(" ", attr); - break; - } - if (*p == ':') { - attr = 0; - } - } - } - if (msg_col > 15) { - msg_putchar('\n'); - if (got_int) { - break; - } - msg_advance(15); - } - } else { - for (p = tagp.command; - *p && *p != '\r' && *p != '\n'; - p++) { - } - command_end = p; - } - - // Put the info (in several lines) at column 15. - // Don't display "/^" and "?^". - p = tagp.command; - if (*p == '/' || *p == '?') { - p++; - if (*p == '^') { - p++; - } - } - // Remove leading whitespace from pattern - while (p != command_end && ascii_isspace(*p)) { - p++; - } + // Put the info (in several lines) at column 15. + // Don't display "/^" and "?^". + p = tagp.command; + if (*p == '/' || *p == '?') { + p++; + if (*p == '^') { + p++; + } + } + // Remove leading whitespace from pattern + while (p != command_end && ascii_isspace(*p)) { + p++; + } - while (p != command_end) { - if (msg_col + (*p == TAB ? 1 : ptr2cells(p)) > Columns) { - msg_putchar('\n'); - } - if (got_int) { - break; - } - msg_advance(15); + while (p != command_end) { + if (msg_col + (*p == TAB ? 1 : ptr2cells(p)) > Columns) { + msg_putchar('\n'); + } + if (got_int) { + break; + } + msg_advance(15); - // skip backslash used for escaping a command char or - // a backslash - if (*p == '\\' && (*(p + 1) == *tagp.command - || *(p + 1) == '\\')) { - p++; - } + // skip backslash used for escaping a command char or + // a backslash + if (*p == '\\' && (*(p + 1) == *tagp.command + || *(p + 1) == '\\')) { + p++; + } - if (*p == TAB) { - msg_putchar(' '); - p++; - } else { - p = msg_outtrans_one(p, 0); - } + if (*p == TAB) { + msg_putchar(' '); + p++; + } else { + p = msg_outtrans_one(p, 0); + } - // don't display the "$/;\"" and "$?;\"" - if (p == command_end - 2 && *p == '$' - && *(p + 1) == *tagp.command) { - break; - } - // don't display matching '/' or '?' - if (p == command_end - 1 && *p == *tagp.command - && (*p == '/' || *p == '?')) { - break; - } - } - if (msg_col) { - msg_putchar('\n'); - } - os_breakcheck(); + // don't display the "$/;\"" and "$?;\"" + if (p == command_end - 2 && *p == '$' + && *(p + 1) == *tagp.command) { + break; + } + // don't display matching '/' or '?' + if (p == command_end - 1 && *p == *tagp.command + && (*p == '/' || *p == '?')) { + break; + } } - if (got_int) { - got_int = false; // only stop the listing + if (msg_col) { + msg_putchar('\n'); } + os_breakcheck(); + } + if (got_int) { + got_int = false; // only stop the listing + } } // // Add the matching tags to the location list for the current // window. // -static int -add_llist_tags( - char_u *tag, - int num_matches, - char_u **matches) +static int add_llist_tags(char_u *tag, int num_matches, char_u **matches) { - list_T *list; - char_u tag_name[128 + 1]; - char_u *fname; - char_u *cmd; - int i; - char_u *p; - tagptrs_T tagp; - - fname = xmalloc(MAXPATHL + 1); - cmd = xmalloc(CMDBUFFSIZE + 1); - list = tv_list_alloc(0); - - for (i = 0; i < num_matches; i++) { - int len, cmd_len; - long lnum; - dict_T *dict; - - parse_match(matches[i], &tagp); - - // Save the tag name - len = (int)(tagp.tagname_end - tagp.tagname); - if (len > 128) { - len = 128; - } - xstrlcpy((char *)tag_name, (const char *)tagp.tagname, len + 1); - tag_name[len] = NUL; + list_T *list; + char_u tag_name[128 + 1]; + char_u *fname; + char_u *cmd; + int i; + char_u *p; + tagptrs_T tagp; - // Save the tag file name - p = tag_full_fname(&tagp); - if (p == NULL) { - continue; - } - xstrlcpy((char *)fname, (const char *)p, MAXPATHL); - XFREE_CLEAR(p); - - // Get the line number or the search pattern used to locate - // the tag. - lnum = 0; - if (isdigit(*tagp.command)) { - // Line number is used to locate the tag - lnum = atol((char *)tagp.command); - } else { - char_u *cmd_start, *cmd_end; + fname = xmalloc(MAXPATHL + 1); + cmd = xmalloc(CMDBUFFSIZE + 1); + list = tv_list_alloc(0); - // Search pattern is used to locate the tag + for (i = 0; i < num_matches; i++) { + int len, cmd_len; + long lnum; + dict_T *dict; - // Locate the end of the command - cmd_start = tagp.command; - cmd_end = tagp.command_end; - if (cmd_end == NULL) { - for (p = tagp.command; - *p && *p != '\r' && *p != '\n'; p++) { - } - cmd_end = p; - } + parse_match(matches[i], &tagp); - // Now, cmd_end points to the character after the - // command. Adjust it to point to the last - // character of the command. - cmd_end--; + // Save the tag name + len = (int)(tagp.tagname_end - tagp.tagname); + if (len > 128) { + len = 128; + } + xstrlcpy((char *)tag_name, (const char *)tagp.tagname, len + 1); + tag_name[len] = NUL; - // Skip the '/' and '?' characters at the - // beginning and end of the search pattern. - if (*cmd_start == '/' || *cmd_start == '?') { - cmd_start++; - } + // Save the tag file name + p = tag_full_fname(&tagp); + if (p == NULL) { + continue; + } + xstrlcpy((char *)fname, (const char *)p, MAXPATHL); + XFREE_CLEAR(p); + + // Get the line number or the search pattern used to locate + // the tag. + lnum = 0; + if (isdigit(*tagp.command)) { + // Line number is used to locate the tag + lnum = atol((char *)tagp.command); + } else { + char_u *cmd_start, *cmd_end; - if (*cmd_end == '/' || *cmd_end == '?') { - cmd_end--; - } + // Search pattern is used to locate the tag - len = 0; - cmd[0] = NUL; + // Locate the end of the command + cmd_start = tagp.command; + cmd_end = tagp.command_end; + if (cmd_end == NULL) { + for (p = tagp.command; + *p && *p != '\r' && *p != '\n'; p++) { + } + cmd_end = p; + } - // If "^" is present in the tag search pattern, then - // copy it first. - if (*cmd_start == '^') { - STRCPY(cmd, "^"); - cmd_start++; - len++; - } + // Now, cmd_end points to the character after the + // command. Adjust it to point to the last + // character of the command. + cmd_end--; - // Precede the tag pattern with \V to make it very - // nomagic. - STRCAT(cmd, "\\V"); - len += 2; + // Skip the '/' and '?' characters at the + // beginning and end of the search pattern. + if (*cmd_start == '/' || *cmd_start == '?') { + cmd_start++; + } - cmd_len = (int)(cmd_end - cmd_start + 1); - if (cmd_len > (CMDBUFFSIZE - 5)) { - cmd_len = CMDBUFFSIZE - 5; - } - snprintf((char *)cmd + len, CMDBUFFSIZE + 1 - len, - "%.*s", cmd_len, cmd_start); - len += cmd_len; - - if (cmd[len - 1] == '$') { - // Replace '$' at the end of the search pattern - // with '\$' - cmd[len - 1] = '\\'; - cmd[len] = '$'; - len++; - } + if (*cmd_end == '/' || *cmd_end == '?') { + cmd_end--; + } - cmd[len] = NUL; - } + len = 0; + cmd[0] = NUL; - dict = tv_dict_alloc(); - tv_list_append_dict(list, dict); + // If "^" is present in the tag search pattern, then + // copy it first. + if (*cmd_start == '^') { + STRCPY(cmd, "^"); + cmd_start++; + len++; + } - tv_dict_add_str(dict, S_LEN("text"), (const char *)tag_name); - tv_dict_add_str(dict, S_LEN("filename"), (const char *)fname); - tv_dict_add_nr(dict, S_LEN("lnum"), lnum); - if (lnum == 0) { - tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cmd); - } + // Precede the tag pattern with \V to make it very + // nomagic. + STRCAT(cmd, "\\V"); + len += 2; + + cmd_len = (int)(cmd_end - cmd_start + 1); + if (cmd_len > (CMDBUFFSIZE - 5)) { + cmd_len = CMDBUFFSIZE - 5; + } + snprintf((char *)cmd + len, CMDBUFFSIZE + 1 - len, + "%.*s", cmd_len, cmd_start); + len += cmd_len; + + if (cmd[len - 1] == '$') { + // Replace '$' at the end of the search pattern + // with '\$' + cmd[len - 1] = '\\'; + cmd[len] = '$'; + len++; + } + + cmd[len] = NUL; } - vim_snprintf((char *)IObuff, IOSIZE, "ltag %s", tag); - set_errorlist(curwin, list, ' ', IObuff, NULL); + dict = tv_dict_alloc(); + tv_list_append_dict(list, dict); - tv_list_free(list); - XFREE_CLEAR(fname); - XFREE_CLEAR(cmd); + tv_dict_add_str(dict, S_LEN("text"), (const char *)tag_name); + tv_dict_add_str(dict, S_LEN("filename"), (const char *)fname); + tv_dict_add_nr(dict, S_LEN("lnum"), lnum); + if (lnum == 0) { + tv_dict_add_str(dict, S_LEN("pattern"), (const char *)cmd); + } + } - return OK; + vim_snprintf((char *)IObuff, IOSIZE, "ltag %s", tag); + set_errorlist(curwin, list, ' ', IObuff, NULL); + + tv_list_free(list); + XFREE_CLEAR(fname); + XFREE_CLEAR(cmd); + + return OK; } /* @@ -1024,8 +1022,9 @@ static void taglen_advance(int l) if (l == MAXCOL) { msg_putchar('\n'); msg_advance(24); - } else + } else { msg_advance(13 + l); + } } /* @@ -1034,18 +1033,19 @@ static void taglen_advance(int l) void do_tags(exarg_T *eap) { int i; - char_u *name; - taggy_T *tagstack = curwin->w_tagstack; + char_u *name; + taggy_T *tagstack = curwin->w_tagstack; int tagstackidx = curwin->w_tagstackidx; int tagstacklen = curwin->w_tagstacklen; - /* Highlight title */ + // Highlight title MSG_PUTS_TITLE(_("\n # TO tag FROM line in file/text")); for (i = 0; i < tagstacklen; ++i) { if (tagstack[i].tagname != NULL) { name = fm_getname(&(tagstack[i].fmark), 30); - if (name == NULL) /* file name not available */ + if (name == NULL) { // file name not available continue; + } msg_putchar('\n'); vim_snprintf((char *)IObuff, IOSIZE, "%c%2d %2d %-15s %5ld ", @@ -1059,10 +1059,11 @@ void do_tags(exarg_T *eap) ? HL_ATTR(HLF_D) : 0); xfree(name); } - ui_flush(); /* show one line at a time */ + ui_flush(); // show one line at a time } - if (tagstackidx == tagstacklen) /* idx at top of stack */ + if (tagstackidx == tagstacklen) { // idx at top of stack MSG_PUTS("\n>"); + } } @@ -1078,15 +1079,17 @@ static int tag_strnicmp(char_u *s1, char_u *s2, size_t len) while (len > 0) { i = TOUPPER_ASC(*s1) - TOUPPER_ASC(*s2); - if (i != 0) - return i; /* this character different */ - if (*s1 == NUL) - break; /* strings match until NUL */ + if (i != 0) { + return i; // this character different + } + if (*s1 == NUL) { + break; // strings match until NUL + } ++s1; ++s2; --len; } - return 0; /* strings match */ + return 0; // strings match } @@ -1100,48 +1103,54 @@ static void prepare_pats(pat_T *pats, int has_re) if (has_re) { /* When the pattern starts with '^' or "\\<", binary searching can be * used (much faster). */ - if (pats->pat[0] == '^') + if (pats->pat[0] == '^') { pats->head = pats->pat + 1; - else if (pats->pat[0] == '\\' && pats->pat[1] == '<') + } else if (pats->pat[0] == '\\' && pats->pat[1] == '<') { pats->head = pats->pat + 2; - if (pats->head == pats->pat) + } + if (pats->head == pats->pat) { pats->headlen = 0; - else + } else { for (pats->headlen = 0; pats->head[pats->headlen] != NUL; - ++pats->headlen) + ++pats->headlen) { if (vim_strchr((char_u *)(p_magic ? ".[~*\\$" : "\\$"), - pats->head[pats->headlen]) != NULL) + pats->head[pats->headlen]) != NULL) { break; - if (p_tl != 0 && pats->headlen > p_tl) /* adjust for 'taglength' */ + } + } + } + if (p_tl != 0 && pats->headlen > p_tl) { // adjust for 'taglength' pats->headlen = p_tl; + } } - if (has_re) + if (has_re) { pats->regmatch.regprog = vim_regcomp(pats->pat, p_magic ? RE_MAGIC : 0); - else + } else { pats->regmatch.regprog = NULL; + } } -// -// Call the user-defined function to generate a list of tags used by -// find_tags(). -// -// Return OK if at least 1 tag has been successfully found, -// NOTDONE if the function returns v:null, and FAIL otherwise. -// -static int find_tagfunc_tags( - char_u *pat, // pattern supplied to the user-defined function - garray_T *ga, // the tags will be placed here - int *match_count, // here the number of tags found will be placed - int flags, // flags from find_tags (TAG_*) - char_u *buf_ffname) // name of buffer for priority +/// Call the user-defined function to generate a list of tags used by +/// find_tags(). +/// +/// Return OK if at least 1 tag has been successfully found, +/// NOTDONE if the function returns v:null, and FAIL otherwise. +/// +/// @param pat pattern supplied to the user-defined function +/// @param ga the tags will be placed here +/// @param match_count here the number of tags found will be placed +/// @param flags flags from find_tags (TAG_*) +/// @param buf_ffname name of buffer for priority +static int find_tagfunc_tags(char_u *pat, garray_T *ga, int *match_count, int flags, + char_u *buf_ffname) { - pos_T save_pos; - list_T *taglist; - int ntags = 0; - int result = FAIL; - typval_T args[4]; - typval_T rettv; + pos_T save_pos; + list_T *taglist; + int ntags = 0; + int result = FAIL; + typval_T args[4]; + typval_T rettv; char_u flagString[4]; taggy_T *tag = &curwin->w_tagstack[curwin->w_tagstackidx]; @@ -1195,12 +1204,12 @@ static int find_tagfunc_tags( taglist = rettv.vval.v_list; TV_LIST_ITER_CONST(taglist, li, { - char_u *res_name; - char_u *res_fname; - char_u *res_cmd; - char_u *res_kind; - int has_extra = 0; - int name_only = flags & TAG_NAMES; + char_u *res_name; + char_u *res_fname; + char_u *res_cmd; + char_u *res_kind; + int has_extra = 0; + int name_only = flags & TAG_NAMES; if (TV_LIST_ITEM_TV(li)->v_type != VAR_DICT) { EMSG(_(tfu_inv_ret_msg)); @@ -1326,50 +1335,46 @@ static int find_tagfunc_tags( return result; } -/* - * find_tags() - search for tags in tags files - * - * Return FAIL if search completely failed (*num_matches will be 0, *matchesp - * will be NULL), OK otherwise. - * - * There is a priority in which type of tag is recognized. - * - * 6. A static or global tag with a full matching tag for the current file. - * 5. A global tag with a full matching tag for another file. - * 4. A static tag with a full matching tag for another file. - * 3. A static or global tag with an ignore-case matching tag for the - * current file. - * 2. A global tag with an ignore-case matching tag for another file. - * 1. A static tag with an ignore-case matching tag for another file. - * - * Tags in an emacs-style tags file are always global. - * - * flags: - * TAG_HELP only search for help tags - * TAG_NAMES only return name of tag - * TAG_REGEXP use "pat" as a regexp - * TAG_NOIC don't always ignore case - * TAG_KEEP_LANG keep language - * TAG_CSCOPE use cscope results for tags - * TAG_NO_TAGFUNC do not call the 'tagfunc' function - */ -int -find_tags( - char_u *pat, // pattern to search for - int *num_matches, // return: number of matches found - char_u ***matchesp, // return: array of matches found - int flags, - int mincount, /* MAXCOL: find all matches - other: minimal number of matches */ - char_u *buf_ffname /* name of buffer for priority */ -) +/// find_tags() - search for tags in tags files +/// +/// Return FAIL if search completely failed (*num_matches will be 0, *matchesp +/// will be NULL), OK otherwise. +/// +/// There is a priority in which type of tag is recognized. +/// +/// 6. A static or global tag with a full matching tag for the current file. +/// 5. A global tag with a full matching tag for another file. +/// 4. A static tag with a full matching tag for another file. +/// 3. A static or global tag with an ignore-case matching tag for the +/// current file. +/// 2. A global tag with an ignore-case matching tag for another file. +/// 1. A static tag with an ignore-case matching tag for another file. +/// +/// Tags in an emacs-style tags file are always global. +/// +/// flags: +/// TAG_HELP only search for help tags +/// TAG_NAMES only return name of tag +/// TAG_REGEXP use "pat" as a regexp +/// TAG_NOIC don't always ignore case +/// TAG_KEEP_LANG keep language +/// TAG_CSCOPE use cscope results for tags +/// TAG_NO_TAGFUNC do not call the 'tagfunc' function +/// +/// @param pat pattern to search for +/// @param num_matches return: number of matches found +/// @param matchesp return: array of matches found +/// @param mincount MAXCOL: find all matches other: minimal number of matches */ +/// @param buf_ffname name of buffer for priority +int find_tags(char_u *pat, int *num_matches, char_u ***matchesp, int flags, int mincount, + char_u *buf_ffname) { - FILE *fp; - char_u *lbuf; /* line buffer */ - int lbuf_size = LSIZE; /* length of lbuf */ - char_u *tag_fname; /* name of tag file */ - tagname_T tn; /* info for get_tagfname() */ - int first_file; /* trying first tag file */ + FILE *fp; + char_u *lbuf; // line buffer + int lbuf_size = LSIZE; // length of lbuf + char_u *tag_fname; // name of tag file + tagname_T tn; // info for get_tagfname() + int first_file; // trying first tag file tagptrs_T tagp; bool did_open = false; // did open a tag file bool stop_searching = false; // stop when match found or error @@ -1377,8 +1382,8 @@ find_tags( int is_static; // current tag line is static int is_current; // file name matches bool eof = false; // found end-of-file - char_u *p; - char_u *s; + char_u *p; + char_u *s; int i; int tag_file_sorted = NUL; // !_TAG_FILE_SORTED value struct tag_search_info { // Binary search file offsets @@ -1396,17 +1401,17 @@ find_tags( off_T offset; int round; enum { - TS_START, /* at start of file */ - TS_LINEAR /* linear searching forward, till EOF */ - , TS_BINARY, /* binary searching */ - TS_SKIP_BACK, /* skipping backwards */ - TS_STEP_FORWARD /* stepping forwards */ - } state; /* Current search state */ + TS_START, // at start of file + TS_LINEAR // linear searching forward, till EOF + , TS_BINARY, // binary searching + TS_SKIP_BACK, // skipping backwards + TS_STEP_FORWARD // stepping forwards + } state; // Current search state int cmplen; - int match; /* matches */ - int match_no_ic = 0; /* matches with rm_ic == FALSE */ - int match_re; /* match with regexp */ + int match; // matches + int match_no_ic = 0; // matches with rm_ic == FALSE + int match_re; // match with regexp int matchoff = 0; int save_emsg_off; @@ -1416,16 +1421,16 @@ find_tags( hashtab_T ht_match[MT_COUNT]; // stores matches by key hash_T hash = 0; int match_count = 0; // number of matches found - char_u **matches; + char_u **matches; int mtt; int help_save; int help_pri = 0; - char_u *help_lang_find = NULL; // lang to be found + char_u *help_lang_find = NULL; // lang to be found char_u help_lang[3]; // lang of current tags file - char_u *saved_pat = NULL; // copy of pat[] + char_u *saved_pat = NULL; // copy of pat[] bool is_txt = false; - pat_T orgpat; /* holds unconverted pattern info */ + pat_T orgpat; // holds unconverted pattern info vimconv_T vimconv; int findall = (mincount == MAXCOL || mincount == TAG_MANY); @@ -1447,22 +1452,22 @@ find_tags( // Change the value of 'ignorecase' according to 'tagcase' for the // duration of this function. switch (curbuf->b_tc_flags ? curbuf->b_tc_flags : tc_flags) { - case TC_FOLLOWIC: - break; - case TC_IGNORE: - p_ic = true; - break; - case TC_MATCH: - p_ic = false; - break; - case TC_FOLLOWSCS: - p_ic = ignorecase(pat); - break; - case TC_SMART: - p_ic = ignorecase_opt(pat, true, true); - break; - default: - abort(); + case TC_FOLLOWIC: + break; + case TC_IGNORE: + p_ic = true; + break; + case TC_MATCH: + p_ic = false; + break; + case TC_FOLLOWSCS: + p_ic = ignorecase(pat); + break; + case TC_SMART: + p_ic = ignorecase_opt(pat, true, true); + break; + default: + abort(); } help_save = curbuf->b_help; @@ -1480,7 +1485,7 @@ find_tags( hash_init(&ht_match[mtt]); } - STRCPY(tag_fname, "from cscope"); /* for error messages */ + STRCPY(tag_fname, "from cscope"); // for error messages /* * Initialize a few variables @@ -1506,15 +1511,17 @@ find_tags( orgpat.len -= 3; } } - if (p_tl != 0 && orgpat.len > p_tl) /* adjust for 'taglength' */ + if (p_tl != 0 && orgpat.len > p_tl) { // adjust for 'taglength' orgpat.len = p_tl; + } save_emsg_off = emsg_off; - emsg_off = TRUE; /* don't want error for invalid RE here */ + emsg_off = TRUE; // don't want error for invalid RE here prepare_pats(&orgpat, has_re); emsg_off = save_emsg_off; - if (has_re && orgpat.regmatch.regprog == NULL) + if (has_re && orgpat.regmatch.regprog == NULL) { goto findtag_end; + } // This is only to avoid a compiler warning for using search_info // uninitialised. @@ -1580,8 +1587,9 @@ find_tags( /* When searching for a specific language skip tags files * for other languages. */ if (help_lang_find != NULL - && STRICMP(help_lang, help_lang_find) != 0) + && STRICMP(help_lang, help_lang_find) != 0) { continue; + } /* For CTRL-] in a help file prefer a match with the same * language. */ @@ -1591,23 +1599,26 @@ find_tags( && (i = (int)STRLEN(curbuf->b_fname)) > 4 && curbuf->b_fname[i - 1] == 'x' && curbuf->b_fname[i - 4] == '.' - && STRNICMP(curbuf->b_fname + i - 3, help_lang, 2) == 0) + && STRNICMP(curbuf->b_fname + i - 3, help_lang, 2) == 0) { help_pri = 0; - else { + } else { help_pri = 1; for (s = p_hlg; *s != NUL; ++s) { - if (STRNICMP(s, help_lang, 2) == 0) + if (STRNICMP(s, help_lang, 2) == 0) { break; + } ++help_pri; - if ((s = vim_strchr(s, ',')) == NULL) + if ((s = vim_strchr(s, ',')) == NULL) { break; + } } if (s == NULL || *s == NUL) { /* Language not in 'helplang': use last, prefer English, * unless found already. */ ++help_pri; - if (STRICMP(help_lang, "en") != 0) + if (STRICMP(help_lang, "en") != 0) { ++help_pri; + } } } } @@ -1624,7 +1635,7 @@ find_tags( } did_open = true; // remember that we found at least one file - state = TS_START; /* we're at the start of the file */ + state = TS_START; // we're at the start of the file /* * Read and parse the lines in the file one by one @@ -1636,8 +1647,9 @@ find_tags( } else { fast_breakcheck(); } - if ((flags & TAG_INS_COMP)) /* Double brackets for gcc */ + if ((flags & TAG_INS_COMP)) { // Double brackets for gcc ins_compl_check_keys(30, false); + } if (got_int || compl_interrupted) { stop_searching = true; break; @@ -1649,18 +1661,20 @@ find_tags( retval = OK; break; } - if (get_it_again) + if (get_it_again) { goto line_read_in; + } /* * For binary search: compute the next offset to use. */ if (state == TS_BINARY) { offset = search_info.low_offset + ((search_info.high_offset - search_info.low_offset) / 2); - if (offset == search_info.curr_offset) - break; /* End the binary search without a match. */ - else + if (offset == search_info.curr_offset) { + break; // End the binary search without a match. + } else { search_info.curr_offset = offset; + } } else if (state == TS_SKIP_BACK) { // Skipping back (after a match during binary search). search_info.curr_offset -= lbuf_size * 2; @@ -1676,7 +1690,7 @@ find_tags( * start of the next line. */ if (state == TS_BINARY || state == TS_SKIP_BACK) { - /* Adjust the search file offset to the correct position */ + // Adjust the search file offset to the correct position search_info.curr_offset_used = search_info.curr_offset; vim_fseek(fp, search_info.curr_offset, SEEK_SET); eof = vim_fgets(lbuf, lbuf_size, fp); @@ -1691,13 +1705,13 @@ find_tags( } eof = vim_fgets(lbuf, lbuf_size, fp); } - /* skip empty and blank lines */ + // skip empty and blank lines while (!eof && vim_isblankline(lbuf)) { search_info.curr_offset = vim_ftell(fp); eof = vim_fgets(lbuf, lbuf_size, fp); } if (eof) { - /* Hit end of file. Skip backwards. */ + // Hit end of file. Skip backwards. state = TS_SKIP_BACK; search_info.match_offset = vim_ftell(fp); search_info.curr_offset = search_info.curr_offset_used; @@ -1708,7 +1722,7 @@ find_tags( * Not jumping around in the file: Read the next line. */ else { - /* skip empty and blank lines */ + // skip empty and blank lines do { eof = use_cscope ? cs_fgets(lbuf, lbuf_size) @@ -1716,13 +1730,13 @@ find_tags( } while (!eof && vim_isblankline(lbuf)); if (eof) { - break; /* end of file */ + break; // end of file } } line_read_in: if (vimconv.vc_type != CONV_NONE) { - char_u *conv_line; + char_u *conv_line; int len; /* Convert every line. Converting the pattern from 'enc' to @@ -1730,7 +1744,7 @@ line_read_in: * not recognized. */ conv_line = string_convert(&vimconv, lbuf, NULL); if (conv_line != NULL) { - /* Copy or swap lbuf and conv_line. */ + // Copy or swap lbuf and conv_line. len = (int)STRLEN(conv_line) + 1; if (len > lbuf_size) { xfree(lbuf); @@ -1754,30 +1768,33 @@ line_read_in: * case is folded lower case letters sort before "_". */ if (STRNCMP(lbuf, "!_TAG_", 6) <= 0 || (lbuf[0] == '!' && ASCII_ISLOWER(lbuf[1]))) { - if (STRNCMP(lbuf, "!_TAG_", 6) != 0) + if (STRNCMP(lbuf, "!_TAG_", 6) != 0) { /* Non-header item before the header, e.g. "!" itself. */ goto parse_line; + } /* * Read header line. */ - if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) + if (STRNCMP(lbuf, "!_TAG_FILE_SORTED\t", 18) == 0) { tag_file_sorted = lbuf[18]; + } if (STRNCMP(lbuf, "!_TAG_FILE_ENCODING\t", 20) == 0) { /* Prepare to convert every line from the specified * encoding to 'encoding'. */ - for (p = lbuf + 20; *p > ' ' && *p < 127; ++p) + for (p = lbuf + 20; *p > ' ' && *p < 127; ++p) { ; + } *p = NUL; convert_setup(&vimconv, lbuf + 20, p_enc); } - /* Read the next line. Unrecognized flags are ignored. */ + // Read the next line. Unrecognized flags are ignored. continue; } - /* Headers ends. */ + // Headers ends. /* * When there is no tag head, or ignoring case, need to do a @@ -1788,18 +1805,19 @@ line_read_in: * flag set. * For cscope, it's always linear. */ - if (linear || use_cscope) + if (linear || use_cscope) { state = TS_LINEAR; - else if (tag_file_sorted == NUL) + } else if (tag_file_sorted == NUL) { state = TS_BINARY; - else if (tag_file_sorted == '1') + } else if (tag_file_sorted == '1') { state = TS_BINARY; - else if (tag_file_sorted == '2') { + } else if (tag_file_sorted == '2') { state = TS_BINARY; sortic = true; orgpat.regmatch.rm_ic = (p_ic || !noic); - } else + } else { state = TS_LINEAR; + } if (state == TS_BINARY && orgpat.regmatch.rm_ic && !sortic) { /* Binary search won't work for ignoring case, use linear @@ -1865,20 +1883,23 @@ parse_line: * there is no regexp, or the tag is too short. */ cmplen = (int)(tagp.tagname_end - tagp.tagname); - if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */ + if (p_tl != 0 && cmplen > p_tl) { // adjust for 'taglength' cmplen = p_tl; - if (has_re && orgpat.headlen < cmplen) + } + if (has_re && orgpat.headlen < cmplen) { cmplen = orgpat.headlen; - else if (state == TS_LINEAR && orgpat.headlen != cmplen) + } else if (state == TS_LINEAR && orgpat.headlen != cmplen) { continue; + } if (state == TS_BINARY) { /* * Simplistic check for unsorted tags file. */ i = (int)tagp.tagname[0]; - if (sortic) + if (sortic) { i = TOUPPER_ASC(tagp.tagname[0]); + } if (i < search_info.low_char || i > search_info.high_char) { sort_error = true; } @@ -1886,21 +1907,23 @@ parse_line: /* * Compare the current tag with the searched tag. */ - if (sortic) + if (sortic) { tagcmp = tag_strnicmp(tagp.tagname, orgpat.head, - (size_t)cmplen); - else + (size_t)cmplen); + } else { tagcmp = STRNCMP(tagp.tagname, orgpat.head, cmplen); + } /* * A match with a shorter tag means to search forward. * A match with a longer tag means to search backward. */ if (tagcmp == 0) { - if (cmplen < orgpat.headlen) + if (cmplen < orgpat.headlen) { tagcmp = -1; - else if (cmplen > orgpat.headlen) + } else if (cmplen > orgpat.headlen) { tagcmp = 1; + } } if (tagcmp == 0) { @@ -1915,37 +1938,40 @@ parse_line: search_info.curr_offset = vim_ftell(fp); if (search_info.curr_offset < search_info.high_offset) { search_info.low_offset = search_info.curr_offset; - if (sortic) + if (sortic) { search_info.low_char = TOUPPER_ASC(tagp.tagname[0]); - else + } else { search_info.low_char = tagp.tagname[0]; + } continue; } } if (tagcmp > 0 && search_info.curr_offset != search_info.high_offset) { search_info.high_offset = search_info.curr_offset; - if (sortic) + if (sortic) { search_info.high_char = TOUPPER_ASC(tagp.tagname[0]); - else + } else { search_info.high_char = tagp.tagname[0]; + } continue; } - /* No match yet and are at the end of the binary search. */ + // No match yet and are at the end of the binary search. break; - } else if (state == TS_SKIP_BACK) { + } else if (state == TS_SKIP_BACK) { assert(cmplen >= 0); - if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) + if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) { state = TS_STEP_FORWARD; - else + } else { /* Have to skip back more. Restore the curr_offset * used, otherwise we get stuck at a long line. */ search_info.curr_offset = search_info.curr_offset_used; + } continue; - } else if (state == TS_STEP_FORWARD) { + } else if (state == TS_STEP_FORWARD) { assert(cmplen >= 0); if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) { if ((off_T)vim_ftell(fp) > search_info.match_offset) { @@ -1954,23 +1980,27 @@ parse_line: continue; // before first match } } - } else - /* skip this match if it can't match */ - assert(cmplen >= 0); - if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) + } else { + // skip this match if it can't match + assert(cmplen >= 0); + } + if (mb_strnicmp(tagp.tagname, orgpat.head, (size_t)cmplen) != 0) { continue; + } // Can be a matching tag, isolate the file name and command. tagp.fname = tagp.tagname_end + 1; tagp.fname_end = vim_strchr(tagp.fname, TAB); tagp.command = tagp.fname_end + 1; - if (tagp.fname_end == NULL) + if (tagp.fname_end == NULL) { i = FAIL; - else + } else { i = OK; - } else + } + } else { i = parse_tag_line(lbuf, - &tagp); + &tagp); + } if (i == FAIL) { line_error = true; break; @@ -1981,20 +2011,23 @@ parse_line: * a regexp). */ cmplen = (int)(tagp.tagname_end - tagp.tagname); - if (p_tl != 0 && cmplen > p_tl) /* adjust for 'taglength' */ + if (p_tl != 0 && cmplen > p_tl) { // adjust for 'taglength' cmplen = p_tl; - /* if tag length does not match, don't try comparing */ - if (orgpat.len != cmplen) + } + // if tag length does not match, don't try comparing + if (orgpat.len != cmplen) { match = FALSE; - else { + } else { if (orgpat.regmatch.rm_ic) { assert(cmplen >= 0); match = mb_strnicmp(tagp.tagname, orgpat.pat, (size_t)cmplen) == 0; - if (match) + if (match) { match_no_ic = (STRNCMP(tagp.tagname, orgpat.pat, - cmplen) == 0); - } else + cmplen) == 0); + } + } else { match = (STRNCMP(tagp.tagname, orgpat.pat, cmplen) == 0); + } } /* @@ -2012,7 +2045,7 @@ parse_line: if (orgpat.regmatch.rm_ic) { orgpat.regmatch.rm_ic = FALSE; match_no_ic = vim_regexec(&orgpat.regmatch, tagp.tagname, - (colnr_T)0); + (colnr_T)0); orgpat.regmatch.rm_ic = TRUE; } } @@ -2025,7 +2058,7 @@ parse_line: int len = 0; if (use_cscope) { - /* Don't change the ordering, always use the same table. */ + // Don't change the ordering, always use the same table. mtt = MT_GL_OTH; } else { // Decide in which array to store this match. @@ -2035,27 +2068,31 @@ parse_line: // Decide in which of the sixteen tables to store this match. if (is_static) { - if (is_current) + if (is_current) { mtt = MT_ST_CUR; - else + } else { mtt = MT_ST_OTH; + } } else { - if (is_current) + if (is_current) { mtt = MT_GL_CUR; - else + } else { mtt = MT_GL_OTH; + } } - if (orgpat.regmatch.rm_ic && !match_no_ic) + if (orgpat.regmatch.rm_ic && !match_no_ic) { mtt += MT_IC_OFF; - if (match_re) + } + if (match_re) { mtt += MT_RE_OFF; + } } // Add the found match in ht_match[mtt] and ga_match[mtt]. // Store the info we need later, which depends on the kind of // tags we are dealing with. if (help_only) { -# define ML_EXTRA 3 +#define ML_EXTRA 3 // Append the help-heuristic number after the tagname, for // sorting it later. The heuristic is ignored for // detecting duplicates. @@ -2074,7 +2111,7 @@ parse_line: + help_pri); *tagp.tagname_end = TAB; - } else if (name_only) { + } else if (name_only) { if (get_it_again) { char_u *temp_end = tagp.command; @@ -2148,7 +2185,7 @@ parse_line: hash_add_item(&ht_match[mtt], hi, mfp, hash); ga_grow(&ga_match[mtt], 1); ((char_u **)(ga_match[mtt].ga_data)) - [ga_match[mtt].ga_len++] = mfp; + [ga_match[mtt].ga_len++] = mfp; match_count++; } else { // duplicate tag, drop it @@ -2156,9 +2193,10 @@ parse_line: } } } - if (use_cscope && eof) + if (use_cscope && eof) { break; - } /* forever */ + } + } // forever if (line_error) { EMSG2(_("E431: Format error in tags file \"%s\""), tag_fname); @@ -2169,10 +2207,12 @@ parse_line: line_error = false; } - if (!use_cscope) + if (!use_cscope) { fclose(fp); - if (vimconv.vc_type != CONV_NONE) + } + if (vimconv.vc_type != CONV_NONE) { convert_setup(&vimconv, NULL, NULL); + } tag_file_sorted = NUL; if (sort_error) { @@ -2188,27 +2228,31 @@ parse_line: stop_searching = true; } - if (stop_searching || use_cscope) + if (stop_searching || use_cscope) { break; + } + } // end of for-each-file loop - } /* end of for-each-file loop */ - - if (!use_cscope) + if (!use_cscope) { tagname_free(&tn); + } /* stop searching when already did a linear search, or when TAG_NOIC * used, and 'ignorecase' not set or already did case-ignore search */ - if (stop_searching || linear || (!p_ic && noic) || orgpat.regmatch.rm_ic) + if (stop_searching || linear || (!p_ic && noic) || orgpat.regmatch.rm_ic) { break; - if (use_cscope) + } + if (use_cscope) { break; - orgpat.regmatch.rm_ic = TRUE; /* try another time while ignoring case */ + } + orgpat.regmatch.rm_ic = TRUE; // try another time while ignoring case } if (!stop_searching) { - if (!did_open && verbose) /* never opened any tags file */ + if (!did_open && verbose) { // never opened any tags file EMSG(_("E433: No tags file")); - retval = OK; /* It's OK even when no tag found */ + } + retval = OK; // It's OK even when no tag found } findtag_end: @@ -2220,13 +2264,15 @@ findtag_end: * Move the matches from the ga_match[] arrays into one list of * matches. When retval == FAIL, free the matches. */ - if (retval == FAIL) + if (retval == FAIL) { match_count = 0; + } - if (match_count > 0) + if (match_count > 0) { matches = xmalloc(match_count * sizeof(char_u *)); - else + } else { matches = NULL; + } match_count = 0; for (mtt = 0; mtt < MT_COUNT; mtt++) { for (i = 0; i < ga_match[mtt].ga_len; i++) { @@ -2245,7 +2291,7 @@ findtag_end: } } } - matches[match_count++] = (char_u *)mfp; + matches[match_count++] = mfp; } } @@ -2275,7 +2321,7 @@ static void found_tagfile_cb(char_u *fname, void *cookie) char_u *const tag_fname = vim_strsave(fname); #ifdef BACKSLASH_IN_FILENAME - slash_adjust(tag_fname); + slash_adjust(tag_fname); #endif simplify_filename(tag_fname); GA_APPEND(char_u *, &tag_fnames, tag_fname); @@ -2293,24 +2339,22 @@ void free_tag_stuff(void) #endif -/* - * Get the next name of a tag file from the tag file list. - * For help files, use "tags" file only. - * - * Return FAIL if no more tag file names, OK otherwise. - */ -int -get_tagfname( - tagname_T *tnp, // holds status info - int first, // TRUE when first file name is wanted - char_u *buf // pointer to buffer of MAXPATHL chars -) +/// Get the next name of a tag file from the tag file list. +/// For help files, use "tags" file only. +/// +/// @param tnp holds status info +/// @param first TRUE when first file name is wanted +/// @param buf pointer to buffer of MAXPATHL chars +/// +/// @return FAIL if no more tag file names, OK otherwise. +int get_tagfname(tagname_T *tnp, int first, char_u *buf) { - char_u *fname = NULL; - char_u *r_ptr; + char_u *fname = NULL; + char_u *r_ptr; - if (first) + if (first) { memset(tnp, 0, sizeof(tagname_T)); + } if (curbuf->b_help) { /* @@ -2328,8 +2372,9 @@ get_tagfname( if (tnp->tn_hf_idx >= tag_fnames.ga_len) { /* Not found in 'runtimepath', use 'helpfile', if it exists and * wasn't used yet, replacing "help.txt" with "tags". */ - if (tnp->tn_hf_idx > tag_fnames.ga_len || *p_hf == NUL) + if (tnp->tn_hf_idx > tag_fnames.ga_len || *p_hf == NUL) { return FAIL; + } ++tnp->tn_hf_idx; STRCPY(buf, p_hf); STRCPY(path_tail(buf), "tags"); @@ -2367,14 +2412,15 @@ get_tagfname( for (;; ) { if (tnp->tn_did_filefind_init) { fname = vim_findfile(tnp->tn_search_ctx); - if (fname != NULL) + if (fname != NULL) { break; + } tnp->tn_did_filefind_init = FALSE; } else { - char_u *filename = NULL; + char_u *filename = NULL; - /* Stop when used all parts of 'tags'. */ + // Stop when used all parts of 'tags'. if (*tnp->tn_np == NUL) { vim_findfile_cleanup(tnp->tn_search_ctx); tnp->tn_search_ctx = NULL; @@ -2395,12 +2441,13 @@ get_tagfname( *filename++ = NUL; tnp->tn_search_ctx = vim_findfile_init(buf, filename, - r_ptr, 100, - FALSE, /* don't free visited list */ - FINDFILE_FILE, /* we search for a file */ - tnp->tn_search_ctx, TRUE, curbuf->b_ffname); - if (tnp->tn_search_ctx != NULL) + r_ptr, 100, + FALSE, // don't free visited list + FINDFILE_FILE, // we search for a file + tnp->tn_search_ctx, TRUE, curbuf->b_ffname); + if (tnp->tn_search_ctx != NULL) { tnp->tn_did_filefind_init = TRUE; + } } } @@ -2420,43 +2467,44 @@ void tagname_free(tagname_T *tnp) ga_clear_strings(&tag_fnames); } -/* - * Parse one line from the tags file. Find start/end of tag name, start/end of - * file name and start of search pattern. - * - * If is_etag is TRUE, tagp->fname and tagp->fname_end are not set. - * - * Return FAIL if there is a format error in this line, OK otherwise. - */ -static int -parse_tag_line( - char_u *lbuf, // line to be parsed - tagptrs_T *tagp -) +/// Parse one line from the tags file. Find start/end of tag name, start/end of +/// file name and start of search pattern. +/// +/// If is_etag is TRUE, tagp->fname and tagp->fname_end are not set. +/// +/// @param lbuf line to be parsed +/// +/// @return FAIL if there is a format error in this line, OK otherwise. +static int parse_tag_line(char_u *lbuf, tagptrs_T *tagp) { - char_u *p; + char_u *p; - /* Isolate the tagname, from lbuf up to the first white */ + // Isolate the tagname, from lbuf up to the first white tagp->tagname = lbuf; p = vim_strchr(lbuf, TAB); - if (p == NULL) + if (p == NULL) { return FAIL; + } tagp->tagname_end = p; - /* Isolate file name, from first to second white space */ - if (*p != NUL) + // Isolate file name, from first to second white space + if (*p != NUL) { ++p; + } tagp->fname = p; p = vim_strchr(p, TAB); - if (p == NULL) + if (p == NULL) { return FAIL; + } tagp->fname_end = p; - /* find start of search command, after second white space */ - if (*p != NUL) + // find start of search command, after second white space + if (*p != NUL) { ++p; - if (*p == NUL) + } + if (*p == NUL) { return FAIL; + } tagp->command = p; return OK; @@ -2466,12 +2514,12 @@ parse_tag_line( * Check if tagname is a static tag * * Static tags produced by the older ctags program have the format: - * 'file:tag file /pattern'. + * 'file:tag file /pattern'. * This is only recognized when both occurrence of 'file' are the same, to * avoid recognizing "string::string" or ":exit". * * Static tags produced by the new ctags program have the format: - * 'tag file /pattern/;"<Tab>file:' " + * 'tag file /pattern/;"<Tab>file:' " * * Return TRUE if it is a static tag and adjust *tagname to the real tag. * Return FALSE if it is not a static tag. @@ -2484,8 +2532,9 @@ static bool test_for_static(tagptrs_T *tagp) p = tagp->command; while ((p = vim_strchr(p, '\t')) != NULL) { ++p; - if (STRNCMP(p, "file:", 5) == 0) + if (STRNCMP(p, "file:", 5) == 0) { return TRUE; + } } return FALSE; @@ -2501,32 +2550,29 @@ static size_t matching_line_len(const char_u *const lbuf) return (p - lbuf) + STRLEN(p); } -/* - * Parse a line from a matching tag. Does not change the line itself. - * - * The line that we get looks like this: - * Emacs tag: <mtt><tag_fname><NUL><ebuf><NUL><lbuf> - * other tag: <mtt><tag_fname><NUL><NUL><lbuf> - * without Emacs tags: <mtt><tag_fname><NUL><lbuf> - * - * Return OK or FAIL. - */ -static int -parse_match( - char_u *lbuf, // input: matching line - tagptrs_T *tagp // output: pointers into the line -) +/// Parse a line from a matching tag. Does not change the line itself. +/// +/// The line that we get looks like this: +/// Emacs tag: <mtt><tag_fname><NUL><ebuf><NUL><lbuf> +/// other tag: <mtt><tag_fname><NUL><NUL><lbuf> +/// without Emacs tags: <mtt><tag_fname><NUL><lbuf> +/// +/// @param lbuf input: matching line +/// @param tagp output: pointers into the line +/// +/// @return OK or FAIL. +static int parse_match(char_u *lbuf, tagptrs_T *tagp) { int retval; - char_u *p; - char_u *pc, *pt; + char_u *p; + char_u *pc, *pt; tagp->tag_fname = lbuf + 1; lbuf += STRLEN(tagp->tag_fname) + 2; - /* Find search pattern and the file name for non-etags. */ + // Find search pattern and the file name for non-etags. retval = parse_tag_line(lbuf, - tagp); + tagp); tagp->tagkind = NULL; tagp->user_data = NULL; @@ -2534,7 +2580,7 @@ parse_match( tagp->command_end = NULL; if (retval == OK) { - /* Try to find a kind field: "kind:<kind>" or just "<kind>"*/ + // Try to find a kind field: "kind:<kind>" or just "<kind>" p = tagp->command; if (find_extra(&p) == OK) { tagp->command_end = p; @@ -2562,8 +2608,9 @@ parse_match( if (pc == NULL || (pt != NULL && pc > pt)) { tagp->tagkind = p; } - if (pt == NULL) + if (pt == NULL) { break; + } p = pt; MB_PTR_ADV(p); } @@ -2602,32 +2649,30 @@ static char_u *tag_full_fname(tagptrs_T *tagp) return fullname; } -/* - * Jump to a tag that has been found in one of the tag files - * - * returns OK for success, NOTAGFILE when file not found, FAIL otherwise. - */ -static int jumpto_tag( - const char_u *lbuf_arg, // line from the tags file for this tag - int forceit, // :ta with ! - int keep_help // keep help flag (FALSE for cscope) -) +/// Jump to a tag that has been found in one of the tag files +/// +/// @param lbuf_arg line from the tags file for this tag +/// @param forceit :ta with ! +/// @param keep_help keep help flag (FALSE for cscope) +/// +/// @return OK for success, NOTAGFILE when file not found, FAIL otherwise. +static int jumpto_tag(const char_u *lbuf_arg, int forceit, int keep_help) { int save_magic; bool save_p_ws; int save_p_scs, save_p_ic; linenr_T save_lnum; - char_u *str; - char_u *pbuf; /* search pattern buffer */ - char_u *pbuf_end; - char_u *tofree_fname = NULL; - char_u *fname; + char_u *str; + char_u *pbuf; // search pattern buffer + char_u *pbuf_end; + char_u *tofree_fname = NULL; + char_u *fname; tagptrs_T tagp; int retval = FAIL; int getfile_result = GETFILE_UNUSED; int search_options; - win_T *curwin_save = NULL; - char_u *full_fname = NULL; + win_T *curwin_save = NULL; + char_u *full_fname = NULL; const bool old_KeyTyped = KeyTyped; // getting the file may reset it const int l_g_do_tagpreview = g_do_tagpreview; const size_t len = matching_line_len(lbuf_arg) + 1; @@ -2636,7 +2681,7 @@ static int jumpto_tag( pbuf = xmalloc(LSIZE); - /* parse the match line into the tagp structure */ + // parse the match line into the tagp structure if (parse_match(lbuf, &tagp) == FAIL) { tagp.fname_end = NULL; goto erret; @@ -2646,7 +2691,7 @@ static int jumpto_tag( *tagp.fname_end = NUL; fname = tagp.fname; - /* copy the command to pbuf[], remove trailing CR/NL */ + // copy the command to pbuf[], remove trailing CR/NL str = tagp.command; for (pbuf_end = pbuf; *str && *str != '\n' && *str != '\r'; ) { *pbuf_end++ = *str++; @@ -2680,8 +2725,8 @@ static int jumpto_tag( * autocommand event (e.g., http://sys/file). */ if (!os_path_exists(fname) - && !has_autocmd(EVENT_BUFREADCMD, fname, NULL) - ) { + && !has_autocmd(EVENT_BUFREADCMD, fname, + NULL)) { retval = NOTAGFILE; xfree(nofile_fname); nofile_fname = vim_strsave(fname); @@ -2692,8 +2737,8 @@ static int jumpto_tag( if (l_g_do_tagpreview != 0) { - postponed_split = 0; /* don't split again below */ - curwin_save = curwin; /* Save current window */ + postponed_split = 0; // don't split again below + curwin_save = curwin; // Save current window /* * If we are reusing a window, we may change dir when @@ -2750,10 +2795,11 @@ static int jumpto_tag( if (keep_help) { /* A :ta from a help file will keep the b_help flag set. For ":ptag" * we need to use the flag from the window where we came from. */ - if (l_g_do_tagpreview != 0) + if (l_g_do_tagpreview != 0) { keep_help_flag = curwin_save->w_buffer->b_help; - else + } else { keep_help_flag = curbuf->b_help; + } } if (getfile_result == GETFILE_UNUSED) { @@ -2777,10 +2823,11 @@ static int jumpto_tag( * command. If 'cpoptions' does not contain 't', the search pattern * is not stored. */ - if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL) + if (vim_strchr(p_cpo, CPO_TAGPAT) != NULL) { search_options = 0; - else + } else { search_options = SEARCH_KEEP; + } /* * If the command is a search, try here. @@ -2791,14 +2838,15 @@ static int jumpto_tag( * anything following. */ str = pbuf; - if (pbuf[0] == '/' || pbuf[0] == '?') + if (pbuf[0] == '/' || pbuf[0] == '?') { str = skip_regexp(pbuf + 1, pbuf[0], FALSE, NULL) + 1; - if (str > pbuf_end - 1) { /* search command with nothing following */ + } + if (str > pbuf_end - 1) { // search command with nothing following save_p_ws = p_ws; save_p_ic = p_ic; save_p_scs = p_scs; - p_ws = true; /* need 'wrapscan' for backward searches */ - p_ic = FALSE; /* don't ignore case now */ + p_ws = true; // need 'wrapscan' for backward searches + p_ic = FALSE; // don't ignore case now p_scs = FALSE; save_lnum = curwin->w_cursor.lnum; if (tagp.tagline > 0) { @@ -2898,15 +2946,17 @@ static int jumpto_tag( * For a help buffer: Put the cursor line at the top of the window, * the help subject will be below it. */ - if (curbuf->b_help) + if (curbuf->b_help) { set_topline(curwin, curwin->w_cursor.lnum); - if ((fdo_flags & FDO_TAG) && old_KeyTyped) + } + if ((fdo_flags & FDO_TAG) && old_KeyTyped) { foldOpenCursor(); + } } if (l_g_do_tagpreview != 0 && curwin != curwin_save && win_valid(curwin_save)) { - /* Return cursor to where we were */ + // Return cursor to where we were validate_cursor(); redraw_later(curwin, VALID); win_enter(curwin_save, true); @@ -2935,11 +2985,10 @@ erret: // If 'tagrelative' option set, change fname (name of file containing tag) // according to tag_fname (name of tag file containing fname). // Returns a pointer to allocated memory. -static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname, - const bool expand) +static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname, const bool expand) { - char_u *p; - char_u *expanded_fname = NULL; + char_u *p; + char_u *expanded_fname = NULL; expand_T xpc; /* @@ -2949,9 +2998,10 @@ static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname, ExpandInit(&xpc); xpc.xp_context = EXPAND_FILES; expanded_fname = ExpandOne(&xpc, fname, NULL, - WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); - if (expanded_fname != NULL) + WILD_LIST_NOTFOUND|WILD_SILENT, WILD_EXPAND_FREE); + if (expanded_fname != NULL) { fname = expanded_fname; + } } char_u *retval; @@ -2961,13 +3011,14 @@ static char_u *expand_tag_fname(char_u *fname, char_u *const tag_fname, retval = xmalloc(MAXPATHL); STRCPY(retval, tag_fname); STRLCPY(retval + (p - tag_fname), fname, - MAXPATHL - (p - tag_fname)); + MAXPATHL - (p - tag_fname)); /* * Translate names like "src/a/../b/file.c" into "src/b/file.c". */ simplify_filename(retval); - } else + } else { retval = vim_strsave(fname); + } xfree(expanded_fname); @@ -2984,9 +3035,9 @@ static int test_for_current(char_u *fname, char_u *fname_end, char_u *tag_fname, { int c; int retval = FALSE; - char_u *fullname; + char_u *fullname; - if (buf_ffname != NULL) { /* if the buffer has a name */ + if (buf_ffname != NULL) { // if the buffer has a name { c = *fname_end; *fname_end = NUL; @@ -3053,13 +3104,8 @@ static void tagstack_clear_entry(taggy_T *item) XFREE_CLEAR(item->user_data); } -int -expand_tags ( - int tagnames, /* expand tag names */ - char_u *pat, - int *num_file, - char_u ***file -) +/// @param tagnames expand tag names +int expand_tags(int tagnames, char_u *pat, int *num_file, char_u ***file) { int i; int extra_flag; @@ -3116,17 +3162,13 @@ expand_tags ( } -/* - * Add a tag field to the dictionary "dict". - * Return OK or FAIL. - */ -static int -add_tag_field( - dict_T *dict, - const char *field_name, - const char_u *start, // start of the value - const char_u *end // after the value; can be NULL -) +/// Add a tag field to the dictionary "dict". +/// Return OK or FAIL. +/// +/// @param start start of the value +/// @param end after the value; can be NULL +static int add_tag_field(dict_T *dict, const char *field_name, const char_u *start, + const char_u *end) FUNC_ATTR_NONNULL_ARG(1, 2) { int len = 0; @@ -3145,12 +3187,14 @@ add_tag_field( if (start != NULL) { if (end == NULL) { end = start + STRLEN(start); - while (end > start && (end[-1] == '\r' || end[-1] == '\n')) + while (end > start && (end[-1] == '\r' || end[-1] == '\n')) { --end; + } } len = (int)(end - start); - if (len > MAXPATHL - 1) + if (len > MAXPATHL - 1) { len = MAXPATHL - 1; + } STRLCPY(buf, start, len + 1); } buf[len] = NUL; @@ -3165,9 +3209,9 @@ add_tag_field( int get_tags(list_T *list, char_u *pat, char_u *buf_fname) { int num_matches, i, ret; - char_u **matches; - char_u *full_fname; - dict_T *dict; + char_u **matches; + char_u *full_fname; + dict_T *dict; tagptrs_T tp; bool is_static; @@ -3178,7 +3222,7 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname) int parse_result = parse_match(matches[i], &tp); // Avoid an unused variable warning in release builds. - (void) parse_result; + (void)parse_result; assert(parse_result == OK); is_static = test_for_static(&tp); @@ -3216,29 +3260,35 @@ int get_tags(list_T *list, char_u *pat, char_u *buf_fname) // skip "file:" (static tag) p += 4; } else if (!ascii_iswhite(*p)) { - char_u *s, *n; + char_u *s, *n; int len; /* Add extra field as a dict entry. Fields are * separated by Tabs. */ n = p; - while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') + while (*p != NUL && *p >= ' ' && *p < 127 && *p != ':') { ++p; + } len = (int)(p - n); if (*p == ':' && len > 0) { s = ++p; - while (*p != NUL && *p >= ' ') + while (*p != NUL && *p >= ' ') { ++p; + } n[len] = NUL; - if (add_tag_field(dict, (char *)n, s, p) == FAIL) + if (add_tag_field(dict, (char *)n, s, p) == FAIL) { ret = FAIL; + } n[len] = ':'; - } else - /* Skip field without colon. */ - while (*p != NUL && *p >= ' ') + } else { + // Skip field without colon. + while (*p != NUL && *p >= ' ') { ++p; - if (*p == NUL) + } + } + if (*p == NUL) { break; + } } } } @@ -3319,14 +3369,8 @@ static void tagstack_shift(win_T *wp) } // Push a new item to the tag stack -static void tagstack_push_item( - win_T *wp, - char_u *tagname, - int cur_fnum, - int cur_match, - pos_T mark, - int fnum, - char_u *user_data) +static void tagstack_push_item(win_T *wp, char_u *tagname, int cur_fnum, int cur_match, pos_T mark, + int fnum, char_u *user_data) { taggy_T *tagstack = wp->w_tagstack; int idx = wp->w_tagstacklen; // top of the stack @@ -3382,13 +3426,12 @@ static void tagstack_push_items(win_T *wp, list_T *l) if (mark.col > 0) { mark.col--; } - tagstack_push_item( - wp, - tagname, - (int)tv_dict_get_number(itemdict, "bufnr"), - (int)tv_dict_get_number(itemdict, "matchnr") - 1, - mark, fnum, - (char_u *)tv_dict_get_string(itemdict, "user_data", true)); + tagstack_push_item(wp, + tagname, + (int)tv_dict_get_number(itemdict, "bufnr"), + (int)tv_dict_get_number(itemdict, "matchnr") - 1, + mark, fnum, + (char_u *)tv_dict_get_string(itemdict, "user_data", true)); } } diff --git a/src/nvim/terminal.c b/src/nvim/terminal.c index 3335fa500a..07d668ba5b 100644 --- a/src/nvim/terminal.c +++ b/src/nvim/terminal.c @@ -37,45 +37,44 @@ // Some code from pangoterm http://www.leonerd.org.uk/code/pangoterm #include <assert.h> -#include <stdio.h> -#include <stdint.h> #include <stdbool.h> - +#include <stdint.h> +#include <stdio.h> #include <vterm.h> -#include "nvim/log.h" -#include "nvim/vim.h" -#include "nvim/terminal.h" -#include "nvim/message.h" -#include "nvim/memory.h" -#include "nvim/option.h" -#include "nvim/highlight.h" -#include "nvim/macros.h" -#include "nvim/mbyte.h" +#include "nvim/api/private/helpers.h" +#include "nvim/ascii.h" #include "nvim/buffer.h" #include "nvim/change.h" -#include "nvim/ascii.h" +#include "nvim/edit.h" +#include "nvim/event/loop.h" +#include "nvim/event/time.h" +#include "nvim/ex_cmds.h" +#include "nvim/ex_docmd.h" +#include "nvim/fileio.h" #include "nvim/getchar.h" -#include "nvim/ui.h" -#include "nvim/syntax.h" -#include "nvim/screen.h" +#include "nvim/highlight.h" #include "nvim/keymap.h" -#include "nvim/edit.h" -#include "nvim/mouse.h" -#include "nvim/memline.h" +#include "nvim/log.h" +#include "nvim/macros.h" +#include "nvim/main.h" #include "nvim/map.h" +#include "nvim/mbyte.h" +#include "nvim/memline.h" +#include "nvim/memory.h" +#include "nvim/message.h" #include "nvim/misc1.h" +#include "nvim/mouse.h" #include "nvim/move.h" -#include "nvim/main.h" +#include "nvim/option.h" +#include "nvim/os/input.h" +#include "nvim/screen.h" #include "nvim/state.h" -#include "nvim/ex_docmd.h" -#include "nvim/ex_cmds.h" +#include "nvim/syntax.h" +#include "nvim/terminal.h" +#include "nvim/ui.h" +#include "nvim/vim.h" #include "nvim/window.h" -#include "nvim/fileio.h" -#include "nvim/event/loop.h" -#include "nvim/event/time.h" -#include "nvim/os/input.h" -#include "nvim/api/private/helpers.h" typedef struct terminal_state { VimState state; @@ -210,7 +209,7 @@ Terminal *terminal_open(buf_T *buf, TerminalOptions opts) buf->b_p_ma = false; // 'nomodifiable' buf->b_p_ul = -1; // 'undolevels' buf->b_p_scbk = // 'scrollback' (initialize local from global) - (p_scbk < 0) ? 10000 : MAX(1, p_scbk); + (p_scbk < 0) ? 10000 : MAX(1, p_scbk); buf->b_p_tw = 0; // 'textwidth' set_option_value("wrap", false, NULL, OPT_LOCAL); set_option_value("list", false, NULL, OPT_LOCAL); @@ -359,11 +358,21 @@ void terminal_enter(void) // Disable these options in terminal-mode. They are nonsense because cursor is // placed at end of buffer to "follow" output. #11072 win_T *save_curwin = curwin; - int save_w_p_cul = curwin->w_p_cul; + bool save_w_p_cul = curwin->w_p_cul; + char_u *save_w_p_culopt = NULL; + char_u save_w_p_culopt_flags = curwin->w_p_culopt_flags; int save_w_p_cuc = curwin->w_p_cuc; long save_w_p_so = curwin->w_p_so; long save_w_p_siso = curwin->w_p_siso; - curwin->w_p_cul = false; + if (curwin->w_p_cul && curwin->w_p_culopt_flags & CULOPT_NBR) { + if (strcmp((char *)curwin->w_p_culopt, "number")) { + save_w_p_culopt = curwin->w_p_culopt; + curwin->w_p_culopt = (char_u *)xstrdup("number"); + } + curwin->w_p_culopt_flags = CULOPT_NBR; + } else { + curwin->w_p_cul = false; + } curwin->w_p_cuc = false; curwin->w_p_so = 0; curwin->w_p_siso = 0; @@ -387,9 +396,16 @@ void terminal_enter(void) if (save_curwin == curwin) { // save_curwin may be invalid (window closed)! curwin->w_p_cul = save_w_p_cul; + if (save_w_p_culopt) { + xfree(curwin->w_p_culopt); + curwin->w_p_culopt = save_w_p_culopt; + } + curwin->w_p_culopt_flags = save_w_p_culopt_flags; curwin->w_p_cuc = save_w_p_cuc; curwin->w_p_so = save_w_p_so; curwin->w_p_siso = save_w_p_siso; + } else if (save_w_p_culopt) { + xfree(save_w_p_culopt); } // draw the unfocused cursor @@ -452,56 +468,56 @@ static int terminal_execute(VimState *state, int key) TerminalState *s = (TerminalState *)state; switch (key) { - case K_LEFTMOUSE: - case K_LEFTDRAG: - case K_LEFTRELEASE: - case K_MOUSEMOVE: - case K_MIDDLEMOUSE: - case K_MIDDLEDRAG: - case K_MIDDLERELEASE: - case K_RIGHTMOUSE: - case K_RIGHTDRAG: - case K_RIGHTRELEASE: - case K_MOUSEDOWN: - case K_MOUSEUP: - if (send_mouse_event(s->term, key)) { - return 0; - } - break; - - case K_EVENT: - // We cannot let an event free the terminal yet. It is still needed. - s->term->refcount++; - state_handle_k_event(); - s->term->refcount--; - if (s->term->buf_handle == 0) { - s->close = true; - return 0; - } - break; + case K_LEFTMOUSE: + case K_LEFTDRAG: + case K_LEFTRELEASE: + case K_MOUSEMOVE: + case K_MIDDLEMOUSE: + case K_MIDDLEDRAG: + case K_MIDDLERELEASE: + case K_RIGHTMOUSE: + case K_RIGHTDRAG: + case K_RIGHTRELEASE: + case K_MOUSEDOWN: + case K_MOUSEUP: + if (send_mouse_event(s->term, key)) { + return 0; + } + break; + + case K_EVENT: + // We cannot let an event free the terminal yet. It is still needed. + s->term->refcount++; + state_handle_k_event(); + s->term->refcount--; + if (s->term->buf_handle == 0) { + s->close = true; + return 0; + } + break; - case K_COMMAND: - do_cmdline(NULL, getcmdkeycmd, NULL, 0); - break; + case K_COMMAND: + do_cmdline(NULL, getcmdkeycmd, NULL, 0); + break; - case Ctrl_N: - if (s->got_bsl) { - return 0; - } - FALLTHROUGH; + case Ctrl_N: + if (s->got_bsl) { + return 0; + } + FALLTHROUGH; - default: - if (key == Ctrl_BSL && !s->got_bsl) { - s->got_bsl = true; - break; - } - if (s->term->closed) { - s->close = true; - return 0; - } + default: + if (key == Ctrl_BSL && !s->got_bsl) { + s->got_bsl = true; + break; + } + if (s->term->closed) { + s->close = true; + return 0; + } - s->got_bsl = false; - terminal_send_key(s->term, key); + s->got_bsl = false; + terminal_send_key(s->term, key); } if (curbuf->terminal == NULL) { @@ -554,30 +570,30 @@ static bool is_filter_char(int c) { unsigned int flag = 0; switch (c) { - case 0x08: - flag = TPF_BS; - break; - case 0x09: - flag = TPF_HT; - break; - case 0x0A: - case 0x0D: - break; - case 0x0C: - flag = TPF_FF; - break; - case 0x1b: - flag = TPF_ESC; - break; - case 0x7F: - flag = TPF_DEL; - break; - default: - if (c < ' ') { - flag = TPF_C0; - } else if (c >= 0x80 && c <= 0x9F) { - flag = TPF_C1; - } + case 0x08: + flag = TPF_BS; + break; + case 0x09: + flag = TPF_HT; + break; + case 0x0A: + case 0x0D: + break; + case 0x0C: + flag = TPF_FF; + break; + case 0x1b: + flag = TPF_ESC; + break; + case 0x7F: + flag = TPF_DEL; + break; + default: + if (c < ' ') { + flag = TPF_C0; + } else if (c >= 0x80 && c <= 0x9F) { + flag = TPF_C1; + } } return !!(tpf_flags & flag); } @@ -666,8 +682,7 @@ static int get_rgb(VTermState *state, VTermColor color) } -void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, - int *term_attrs) +void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, int *term_attrs) { int height, width; vterm_get_size(term->vt, &height, &width); @@ -701,12 +716,12 @@ void terminal_get_line_attributes(Terminal *term, win_T *wp, int linenr, bool bg_set = vt_bg_idx && vt_bg_idx <= 16 && term->color_set[vt_bg_idx-1]; int hl_attrs = (cell.attrs.bold ? HL_BOLD : 0) - | (cell.attrs.italic ? HL_ITALIC : 0) - | (cell.attrs.reverse ? HL_INVERSE : 0) - | (cell.attrs.underline ? HL_UNDERLINE : 0) - | (cell.attrs.strike ? HL_STRIKETHROUGH: 0) - | ((fg_indexed && !fg_set) ? HL_FG_INDEXED : 0) - | ((bg_indexed && !bg_set) ? HL_BG_INDEXED : 0); + | (cell.attrs.italic ? HL_ITALIC : 0) + | (cell.attrs.reverse ? HL_INVERSE : 0) + | (cell.attrs.underline ? HL_UNDERLINE : 0) + | (cell.attrs.strike ? HL_STRIKETHROUGH: 0) + | ((fg_indexed && !fg_set) ? HL_FG_INDEXED : 0) + | ((bg_indexed && !bg_set) ? HL_BG_INDEXED : 0); int attr_id = 0; @@ -757,12 +772,11 @@ static int term_damage(VTermRect rect, void *data) static int term_moverect(VTermRect dest, VTermRect src, void *data) { invalidate_terminal(data, MIN(dest.start_row, src.start_row), - MAX(dest.end_row, src.end_row)); + MAX(dest.end_row, src.end_row)); return 1; } -static int term_movecursor(VTermPos new, VTermPos old, int visible, - void *data) +static int term_movecursor(VTermPos new, VTermPos old, int visible, void *data) { Terminal *term = data; term->cursor.row = new.row; @@ -791,26 +805,26 @@ static int term_settermprop(VTermProp prop, VTermValue *val, void *data) Terminal *term = data; switch (prop) { - case VTERM_PROP_ALTSCREEN: - break; - - case VTERM_PROP_CURSORVISIBLE: - term->cursor.visible = val->boolean; - invalidate_terminal(term, term->cursor.row, term->cursor.row + 1); - break; - - case VTERM_PROP_TITLE: { - buf_T *buf = handle_get_buffer(term->buf_handle); - buf_set_term_title(buf, val->string); - break; - } + case VTERM_PROP_ALTSCREEN: + break; + + case VTERM_PROP_CURSORVISIBLE: + term->cursor.visible = val->boolean; + invalidate_terminal(term, term->cursor.row, term->cursor.row + 1); + break; + + case VTERM_PROP_TITLE: { + buf_T *buf = handle_get_buffer(term->buf_handle); + buf_set_term_title(buf, val->string); + break; + } - case VTERM_PROP_MOUSE: - term->forward_mouse = (bool)val->number; - break; + case VTERM_PROP_MOUSE: + term->forward_mouse = (bool)val->number; + break; - default: - return 0; + default: + return 0; } return 1; @@ -844,12 +858,11 @@ static int term_sb_push(int cols, const VTermScreenCell *cells, void *data) // Make room at the start by shifting to the right. memmove(term->sb_buffer + 1, term->sb_buffer, - sizeof(term->sb_buffer[0]) * (term->sb_current - 1)); - + sizeof(term->sb_buffer[0]) * (term->sb_current - 1)); } else if (term->sb_current > 0) { // Make room at the start by shifting to the right. memmove(term->sb_buffer + 1, term->sb_buffer, - sizeof(term->sb_buffer[0]) * term->sb_current); + sizeof(term->sb_buffer[0]) * term->sb_current); } if (!sbrow) { @@ -894,7 +907,7 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data) term->sb_current--; // Forget the "popped" row by shifting the rest onto it. memmove(term->sb_buffer, term->sb_buffer + 1, - sizeof(term->sb_buffer[0]) * (term->sb_current)); + sizeof(term->sb_buffer[0]) * (term->sb_current)); size_t cols_to_copy = (size_t)cols; if (cols_to_copy > sbrow->cols) { @@ -919,35 +932,41 @@ static int term_sb_pop(int cols, VTermScreenCell *cells, void *data) static void convert_modifiers(int key, VTermModifier *statep) { - if (mod_mask & MOD_MASK_SHIFT) { *statep |= VTERM_MOD_SHIFT; } - if (mod_mask & MOD_MASK_CTRL) { *statep |= VTERM_MOD_CTRL; } - if (mod_mask & MOD_MASK_ALT) { *statep |= VTERM_MOD_ALT; } + if (mod_mask & MOD_MASK_SHIFT) { + *statep |= VTERM_MOD_SHIFT; + } + if (mod_mask & MOD_MASK_CTRL) { + *statep |= VTERM_MOD_CTRL; + } + if (mod_mask & MOD_MASK_ALT) { + *statep |= VTERM_MOD_ALT; + } switch (key) { - case K_S_TAB: - case K_S_UP: - case K_S_DOWN: - case K_S_LEFT: - case K_S_RIGHT: - case K_S_F1: - case K_S_F2: - case K_S_F3: - case K_S_F4: - case K_S_F5: - case K_S_F6: - case K_S_F7: - case K_S_F8: - case K_S_F9: - case K_S_F10: - case K_S_F11: - case K_S_F12: - *statep |= VTERM_MOD_SHIFT; - break; - - case K_C_LEFT: - case K_C_RIGHT: - *statep |= VTERM_MOD_CTRL; - break; + case K_S_TAB: + case K_S_UP: + case K_S_DOWN: + case K_S_LEFT: + case K_S_RIGHT: + case K_S_F1: + case K_S_F2: + case K_S_F3: + case K_S_F4: + case K_S_F5: + case K_S_F6: + case K_S_F7: + case K_S_F8: + case K_S_F9: + case K_S_F10: + case K_S_F11: + case K_S_F12: + *statep |= VTERM_MOD_SHIFT; + break; + + case K_C_LEFT: + case K_C_RIGHT: + *statep |= VTERM_MOD_CTRL; + break; } } @@ -956,115 +975,212 @@ static VTermKey convert_key(int key, VTermModifier *statep) convert_modifiers(key, statep); switch (key) { - case K_BS: return VTERM_KEY_BACKSPACE; - case K_S_TAB: FALLTHROUGH; - case TAB: return VTERM_KEY_TAB; - case Ctrl_M: return VTERM_KEY_ENTER; - case ESC: return VTERM_KEY_ESCAPE; - - case K_S_UP: FALLTHROUGH; - case K_UP: return VTERM_KEY_UP; - case K_S_DOWN: FALLTHROUGH; - case K_DOWN: return VTERM_KEY_DOWN; - case K_S_LEFT: FALLTHROUGH; - case K_C_LEFT: FALLTHROUGH; - case K_LEFT: return VTERM_KEY_LEFT; - case K_S_RIGHT: FALLTHROUGH; - case K_C_RIGHT: FALLTHROUGH; - case K_RIGHT: return VTERM_KEY_RIGHT; - - case K_INS: return VTERM_KEY_INS; - case K_DEL: return VTERM_KEY_DEL; - case K_HOME: return VTERM_KEY_HOME; - case K_END: return VTERM_KEY_END; - case K_PAGEUP: return VTERM_KEY_PAGEUP; - case K_PAGEDOWN: return VTERM_KEY_PAGEDOWN; - - case K_K0: FALLTHROUGH; - case K_KINS: return VTERM_KEY_KP_0; - case K_K1: FALLTHROUGH; - case K_KEND: return VTERM_KEY_KP_1; - case K_K2: FALLTHROUGH; - case K_KDOWN: return VTERM_KEY_KP_2; - case K_K3: FALLTHROUGH; - case K_KPAGEDOWN: return VTERM_KEY_KP_3; - case K_K4: FALLTHROUGH; - case K_KLEFT: return VTERM_KEY_KP_4; - case K_K5: FALLTHROUGH; - case K_KORIGIN: return VTERM_KEY_KP_5; - case K_K6: FALLTHROUGH; - case K_KRIGHT: return VTERM_KEY_KP_6; - case K_K7: FALLTHROUGH; - case K_KHOME: return VTERM_KEY_KP_7; - case K_K8: FALLTHROUGH; - case K_KUP: return VTERM_KEY_KP_8; - case K_K9: FALLTHROUGH; - case K_KPAGEUP: return VTERM_KEY_KP_9; - case K_KDEL: FALLTHROUGH; - case K_KPOINT: return VTERM_KEY_KP_PERIOD; - case K_KENTER: return VTERM_KEY_KP_ENTER; - case K_KPLUS: return VTERM_KEY_KP_PLUS; - case K_KMINUS: return VTERM_KEY_KP_MINUS; - case K_KMULTIPLY: return VTERM_KEY_KP_MULT; - case K_KDIVIDE: return VTERM_KEY_KP_DIVIDE; - - case K_S_F1: FALLTHROUGH; - case K_F1: return VTERM_KEY_FUNCTION(1); - case K_S_F2: FALLTHROUGH; - case K_F2: return VTERM_KEY_FUNCTION(2); - case K_S_F3: FALLTHROUGH; - case K_F3: return VTERM_KEY_FUNCTION(3); - case K_S_F4: FALLTHROUGH; - case K_F4: return VTERM_KEY_FUNCTION(4); - case K_S_F5: FALLTHROUGH; - case K_F5: return VTERM_KEY_FUNCTION(5); - case K_S_F6: FALLTHROUGH; - case K_F6: return VTERM_KEY_FUNCTION(6); - case K_S_F7: FALLTHROUGH; - case K_F7: return VTERM_KEY_FUNCTION(7); - case K_S_F8: FALLTHROUGH; - case K_F8: return VTERM_KEY_FUNCTION(8); - case K_S_F9: FALLTHROUGH; - case K_F9: return VTERM_KEY_FUNCTION(9); - case K_S_F10: FALLTHROUGH; - case K_F10: return VTERM_KEY_FUNCTION(10); - case K_S_F11: FALLTHROUGH; - case K_F11: return VTERM_KEY_FUNCTION(11); - case K_S_F12: FALLTHROUGH; - case K_F12: return VTERM_KEY_FUNCTION(12); - - case K_F13: return VTERM_KEY_FUNCTION(13); - case K_F14: return VTERM_KEY_FUNCTION(14); - case K_F15: return VTERM_KEY_FUNCTION(15); - case K_F16: return VTERM_KEY_FUNCTION(16); - case K_F17: return VTERM_KEY_FUNCTION(17); - case K_F18: return VTERM_KEY_FUNCTION(18); - case K_F19: return VTERM_KEY_FUNCTION(19); - case K_F20: return VTERM_KEY_FUNCTION(20); - case K_F21: return VTERM_KEY_FUNCTION(21); - case K_F22: return VTERM_KEY_FUNCTION(22); - case K_F23: return VTERM_KEY_FUNCTION(23); - case K_F24: return VTERM_KEY_FUNCTION(24); - case K_F25: return VTERM_KEY_FUNCTION(25); - case K_F26: return VTERM_KEY_FUNCTION(26); - case K_F27: return VTERM_KEY_FUNCTION(27); - case K_F28: return VTERM_KEY_FUNCTION(28); - case K_F29: return VTERM_KEY_FUNCTION(29); - case K_F30: return VTERM_KEY_FUNCTION(30); - case K_F31: return VTERM_KEY_FUNCTION(31); - case K_F32: return VTERM_KEY_FUNCTION(32); - case K_F33: return VTERM_KEY_FUNCTION(33); - case K_F34: return VTERM_KEY_FUNCTION(34); - case K_F35: return VTERM_KEY_FUNCTION(35); - case K_F36: return VTERM_KEY_FUNCTION(36); - case K_F37: return VTERM_KEY_FUNCTION(37); - - default: return VTERM_KEY_NONE; + case K_BS: + return VTERM_KEY_BACKSPACE; + case K_S_TAB: + FALLTHROUGH; + case TAB: + return VTERM_KEY_TAB; + case Ctrl_M: + return VTERM_KEY_ENTER; + case ESC: + return VTERM_KEY_ESCAPE; + + case K_S_UP: + FALLTHROUGH; + case K_UP: + return VTERM_KEY_UP; + case K_S_DOWN: + FALLTHROUGH; + case K_DOWN: + return VTERM_KEY_DOWN; + case K_S_LEFT: + FALLTHROUGH; + case K_C_LEFT: + FALLTHROUGH; + case K_LEFT: + return VTERM_KEY_LEFT; + case K_S_RIGHT: + FALLTHROUGH; + case K_C_RIGHT: + FALLTHROUGH; + case K_RIGHT: + return VTERM_KEY_RIGHT; + + case K_INS: + return VTERM_KEY_INS; + case K_DEL: + return VTERM_KEY_DEL; + case K_HOME: + return VTERM_KEY_HOME; + case K_END: + return VTERM_KEY_END; + case K_PAGEUP: + return VTERM_KEY_PAGEUP; + case K_PAGEDOWN: + return VTERM_KEY_PAGEDOWN; + + case K_K0: + FALLTHROUGH; + case K_KINS: + return VTERM_KEY_KP_0; + case K_K1: + FALLTHROUGH; + case K_KEND: + return VTERM_KEY_KP_1; + case K_K2: + FALLTHROUGH; + case K_KDOWN: + return VTERM_KEY_KP_2; + case K_K3: + FALLTHROUGH; + case K_KPAGEDOWN: + return VTERM_KEY_KP_3; + case K_K4: + FALLTHROUGH; + case K_KLEFT: + return VTERM_KEY_KP_4; + case K_K5: + FALLTHROUGH; + case K_KORIGIN: + return VTERM_KEY_KP_5; + case K_K6: + FALLTHROUGH; + case K_KRIGHT: + return VTERM_KEY_KP_6; + case K_K7: + FALLTHROUGH; + case K_KHOME: + return VTERM_KEY_KP_7; + case K_K8: + FALLTHROUGH; + case K_KUP: + return VTERM_KEY_KP_8; + case K_K9: + FALLTHROUGH; + case K_KPAGEUP: + return VTERM_KEY_KP_9; + case K_KDEL: + FALLTHROUGH; + case K_KPOINT: + return VTERM_KEY_KP_PERIOD; + case K_KENTER: + return VTERM_KEY_KP_ENTER; + case K_KPLUS: + return VTERM_KEY_KP_PLUS; + case K_KMINUS: + return VTERM_KEY_KP_MINUS; + case K_KMULTIPLY: + return VTERM_KEY_KP_MULT; + case K_KDIVIDE: + return VTERM_KEY_KP_DIVIDE; + + case K_S_F1: + FALLTHROUGH; + case K_F1: + return VTERM_KEY_FUNCTION(1); + case K_S_F2: + FALLTHROUGH; + case K_F2: + return VTERM_KEY_FUNCTION(2); + case K_S_F3: + FALLTHROUGH; + case K_F3: + return VTERM_KEY_FUNCTION(3); + case K_S_F4: + FALLTHROUGH; + case K_F4: + return VTERM_KEY_FUNCTION(4); + case K_S_F5: + FALLTHROUGH; + case K_F5: + return VTERM_KEY_FUNCTION(5); + case K_S_F6: + FALLTHROUGH; + case K_F6: + return VTERM_KEY_FUNCTION(6); + case K_S_F7: + FALLTHROUGH; + case K_F7: + return VTERM_KEY_FUNCTION(7); + case K_S_F8: + FALLTHROUGH; + case K_F8: + return VTERM_KEY_FUNCTION(8); + case K_S_F9: + FALLTHROUGH; + case K_F9: + return VTERM_KEY_FUNCTION(9); + case K_S_F10: + FALLTHROUGH; + case K_F10: + return VTERM_KEY_FUNCTION(10); + case K_S_F11: + FALLTHROUGH; + case K_F11: + return VTERM_KEY_FUNCTION(11); + case K_S_F12: + FALLTHROUGH; + case K_F12: + return VTERM_KEY_FUNCTION(12); + + case K_F13: + return VTERM_KEY_FUNCTION(13); + case K_F14: + return VTERM_KEY_FUNCTION(14); + case K_F15: + return VTERM_KEY_FUNCTION(15); + case K_F16: + return VTERM_KEY_FUNCTION(16); + case K_F17: + return VTERM_KEY_FUNCTION(17); + case K_F18: + return VTERM_KEY_FUNCTION(18); + case K_F19: + return VTERM_KEY_FUNCTION(19); + case K_F20: + return VTERM_KEY_FUNCTION(20); + case K_F21: + return VTERM_KEY_FUNCTION(21); + case K_F22: + return VTERM_KEY_FUNCTION(22); + case K_F23: + return VTERM_KEY_FUNCTION(23); + case K_F24: + return VTERM_KEY_FUNCTION(24); + case K_F25: + return VTERM_KEY_FUNCTION(25); + case K_F26: + return VTERM_KEY_FUNCTION(26); + case K_F27: + return VTERM_KEY_FUNCTION(27); + case K_F28: + return VTERM_KEY_FUNCTION(28); + case K_F29: + return VTERM_KEY_FUNCTION(29); + case K_F30: + return VTERM_KEY_FUNCTION(30); + case K_F31: + return VTERM_KEY_FUNCTION(31); + case K_F32: + return VTERM_KEY_FUNCTION(32); + case K_F33: + return VTERM_KEY_FUNCTION(33); + case K_F34: + return VTERM_KEY_FUNCTION(34); + case K_F35: + return VTERM_KEY_FUNCTION(35); + case K_F36: + return VTERM_KEY_FUNCTION(36); + case K_F37: + return VTERM_KEY_FUNCTION(37); + + default: + return VTERM_KEY_NONE; } } -static void mouse_action(Terminal *term, int button, int row, int col, - bool drag, VTermModifier mod) +static void mouse_action(Terminal *term, int button, int row, int col, bool drag, VTermModifier mod) { if (term->pressed_button && (term->pressed_button != button || !drag)) { // release the previous button @@ -1100,16 +1216,26 @@ static bool send_mouse_event(Terminal *term, int c) bool drag = false; switch (c) { - case K_LEFTDRAG: drag = true; FALLTHROUGH; - case K_LEFTMOUSE: button = 1; break; - case K_MOUSEMOVE: drag = true; button = 0; break; - case K_MIDDLEDRAG: drag = true; FALLTHROUGH; - case K_MIDDLEMOUSE: button = 2; break; - case K_RIGHTDRAG: drag = true; FALLTHROUGH; - case K_RIGHTMOUSE: button = 3; break; - case K_MOUSEDOWN: button = 4; break; - case K_MOUSEUP: button = 5; break; - default: return false; + case K_LEFTDRAG: + drag = true; FALLTHROUGH; + case K_LEFTMOUSE: + button = 1; break; + case K_MOUSEMOVE: + drag = true; button = 0; break; + case K_MIDDLEDRAG: + drag = true; FALLTHROUGH; + case K_MIDDLEMOUSE: + button = 2; break; + case K_RIGHTDRAG: + drag = true; FALLTHROUGH; + case K_RIGHTMOUSE: + button = 3; break; + case K_MOUSEDOWN: + button = 4; break; + case K_MOUSEUP: + button = 5; break; + default: + return false; } mouse_action(term, button, row, col - offset, drag, 0); @@ -1162,7 +1288,7 @@ static void fetch_row(Terminal *term, int row, int end_col) if (cell.chars[0]) { for (int i = 0; cell.chars[i]; i++) { cell_len += utf_char2bytes((int)cell.chars[i], - (uint8_t *)ptr + cell_len); + (uint8_t *)ptr + cell_len); } } else { *ptr = ' '; @@ -1181,8 +1307,7 @@ static void fetch_row(Terminal *term, int row, int end_col) term->textbuf[line_len] = 0; } -static bool fetch_cell(Terminal *term, int row, int col, - VTermScreenCell *cell) +static bool fetch_cell(Terminal *term, int row, int col, VTermScreenCell *cell) { if (row < 0) { ScrollbackLine *sbrow = term->sb_buffer[-row - 1]; @@ -1197,8 +1322,8 @@ static bool fetch_cell(Terminal *term, int row, int col, return false; } } else { - vterm_screen_get_cell(term->vts, (VTermPos){.row = row, .col = col}, - cell); + vterm_screen_get_cell(term->vts, (VTermPos){ .row = row, .col = col }, + cell); } return true; } diff --git a/src/nvim/testdir/test_filetype.vim b/src/nvim/testdir/test_filetype.vim index cc789cb6bd..cca89cbd6d 100644 --- a/src/nvim/testdir/test_filetype.vim +++ b/src/nvim/testdir/test_filetype.vim @@ -259,7 +259,7 @@ let s:filename_checks = { \ 'jgraph': ['file.jgr'], \ 'jovial': ['file.jov', 'file.j73', 'file.jovial'], \ 'jproperties': ['file.properties', 'file.properties_xx', 'file.properties_xx_xx', 'some.properties_xx_xx_file'], - \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb'], + \ 'json': ['file.json', 'file.jsonp', 'file.json-patch', 'file.webmanifest', 'Pipfile.lock', 'file.ipynb', '.babelrc', '.eslintrc', '.prettierrc', '.firebaserc'], \ 'jsonc': ['file.jsonc'], \ 'jsp': ['file.jsp'], \ 'julia': ['file.jl'], @@ -344,6 +344,7 @@ let s:filename_checks = { \ 'nanorc': ['/etc/nanorc', 'file.nanorc', 'any/etc/nanorc'], \ 'ncf': ['file.ncf'], \ 'netrc': ['.netrc'], + \ 'nginx': ['file.nginx', 'nginxfile.conf', 'filenginx.conf', 'any/etc/nginx/file', 'any/usr/local/nginx/conf/file', 'any/nginx/file.conf'], \ 'ninja': ['file.ninja'], \ 'nqc': ['file.nqc'], \ 'nroff': ['file.tr', 'file.nr', 'file.roff', 'file.tmac', 'file.mom', 'tmac.file'], @@ -491,7 +492,7 @@ let s:filename_checks = { \ 'tak': ['file.tak'], \ 'taskdata': ['pending.data', 'completed.data', 'undo.data'], \ 'taskedit': ['file.task'], - \ 'tcl': ['file.tcl', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl'], + \ 'tcl': ['file.tcl', 'file.tm', 'file.tk', 'file.itcl', 'file.itk', 'file.jacl', '.tclshrc', 'tclsh.rc', '.wishrc'], \ 'teraterm': ['file.ttl'], \ 'terminfo': ['file.ti'], \ 'tex': ['file.latex', 'file.sty', 'file.dtx', 'file.ltx', 'file.bbl'], diff --git a/src/nvim/testdir/test_functions.vim b/src/nvim/testdir/test_functions.vim index e82fefc7fc..366615821c 100644 --- a/src/nvim/testdir/test_functions.vim +++ b/src/nvim/testdir/test_functions.vim @@ -585,6 +585,8 @@ func Test_mode() exe "normal iabc\<C-X>\<C-L>\<F2>\<Esc>u" call assert_equal('i-ic', g:current_modes) + exe "normal R\<F2>\<Esc>" + call assert_equal('R-R', g:current_modes) " R_CTRL-P: Multiple matches exe "normal RBa\<C-P>\<F2>\<Esc>u" call assert_equal('R-Rc', g:current_modes) @@ -619,6 +621,42 @@ func Test_mode() exe "normal Rabc\<C-X>\<C-L>\<F2>\<Esc>u" call assert_equal('R-Rc', g:current_modes) + exe "normal gR\<F2>\<Esc>" + call assert_equal('R-Rv', g:current_modes) + " gR_CTRL-P: Multiple matches + exe "normal gRBa\<C-P>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + " gR_CTRL-P: Single match + exe "normal gRBro\<C-P>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + " gR_CTRL-X + exe "normal gRBa\<C-X>\<F2>\<Esc>u" + call assert_equal('R-Rvx', g:current_modes) + " gR_CTRL-X CTRL-P: Multiple matches + exe "normal gRBa\<C-X>\<C-P>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + " gR_CTRL-X CTRL-P: Single match + exe "normal gRBro\<C-X>\<C-P>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + " gR_CTRL-X CTRL-P + CTRL-P: Single match + exe "normal gRBro\<C-X>\<C-P>\<C-P>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + " gR_CTRL-X CTRL-L: Multiple matches + exe "normal gR\<C-X>\<C-L>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + " gR_CTRL-X CTRL-L: Single match + exe "normal gRBlu\<C-X>\<C-L>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + " gR_CTRL-P: No match + exe "normal gRCom\<C-P>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + " gR_CTRL-X CTRL-P: No match + exe "normal gRCom\<C-X>\<C-P>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + " gR_CTRL-X CTRL-L: No match + exe "normal gRabc\<C-X>\<C-L>\<F2>\<Esc>u" + call assert_equal('R-Rvc', g:current_modes) + call assert_equal('n', mode(0)) call assert_equal('n', mode(1)) diff --git a/src/nvim/testdir/test_method.vim b/src/nvim/testdir/test_method.vim index d34448e09e..cdf688b857 100644 --- a/src/nvim/testdir/test_method.vim +++ b/src/nvim/testdir/test_method.vim @@ -1,5 +1,7 @@ " Tests for ->method() +source check.vim + func Test_list_method() let l = [1, 2, 3] call assert_equal([1, 2, 3, 4], [1, 2, 3]->add(4)) @@ -118,6 +120,7 @@ func Test_method_funcref() endfunc func Test_method_float() + CheckFeature float eval 1.234->string()->assert_equal('1.234') eval -1.234->string()->assert_equal('-1.234') endfunc diff --git a/src/nvim/testdir/test_popup.vim b/src/nvim/testdir/test_popup.vim index 710450293c..eb367cfe5c 100644 --- a/src/nvim/testdir/test_popup.vim +++ b/src/nvim/testdir/test_popup.vim @@ -950,6 +950,10 @@ func Test_popup_complete_info_01() \ ["\<C-X>", 'ctrl_x'], \ ["\<C-X>\<C-N>", 'keyword'], \ ["\<C-X>\<C-P>", 'keyword'], + \ ["\<C-X>\<C-E>", 'scroll'], + \ ["\<C-X>\<C-Y>", 'scroll'], + \ ["\<C-X>\<C-E>\<C-E>\<C-Y>", 'scroll'], + \ ["\<C-X>\<C-Y>\<C-E>\<C-Y>", 'scroll'], \ ["\<C-X>\<C-L>", 'whole_line'], \ ["\<C-X>\<C-F>", 'files'], \ ["\<C-X>\<C-]>", 'tags'], diff --git a/src/nvim/tui/tui.c b/src/nvim/tui/tui.c index 803ff23cea..612eaf6667 100644 --- a/src/nvim/tui/tui.c +++ b/src/nvim/tui/tui.c @@ -1019,22 +1019,8 @@ static void tui_mouse_on(UI *ui) { TUIData *data = ui->data; if (!data->mouse_enabled) { -#ifdef WIN32 - // Windows versions with vtp(ENABLE_VIRTUAL_TERMINAL_PROCESSING) and - // no vti(ENABLE_VIRTUAL_TERMINAL_INPUT) will need to use mouse tracking of - // libuv. For this reason, vtp (vterm) state of libuv is temporarily - // disabled because the control sequence needs to be processed by libuv - // instead of Windows vtp. - // ref. https://docs.microsoft.com/en-us/windows/console/setconsolemode - flush_buf(ui); - os_set_vtp(false); -#endif unibi_out_ext(ui, data->unibi_ext.enable_mouse); data->mouse_enabled = true; -#ifdef WIN32 - flush_buf(ui); - os_set_vtp(true); -#endif } } @@ -1042,22 +1028,8 @@ static void tui_mouse_off(UI *ui) { TUIData *data = ui->data; if (data->mouse_enabled) { -#ifdef WIN32 - // Windows versions with vtp(ENABLE_VIRTUAL_TERMINAL_PROCESSING) and - // no vti(ENABLE_VIRTUAL_TERMINAL_INPUT) will need to use mouse tracking of - // libuv. For this reason, vtp (vterm) state of libuv is temporarily - // disabled because the control sequence needs to be processed by libuv - // instead of Windows vtp. - // ref. https://docs.microsoft.com/en-us/windows/console/setconsolemode - flush_buf(ui); - os_set_vtp(false); -#endif unibi_out_ext(ui, data->unibi_ext.disable_mouse); data->mouse_enabled = false; -#ifdef WIN32 - flush_buf(ui); - os_set_vtp(true); -#endif } } diff --git a/src/nvim/ugrid.c b/src/nvim/ugrid.c index 9e4aaff878..ef84cdf334 100644 --- a/src/nvim/ugrid.c +++ b/src/nvim/ugrid.c @@ -2,14 +2,14 @@ // it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com #include <assert.h> +#include <limits.h> #include <stdbool.h> #include <stdio.h> -#include <limits.h> #include "nvim/assert.h" -#include "nvim/vim.h" -#include "nvim/ui.h" #include "nvim/ugrid.h" +#include "nvim/ui.h" +#include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ugrid.c.generated.h" @@ -79,8 +79,7 @@ void ugrid_scroll(UGrid *grid, int top, int bot, int left, int right, int count) } } -static void clear_region(UGrid *grid, int top, int bot, int left, int right, - sattr_T attr) +static void clear_region(UGrid *grid, int top, int bot, int left, int right, sattr_T attr) { for (int row = top; row <= bot; row++) { UGRID_FOREACH_CELL(grid, row, left, right+1, { diff --git a/src/nvim/ui.c b/src/nvim/ui.c index 09709d0f43..aad72af025 100644 --- a/src/nvim/ui.c +++ b/src/nvim/ui.c @@ -3,40 +3,40 @@ #include <assert.h> #include <inttypes.h> +#include <limits.h> #include <stdbool.h> #include <string.h> -#include <limits.h> -#include "nvim/vim.h" -#include "nvim/log.h" +#include "nvim/ascii.h" #include "nvim/aucmd.h" -#include "nvim/ui.h" #include "nvim/charset.h" #include "nvim/cursor.h" +#include "nvim/cursor_shape.h" #include "nvim/diff.h" +#include "nvim/event/loop.h" #include "nvim/ex_cmds2.h" #include "nvim/ex_getln.h" #include "nvim/fold.h" +#include "nvim/garray.h" +#include "nvim/highlight.h" +#include "nvim/log.h" #include "nvim/main.h" -#include "nvim/ascii.h" -#include "nvim/misc1.h" #include "nvim/mbyte.h" -#include "nvim/garray.h" #include "nvim/memory.h" +#include "nvim/misc1.h" #include "nvim/move.h" #include "nvim/normal.h" #include "nvim/option.h" -#include "nvim/os_unix.h" -#include "nvim/event/loop.h" -#include "nvim/os/time.h" #include "nvim/os/input.h" #include "nvim/os/signal.h" +#include "nvim/os/time.h" +#include "nvim/os_unix.h" #include "nvim/popupmnu.h" #include "nvim/screen.h" -#include "nvim/highlight.h" +#include "nvim/ui.h" #include "nvim/ui_compositor.h" +#include "nvim/vim.h" #include "nvim/window.h" -#include "nvim/cursor_shape.h" #ifdef FEAT_TUI # include "nvim/tui/tui.h" #else @@ -70,9 +70,9 @@ static int pending_has_mouse = -1; static size_t uilog_seen = 0; static char uilog_last_event[1024] = { 0 }; -#ifndef EXITFREE -#define entered_free_all_mem false -#endif +# ifndef EXITFREE +# define entered_free_all_mem false +# endif # define UI_LOG(funname) \ do { \ @@ -95,7 +95,7 @@ static char uilog_last_event[1024] = { 0 }; // UI_CALL invokes a function on all registered UI instances. // This is called by code generated by generators/gen_api_ui_events.lua // C code should use ui_call_{funname} instead. -# define UI_CALL(cond, funname, ...) \ +#define UI_CALL(cond, funname, ...) \ do { \ bool any_call = false; \ for (size_t i = 0; i < ui_count; i++) { \ @@ -115,7 +115,7 @@ static char uilog_last_event[1024] = { 0 }; #endif #ifndef EXITFREE -#undef entered_free_all_mem +# undef entered_free_all_mem #endif void ui_init(void) @@ -382,8 +382,8 @@ void ui_set_ext_option(UI *ui, UIExtension ext, bool active) } } -void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, - int clearattr, bool wrap) +void ui_line(ScreenGrid *grid, int row, int startcol, int endcol, int clearcol, int clearattr, + bool wrap) { assert(0 <= row && row < grid->Rows); LineFlags flags = wrap ? kLineFlagWrap : 0; @@ -515,23 +515,23 @@ void ui_check_mouse(void) // normal editing mode (not at hit-return message). for (char_u *p = p_mouse; *p; p++) { switch (*p) { - case 'a': - if (vim_strchr((char_u *)MOUSE_A, checkfor) != NULL) { - has_mouse = true; - return; - } - break; - case MOUSE_HELP: - if (checkfor != MOUSE_RETURN && curbuf->b_help) { - has_mouse = true; - return; - } - break; - default: - if (checkfor == *p) { - has_mouse = true; - return; - } + case 'a': + if (vim_strchr((char_u *)MOUSE_A, checkfor) != NULL) { + has_mouse = true; + return; + } + break; + case MOUSE_HELP: + if (checkfor != MOUSE_RETURN && curbuf->b_help) { + has_mouse = true; + return; + } + break; + default: + if (checkfor == *p) { + has_mouse = true; + return; + } } } } diff --git a/src/nvim/ui_bridge.c b/src/nvim/ui_bridge.c index bc64414ecf..3402df817a 100644 --- a/src/nvim/ui_bridge.c +++ b/src/nvim/ui_bridge.c @@ -5,18 +5,18 @@ // Used by the built-in TUI and libnvim-based UIs. #include <assert.h> +#include <limits.h> #include <stdbool.h> #include <stdio.h> -#include <limits.h> +#include "nvim/api/private/helpers.h" #include "nvim/log.h" #include "nvim/main.h" -#include "nvim/vim.h" -#include "nvim/ui.h" #include "nvim/memory.h" -#include "nvim/ui_bridge.h" #include "nvim/ugrid.h" -#include "nvim/api/private/helpers.h" +#include "nvim/ui.h" +#include "nvim/ui_bridge.h" +#include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ui_bridge.c.generated.h" @@ -26,8 +26,7 @@ // Schedule a function call on the UI bridge thread. #define UI_BRIDGE_CALL(ui, name, argc, ...) \ - ((UIBridgeData *)ui)->scheduler( \ - event_create(ui_bridge_##name##_event, argc, __VA_ARGS__), UI(ui)) + ((UIBridgeData *)ui)->scheduler(event_create(ui_bridge_##name##_event, argc, __VA_ARGS__), UI(ui)) #define INT2PTR(i) ((void *)(intptr_t)i) #define PTR2INT(p) ((Integer)(intptr_t)p) @@ -138,8 +137,8 @@ static void ui_bridge_stop_event(void **argv) ui->stop(ui); } -static void ui_bridge_hl_attr_define(UI *ui, Integer id, HlAttrs attrs, - HlAttrs cterm_attrs, Array info) +static void ui_bridge_hl_attr_define(UI *ui, Integer id, HlAttrs attrs, HlAttrs cterm_attrs, + Array info) { HlAttrs *a = xmalloc(sizeof(HlAttrs)); *a = attrs; @@ -163,11 +162,9 @@ static void ui_bridge_raw_line_event(void **argv) xfree(argv[8]); xfree(argv[9]); } -static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row, - Integer startcol, Integer endcol, - Integer clearcol, Integer clearattr, - LineFlags flags, const schar_T *chunk, - const sattr_T *attrs) +static void ui_bridge_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol, + Integer clearcol, Integer clearattr, LineFlags flags, + const schar_T *chunk, const sattr_T *attrs) { size_t ncol = (size_t)(endcol-startcol); schar_T *c = xmemdup(chunk, ncol * sizeof(schar_T)); diff --git a/src/nvim/ui_compositor.c b/src/nvim/ui_compositor.c index 9c9aec1cf5..7a0f68cfeb 100644 --- a/src/nvim/ui_compositor.c +++ b/src/nvim/ui_compositor.c @@ -7,27 +7,27 @@ // Layer-based compositing: https://en.wikipedia.org/wiki/Digital_compositing #include <assert.h> +#include <limits.h> #include <stdbool.h> #include <stdio.h> -#include <limits.h> +#include "nvim/api/private/helpers.h" +#include "nvim/ascii.h" +#include "nvim/highlight.h" #include "nvim/lib/kvec.h" #include "nvim/log.h" +#include "nvim/lua/executor.h" #include "nvim/main.h" -#include "nvim/ascii.h" -#include "nvim/vim.h" -#include "nvim/ui.h" -#include "nvim/highlight.h" #include "nvim/memory.h" #include "nvim/message.h" +#include "nvim/os/os.h" #include "nvim/popupmnu.h" -#include "nvim/ui_compositor.h" -#include "nvim/ugrid.h" #include "nvim/screen.h" #include "nvim/syntax.h" -#include "nvim/api/private/helpers.h" -#include "nvim/lua/executor.h" -#include "nvim/os/os.h" +#include "nvim/ugrid.h" +#include "nvim/ui.h" +#include "nvim/ui_compositor.h" +#include "nvim/vim.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "ui_compositor.c.generated.h" @@ -123,8 +123,8 @@ bool ui_comp_should_draw(void) /// TODO(bfredl): later on the compositor should just use win_float_pos events, /// though that will require slight event order adjustment: emit the win_pos /// events in the beginning of update_screen(0), rather than in ui_flush() -bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width, - bool valid, bool on_top) +bool ui_comp_put_grid(ScreenGrid *grid, int row, int col, int height, int width, bool valid, + bool on_top) { bool moved; @@ -257,8 +257,7 @@ static void ui_comp_raise_grid(ScreenGrid *grid, size_t new_index) } } -static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle, - Integer r, Integer c) +static void ui_comp_grid_cursor_goto(UI *ui, Integer grid_handle, Integer r, Integer c) { if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid_handle)) { return; @@ -304,8 +303,7 @@ ScreenGrid *ui_comp_mouse_focus(int row, int col) /// Baseline implementation. This is always correct, but we can sometimes /// do something more efficient (where efficiency means smaller deltas to /// the downstream UI.) -static void compose_line(Integer row, Integer startcol, Integer endcol, - LineFlags flags) +static void compose_line(Integer row, Integer startcol, Integer endcol, LineFlags flags) { // If rightleft is set, startcol may be -1. In such cases, the assertions // will fail because no overlap is found. Adjust startcol to prevent it. @@ -447,8 +445,8 @@ static void compose_line(Integer row, Integer startcol, Integer endcol, (const sattr_T *)attrbuf+skipstart); } -static void compose_debug(Integer startrow, Integer endrow, Integer startcol, - Integer endcol, int syn_id, bool delay) +static void compose_debug(Integer startrow, Integer endrow, Integer startcol, Integer endcol, + int syn_id, bool delay) { if (!(rdb_flags & RDB_COMPOSITOR)) { return; @@ -479,8 +477,7 @@ static void debug_delay(Integer lines) } -static void compose_area(Integer startrow, Integer endrow, - Integer startcol, Integer endcol) +static void compose_area(Integer startrow, Integer endrow, Integer startcol, Integer endcol) { compose_debug(startrow, endrow, startcol, endcol, dbghl_recompose, true); endrow = MIN(endrow, default_grid.Rows); @@ -505,11 +502,9 @@ void ui_comp_compose_grid(ScreenGrid *grid) } } -static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, - Integer startcol, Integer endcol, - Integer clearcol, Integer clearattr, - LineFlags flags, const schar_T *chunk, - const sattr_T *attrs) +static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, Integer startcol, Integer endcol, + Integer clearcol, Integer clearattr, LineFlags flags, + const schar_T *chunk, const sattr_T *attrs) { if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) { return; @@ -529,11 +524,11 @@ static void ui_comp_raw_line(UI *ui, Integer grid, Integer row, // when resizing nvim, a window will be attempted to be drawn on the older // and possibly larger global screen size. if (row >= default_grid.Rows) { - DLOG("compositor: invalid row %"PRId64" on grid %"PRId64, row, grid); + DLOG("compositor: invalid row %" PRId64 " on grid %" PRId64, row, grid); return; } if (clearcol > default_grid.Columns) { - DLOG("compositor: invalid last column %"PRId64" on grid %"PRId64, + DLOG("compositor: invalid last column %" PRId64 " on grid %" PRId64, clearcol, grid); if (startcol >= default_grid.Columns) { return; @@ -572,8 +567,8 @@ void ui_comp_set_screen_valid(bool valid) } } -static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row, - Boolean scrolled, String sep_char) +static void ui_comp_msg_set_pos(UI *ui, Integer grid, Integer row, Boolean scrolled, + String sep_char) { msg_grid.comp_row = (int)row; if (scrolled && row > 0) { @@ -617,9 +612,8 @@ static bool curgrid_covered_above(int row) return kv_size(layers)-(above_msg?1:0) > curgrid->comp_index+1; } -static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top, - Integer bot, Integer left, Integer right, - Integer rows, Integer cols) +static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top, Integer bot, Integer left, + Integer right, Integer rows, Integer cols) { if (!ui_comp_should_draw() || !ui_comp_set_grid((int)grid)) { return; @@ -653,8 +647,7 @@ static void ui_comp_grid_scroll(UI *ui, Integer grid, Integer top, } } -static void ui_comp_grid_resize(UI *ui, Integer grid, - Integer width, Integer height) +static void ui_comp_grid_resize(UI *ui, Integer grid, Integer width, Integer height) { if (grid == 1) { ui_composed_call_grid_resize(1, width, height); diff --git a/src/nvim/undo.c b/src/nvim/undo.c index fb96d7e6ff..500845ec72 100644 --- a/src/nvim/undo.c +++ b/src/nvim/undo.c @@ -71,52 +71,51 @@ /* Uncomment the next line for including the u_check() function. This warns * for errors in the debug information. */ -/* #define U_DEBUG 1 */ -#define UH_MAGIC 0x18dade /* value for uh_magic when in use */ -#define UE_MAGIC 0xabc123 /* value for ue_magic when in use */ +// #define U_DEBUG 1 +#define UH_MAGIC 0x18dade // value for uh_magic when in use +#define UE_MAGIC 0xabc123 // value for ue_magic when in use #include <assert.h> +#include <fcntl.h> #include <inttypes.h> #include <limits.h> #include <stdbool.h> #include <string.h> -#include <fcntl.h> #include "auto/config.h" - -#include "nvim/buffer.h" #include "nvim/ascii.h" +#include "nvim/buffer.h" +#include "nvim/buffer_updates.h" #include "nvim/change.h" -#include "nvim/undo.h" #include "nvim/cursor.h" #include "nvim/edit.h" +#include "nvim/extmark.h" #include "nvim/fileio.h" #include "nvim/fold.h" -#include "nvim/buffer_updates.h" -#include "nvim/pos.h" // MAXLNUM +#include "nvim/garray.h" +#include "nvim/lib/kvec.h" #include "nvim/mark.h" -#include "nvim/extmark.h" #include "nvim/memline.h" +#include "nvim/memory.h" #include "nvim/message.h" #include "nvim/misc1.h" -#include "nvim/memory.h" -#include "nvim/garray.h" #include "nvim/option.h" +#include "nvim/os/os.h" +#include "nvim/os/time.h" #include "nvim/os_unix.h" #include "nvim/path.h" +#include "nvim/pos.h" // MAXLNUM #include "nvim/sha256.h" #include "nvim/state.h" #include "nvim/strings.h" #include "nvim/types.h" -#include "nvim/os/os.h" -#include "nvim/os/time.h" -#include "nvim/lib/kvec.h" +#include "nvim/undo.h" #ifdef INCLUDE_GENERATED_DECLARATIONS # include "undo.c.generated.h" #endif -/* used in undo_end() to report number of added and deleted lines */ +// used in undo_end() to report number of added and deleted lines static long u_newcount, u_oldcount; /* @@ -136,13 +135,12 @@ static int seen_b_u_curhead; static int seen_b_u_newhead; static int header_count; -static void u_check_tree(u_header_T *uhp, - u_header_T *exp_uh_next, - u_header_T *exp_uh_alt_prev) { +static void u_check_tree(u_header_T *uhp, u_header_T *exp_uh_next, u_header_T *exp_uh_alt_prev) { u_entry_T *uep; - if (uhp == NULL) + if (uhp == NULL) { return; + } ++header_count; if (uhp == curbuf->b_u_curhead && ++seen_b_u_curhead > 1) { EMSG("b_u_curhead found twice (looping?)"); @@ -153,22 +151,22 @@ static void u_check_tree(u_header_T *uhp, return; } - if (uhp->uh_magic != UH_MAGIC) + if (uhp->uh_magic != UH_MAGIC) { EMSG("uh_magic wrong (may be using freed memory)"); - else { - /* Check pointers back are correct. */ + } else { + // Check pointers back are correct. if (uhp->uh_next.ptr != exp_uh_next) { EMSG("uh_next wrong"); smsg("expected: 0x%x, actual: 0x%x", - exp_uh_next, uhp->uh_next.ptr); + exp_uh_next, uhp->uh_next.ptr); } if (uhp->uh_alt_prev.ptr != exp_uh_alt_prev) { EMSG("uh_alt_prev wrong"); smsg("expected: 0x%x, actual: 0x%x", - exp_uh_alt_prev, uhp->uh_alt_prev.ptr); + exp_uh_alt_prev, uhp->uh_alt_prev.ptr); } - /* Check the undo tree at this header. */ + // Check the undo tree at this header. for (uep = uhp->uh_entry; uep != NULL; uep = uep->ue_next) { if (uep->ue_magic != UE_MAGIC) { EMSG("ue_magic wrong (may be using freed memory)"); @@ -176,10 +174,10 @@ static void u_check_tree(u_header_T *uhp, } } - /* Check the next alt tree. */ + // Check the next alt tree. u_check_tree(uhp->uh_alt_next.ptr, uhp->uh_next.ptr, uhp); - /* Check the next header in this branch. */ + // Check the next header in this branch. u_check_tree(uhp->uh_prev.ptr, uhp, NULL); } } @@ -192,14 +190,16 @@ static void u_check(int newhead_may_be_NULL) { u_check_tree(curbuf->b_u_oldhead, NULL, NULL); if (seen_b_u_newhead == 0 && curbuf->b_u_oldhead != NULL - && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL)) + && !(newhead_may_be_NULL && curbuf->b_u_newhead == NULL)) { EMSGN("b_u_newhead invalid: 0x%x", curbuf->b_u_newhead); - if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0) + } + if (curbuf->b_u_curhead != NULL && seen_b_u_curhead == 0) { EMSGN("b_u_curhead invalid: 0x%x", curbuf->b_u_curhead); + } if (header_count != curbuf->b_u_numhead) { EMSG("b_u_numhead invalid"); smsg("expected: %" PRId64 ", actual: %" PRId64, - (int64_t)header_count, (int64_t)curbuf->b_u_numhead); + (int64_t)header_count, (int64_t)curbuf->b_u_numhead); } } @@ -228,11 +228,12 @@ int u_save_cursor(void) int u_save(linenr_T top, linenr_T bot) { if (top >= bot || bot > (curbuf->b_ml.ml_line_count + 1)) { - return FAIL; /* rely on caller to do error messages */ + return FAIL; // rely on caller to do error messages } - if (top + 2 == bot) + if (top + 2 == bot) { u_saveline((linenr_T)(top + 1)); + } return u_savecommon(curbuf, top, bot, (linenr_T)0, false); } @@ -268,9 +269,8 @@ int u_inssub(linenr_T lnum) */ int u_savedel(linenr_T lnum, long nlines) { - return u_savecommon( - curbuf, lnum - 1, lnum + nlines, - nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, false); + return u_savecommon(curbuf, lnum - 1, lnum + nlines, + nlines == curbuf->b_ml.ml_line_count ? 2 : lnum, false); } /// Return true when undo is allowed. Otherwise print an error message and @@ -327,16 +327,14 @@ static inline void zero_fmark_additional_data(fmark_T *fmarks) * Careful: may trigger autocommands that reload the buffer. * Returns FAIL when lines could not be saved, OK otherwise. */ -int u_savecommon(buf_T *buf, - linenr_T top, linenr_T bot, - linenr_T newbot, int reload) +int u_savecommon(buf_T *buf, linenr_T top, linenr_T bot, linenr_T newbot, int reload) { linenr_T lnum; long i; - u_header_T *uhp; - u_header_T *old_curhead; - u_entry_T *uep; - u_entry_T *prev_uep; + u_header_T *uhp; + u_header_T *old_curhead; + u_entry_T *uep; + u_entry_T *prev_uep; long size; if (!reload) { @@ -381,8 +379,9 @@ int u_savecommon(buf_T *buf, #ifdef U_DEBUG uhp->uh_magic = UH_MAGIC; #endif - } else + } else { uhp = NULL; + } /* * If we undid more than we redid, move the entry lists before and @@ -399,7 +398,7 @@ int u_savecommon(buf_T *buf, */ while (buf->b_u_numhead > get_undolevel(buf) && buf->b_u_oldhead != NULL) { - u_header_T *uhfree = buf->b_u_oldhead; + u_header_T *uhfree = buf->b_u_oldhead; if (uhfree == old_curhead) { // Can't reconnect the branch, delete all of it. @@ -459,11 +458,12 @@ int u_savecommon(buf_T *buf, uhp->uh_walk = 0; 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) + uhp->uh_cursor = curwin->w_cursor; // save cursor pos. for undo + if (virtual_active() && curwin->w_cursor.coladd > 0) { uhp->uh_cursor_vcol = getviscol(); - else + } else { uhp->uh_cursor_vcol = -1; + } // save changed and buffer empty flag for undo uhp->uh_flags = (buf->b_changed ? UH_CHANGED : 0) + @@ -499,8 +499,9 @@ int u_savecommon(buf_T *buf, uep = u_get_headentry(buf); prev_uep = NULL; for (i = 0; i < 10; ++i) { - if (uep == NULL) + if (uep == NULL) { break; + } /* If lines have been inserted/deleted we give up. * Also when the line was included in a multi-line save. */ @@ -509,14 +510,14 @@ int u_savecommon(buf_T *buf, != (uep->ue_bot == 0 ? buf->b_ml.ml_line_count + 1 : uep->ue_bot)) - : uep->ue_lcount != buf->b_ml.ml_line_count) + : uep->ue_lcount != buf->b_ml.ml_line_count) || (uep->ue_size > 1 && top >= uep->ue_top && top + 2 <= uep->ue_top + uep->ue_size + 1)) { break; } - /* If it's the same line we can skip saving it again. */ + // If it's the same line we can skip saving it again. if (uep->ue_size == 1 && uep->ue_top == top) { if (i > 0) { /* It's not the last entry: get ue_bot for the last @@ -609,25 +610,25 @@ int u_savecommon(buf_T *buf, // magic at start of undofile -# define UF_START_MAGIC "Vim\237UnDo\345" -# define UF_START_MAGIC_LEN 9 +#define UF_START_MAGIC "Vim\237UnDo\345" +#define UF_START_MAGIC_LEN 9 // magic at start of header -# define UF_HEADER_MAGIC 0x5fd0 +#define UF_HEADER_MAGIC 0x5fd0 // magic after last header -# define UF_HEADER_END_MAGIC 0xe7aa +#define UF_HEADER_END_MAGIC 0xe7aa // magic at start of entry -# define UF_ENTRY_MAGIC 0xf518 +#define UF_ENTRY_MAGIC 0xf518 // magic after last entry -# define UF_ENTRY_END_MAGIC 0x3581 +#define UF_ENTRY_END_MAGIC 0x3581 // 2-byte undofile version number -# define UF_VERSION 3 +#define UF_VERSION 3 -/* extra fields for header */ -# define UF_LAST_SAVE_NR 1 +// extra fields for header +#define UF_LAST_SAVE_NR 1 -/* extra fields for uhp */ -# define UHP_SAVE_NR 1 +// extra fields for uhp +#define UHP_SAVE_NR 1 static char_u e_not_open[] = N_("E828: Cannot open undo file for writing: %s"); @@ -640,7 +641,7 @@ void u_compute_hash(buf_T *buf, char_u *hash) { context_sha256_T ctx; linenr_T lnum; - char_u *p; + char_u *p; sha256_start(&ctx); for (lnum = 1; lnum <= buf->b_ml.ml_line_count; lnum++) { @@ -688,7 +689,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) // Loop over 'undodir'. When reading find the first file that exists. // When not reading use the first directory that exists or ".". - dirp = (char *) p_udir; + dirp = (char *)p_udir; while (*dirp != NUL) { size_t dir_len = copy_option_part((char_u **)&dirp, (char_u *)dir_name, MAXPATHL, ","); @@ -698,7 +699,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) const size_t ffname_len = strlen(ffname); undo_file_name = xmalloc(ffname_len + 6); memmove(undo_file_name, ffname, ffname_len + 1); - char *const tail = (char *) path_tail((char_u *) undo_file_name); + char *const tail = (char *)path_tail((char_u *)undo_file_name); const size_t tail_len = strlen(tail); memmove(tail + 1, tail, tail_len + 1); *tail = '.'; @@ -754,8 +755,7 @@ char *u_get_undo_file_name(const char *const buf_ffname, const bool reading) /// /// @param[in] mesg Identifier of the corruption kind. /// @param[in] file_name File in which error occurred. -static void corruption_error(const char *const mesg, - const char *const file_name) +static void corruption_error(const char *const mesg, const char *const file_name) FUNC_ATTR_NONNULL_ALL { EMSG3(_("E825: Corrupted undo file (%s): %s"), mesg, file_name); @@ -763,8 +763,8 @@ static void corruption_error(const char *const mesg, static void u_free_uhp(u_header_T *uhp) { - u_entry_T *nuep; - u_entry_T *uep; + u_entry_T *nuep; + u_entry_T *uep; uep = uhp->uh_entry; while (uep != NULL) { @@ -890,8 +890,7 @@ static bool serialize_uhp(bufinfo_T *bi, u_header_T *uhp) return true; } -static u_header_T *unserialize_uhp(bufinfo_T *bi, - const char *file_name) +static u_header_T *unserialize_uhp(bufinfo_T *bi, const char *file_name) { u_header_T *uhp = xmalloc(sizeof(u_header_T)); memset(uhp, 0, sizeof(u_header_T)); @@ -999,7 +998,7 @@ static bool serialize_extmark(bufinfo_T *bi, ExtmarkUndoObject extup) undo_write_bytes(bi, (uintmax_t)extup.type, 4); if (!undo_write(bi, (uint8_t *)&(extup.data.splice), sizeof(ExtmarkSplice))) { - return false; + return false; } } else if (extup.type == kExtmarkMove) { undo_write_bytes(bi, (uintmax_t)UF_ENTRY_MAGIC, 2); @@ -1013,8 +1012,7 @@ static bool serialize_extmark(bufinfo_T *bi, ExtmarkUndoObject extup) return true; } -static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error, - const char *filename) +static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error, const char *filename) { UndoObjectType type; uint8_t *buf = NULL; @@ -1039,7 +1037,7 @@ static ExtmarkUndoObject *unserialize_extmark(bufinfo_T *bi, bool *error, } extup->data.move = *(ExtmarkMove *)buf; } else { - goto error; + goto error; } xfree(buf); @@ -1080,8 +1078,7 @@ static bool serialize_uep(bufinfo_T *bi, u_entry_T *uep) return true; } -static u_entry_T *unserialize_uep(bufinfo_T * bi, bool *error, - const char *file_name) +static u_entry_T *unserialize_uep(bufinfo_T * bi, bool *error, const char *file_name) { u_entry_T *uep = xmalloc(sizeof(u_entry_T)); memset(uep, 0, sizeof(u_entry_T)); @@ -1171,24 +1168,23 @@ static void unserialize_visualinfo(bufinfo_T *bi, visualinfo_T *info) /// @param[in] buf Buffer for which undo file is written. /// @param[in] hash Hash value of the buffer text. Must have #UNDO_HASH_SIZE /// size. -void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, - char_u *const hash) +void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, char_u *const hash) FUNC_ATTR_NONNULL_ARG(3, 4) { - u_header_T *uhp; + u_header_T *uhp; char *file_name; int mark; #ifdef U_DEBUG int headers_written = 0; #endif int fd; - FILE *fp = NULL; + FILE *fp = NULL; int perm; bool write_ok = false; bufinfo_T bi; if (name == NULL) { - file_name = u_get_undo_file_name((char *) buf->b_ffname, false); + file_name = u_get_undo_file_name((char *)buf->b_ffname, false); if (file_name == NULL) { if (p_verbose > 0) { verbose_enter(); @@ -1198,7 +1194,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, return; } } else { - file_name = (char *) name; + file_name = (char *)name; } /* @@ -1221,16 +1217,18 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, * file, and delete it. */ if (os_path_exists((char_u *)file_name)) { if (name == NULL || !forceit) { - /* Check we can read it and it's an undo file. */ + // Check we can read it and it's an undo file. fd = os_open(file_name, O_RDONLY, 0); if (fd < 0) { if (name != NULL || p_verbose > 0) { - if (name == NULL) + if (name == NULL) { verbose_enter(); + } smsg(_("Will not overwrite with undo file, cannot read: %s"), file_name); - if (name == NULL) + if (name == NULL) { verbose_leave(); + } } goto theend; } else { @@ -1240,12 +1238,14 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, if (len < UF_START_MAGIC_LEN || memcmp(mbuf, UF_START_MAGIC, UF_START_MAGIC_LEN) != 0) { if (name != NULL || p_verbose > 0) { - if (name == NULL) + if (name == NULL) { verbose_enter(); + } smsg(_("Will not overwrite, this is not an undo file: %s"), file_name); - if (name == NULL) + if (name == NULL) { verbose_leave(); + } } goto theend; } @@ -1276,7 +1276,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, } #ifdef U_DEBUG - /* Check there is no problem in undo info before writing. */ + // Check there is no problem in undo info before writing. u_check(FALSE); #endif @@ -1323,7 +1323,7 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, mark = ++lastmark; uhp = buf->b_u_oldhead; while (uhp != NULL) { - /* Serialize current UHP if we haven't seen it */ + // Serialize current UHP if we haven't seen it if (uhp->uh_walk != mark) { uhp->uh_walk = mark; #ifdef U_DEBUG @@ -1334,19 +1334,20 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, } } - /* Now walk through the tree - algorithm from undo_time(). */ - if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != mark) + // Now walk through the tree - algorithm from undo_time(). + if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != mark) { uhp = uhp->uh_prev.ptr; - else if (uhp->uh_alt_next.ptr != NULL - && uhp->uh_alt_next.ptr->uh_walk != mark) + } else if (uhp->uh_alt_next.ptr != NULL + && uhp->uh_alt_next.ptr->uh_walk != mark) { uhp = uhp->uh_alt_next.ptr; - else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL - && uhp->uh_next.ptr->uh_walk != mark) + } else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL + && uhp->uh_next.ptr->uh_walk != mark) { uhp = uhp->uh_next.ptr; - else if (uhp->uh_alt_prev.ptr != NULL) + } else if (uhp->uh_alt_prev.ptr != NULL) { uhp = uhp->uh_alt_prev.ptr; - else + } else { uhp = uhp->uh_next.ptr; + } } if (undo_write_bytes(&bi, (uintmax_t)UF_HEADER_END_MAGIC, 2)) { @@ -1361,14 +1362,15 @@ void u_write_undo(const char *const name, const bool forceit, buf_T *const buf, write_error: fclose(fp); - if (!write_ok) + if (!write_ok) { EMSG2(_("E829: write error in undo file: %s"), file_name); + } #ifdef HAVE_ACL if (buf->b_ffname != NULL) { vim_acl_T acl; - /* For systems that support ACL: get the ACL from the original file. */ + // For systems that support ACL: get the ACL from the original file. acl = mch_get_acl(buf->b_ffname); mch_set_acl((char_u *)file_name, acl); mch_free_acl(acl); @@ -1376,8 +1378,9 @@ write_error: #endif theend: - if (file_name != name) + if (file_name != name) { xfree(file_name); + } } /// Loads the undo tree from an undo file. @@ -1385,8 +1388,7 @@ theend: /// a bit more verbose. /// Otherwise use curbuf->b_ffname to generate the undo file name. /// "hash[UNDO_HASH_SIZE]" must be the hash value of the buffer text. -void u_read_undo(char *name, const char_u *hash, - const char_u *orig_name FUNC_ATTR_UNUSED) +void u_read_undo(char *name, const char_u *hash, const char_u *orig_name FUNC_ATTR_UNUSED) FUNC_ATTR_NONNULL_ARG(2) { u_header_T **uhp_table = NULL; @@ -1394,7 +1396,7 @@ void u_read_undo(char *name, const char_u *hash, char *file_name; if (name == NULL) { - file_name = u_get_undo_file_name((char *) curbuf->b_ffname, true); + file_name = u_get_undo_file_name((char *)curbuf->b_ffname, true); if (file_name == NULL) { return; } @@ -1405,7 +1407,7 @@ void u_read_undo(char *name, const char_u *hash, FileInfo file_info_orig; FileInfo file_info_undo; if (os_fileinfo((const char *)orig_name, &file_info_orig) - && os_fileinfo((char *)file_name, &file_info_undo) + && os_fileinfo(file_name, &file_info_undo) && file_info_orig.stat.st_uid != file_info_undo.stat.st_uid && file_info_undo.stat.st_uid != getuid()) { if (p_verbose > 0) { @@ -1418,7 +1420,7 @@ void u_read_undo(char *name, const char_u *hash, } #endif } else { - file_name = (char *) name; + file_name = name; } if (p_verbose > 0) { @@ -1465,7 +1467,7 @@ void u_read_undo(char *name, const char_u *hash, verbose_enter(); } give_warning((char_u *) - _("File contents changed, cannot use undo info"), true); + _("File contents changed, cannot use undo info"), true); if (name == NULL) { verbose_leave(); } @@ -1508,15 +1510,15 @@ void u_read_undo(char *name, const char_u *hash, } int what = undo_read_byte(&bi); switch (what) { - case UF_LAST_SAVE_NR: - last_save_nr = undo_read_4c(&bi); - break; + case UF_LAST_SAVE_NR: + last_save_nr = undo_read_4c(&bi); + break; - default: - // field not supported, skip - while (--len >= 0) { - (void)undo_read_byte(&bi); - } + default: + // field not supported, skip + while (--len >= 0) { + (void)undo_read_byte(&bi); + } } } @@ -1559,7 +1561,7 @@ void u_read_undo(char *name, const char_u *hash, size_t amount = num_head * sizeof(int) + 1; int *uhp_table_used = xmalloc(amount); memset(uhp_table_used, 0, amount); -# define SET_FLAG(j) ++ uhp_table_used[j] +# define SET_FLAG(j) ++uhp_table_used[j] #else # define SET_FLAG(j) #endif @@ -1666,10 +1668,11 @@ void u_read_undo(char *name, const char_u *hash, error: xfree(line_ptr); if (uhp_table != NULL) { - for (long i = 0; i < num_read_uhps; i++) + for (long i = 0; i < num_read_uhps; i++) { if (uhp_table[i] != NULL) { u_free_uhp(uhp_table[i]); } + } xfree(uhp_table); } @@ -1844,7 +1847,7 @@ bool u_undo_and_forget(int count) to_forget->uh_alt_next.ptr = NULL; curbuf->b_u_curhead->uh_alt_prev.ptr = to_forget->uh_alt_prev.ptr; curbuf->b_u_seq_cur = curbuf->b_u_curhead->uh_next.ptr ? - curbuf->b_u_curhead->uh_next.ptr->uh_seq : 0; + curbuf->b_u_curhead->uh_next.ptr->uh_seq : 0; } else if (curbuf->b_u_newhead) { curbuf->b_u_seq_cur = curbuf->b_u_newhead->uh_seq; } @@ -1876,8 +1879,9 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event) u_newcount = 0; u_oldcount = 0; - if (curbuf->b_ml.ml_flags & ML_EMPTY) + if (curbuf->b_ml.ml_flags & ML_EMPTY) { u_oldcount = -1; + } while (count--) { /* Do the change warning now, so that it triggers FileChangedRO when * needed. This may cause the file to be reloaded, that must happen @@ -1894,7 +1898,7 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event) } // nothing to undo if (curbuf->b_u_numhead == 0 || curbuf->b_u_curhead == NULL) { - /* stick curbuf->b_u_curhead at end */ + // stick curbuf->b_u_curhead at end curbuf->b_u_curhead = curbuf->b_u_oldhead; beep_flush(); if (count == startcount - 1) { @@ -1919,8 +1923,9 @@ static void u_doit(int startcount, bool quiet, bool do_buf_event) /* Advance for next redo. Set "newhead" when at the end of the * redoable changes. */ - if (curbuf->b_u_curhead->uh_prev.ptr == NULL) + if (curbuf->b_u_curhead->uh_prev.ptr == NULL) { curbuf->b_u_newhead = curbuf->b_u_curhead; + } curbuf->b_u_curhead = curbuf->b_u_curhead->uh_prev.ptr; } } @@ -1941,8 +1946,8 @@ void undo_time(long step, bool sec, bool file, bool absolute) long closest_start; long closest_seq = 0; long val; - u_header_T *uhp = NULL; - u_header_T *last; + u_header_T *uhp = NULL; + u_header_T *last; int mark; int nomark = 0; // shut up compiler int round; @@ -1958,8 +1963,9 @@ void undo_time(long step, bool sec, bool file, bool absolute) u_newcount = 0; u_oldcount = 0; - if (curbuf->b_ml.ml_flags & ML_EMPTY) + if (curbuf->b_ml.ml_flags & ML_EMPTY) { u_oldcount = -1; + } /* "target" is the node below which we want to be. * Init "closest" to a value we can't reach. */ @@ -1975,23 +1981,26 @@ void undo_time(long step, bool sec, bool file, bool absolute) * the last write, count that as moving one file-write, so * that ":earlier 1f" undoes all changes since the last save. */ uhp = curbuf->b_u_curhead; - if (uhp != NULL) + if (uhp != NULL) { uhp = uhp->uh_next.ptr; - else + } else { uhp = curbuf->b_u_newhead; - if (uhp != NULL && uhp->uh_save_nr != 0) + } + if (uhp != NULL && uhp->uh_save_nr != 0) { /* "uh_save_nr" was set in the last block, that means * there were no changes since the last write */ target = curbuf->b_u_save_nr_cur + step; - else - /* count the changes since the last write as one step */ + } else { + // count the changes since the last write as one step target = curbuf->b_u_save_nr_cur + step + 1; - if (target <= 0) + } + if (target <= 0) { /* Go to before first write: before the oldest change. Use * the sequence number for that. */ dofile = false; + } } else { - /* Moving forward to a newer write. */ + // Moving forward to a newer write. target = curbuf->b_u_save_nr_cur + step; if (target > curbuf->b_u_save_nr_last) { /* Go to after last write: after the latest change. Use @@ -2000,11 +2009,13 @@ void undo_time(long step, bool sec, bool file, bool absolute) dofile = false; } } - } else + } else { target = curbuf->b_u_seq_cur + step; + } if (step < 0) { - if (target < 0) + if (target < 0) { target = 0; + } closest = -1; } else { if (dosec) { @@ -2044,10 +2055,11 @@ void undo_time(long step, bool sec, bool file, bool absolute) mark = ++lastmark; nomark = ++lastmark; - if (curbuf->b_u_curhead == NULL) /* at leaf of the tree */ + if (curbuf->b_u_curhead == NULL) { // at leaf of the tree uhp = curbuf->b_u_newhead; - else + } else { uhp = curbuf->b_u_curhead; + } while (uhp != NULL) { uhp->uh_walk = mark; @@ -2065,17 +2077,17 @@ void undo_time(long step, bool sec, bool file, bool absolute) * "b_u_seq_cur"). When the timestamp is equal find the * highest/lowest sequence number. */ if ((step < 0 ? uhp->uh_seq <= curbuf->b_u_seq_cur - : uhp->uh_seq > curbuf->b_u_seq_cur) + : uhp->uh_seq > curbuf->b_u_seq_cur) && ((dosec && val == closest) ? (step < 0 ? uhp->uh_seq < closest_seq - : uhp->uh_seq > closest_seq) - : closest == closest_start + : uhp->uh_seq > closest_seq) + : closest == closest_start || (val > target ? (closest > target ? val - target <= closest - target : val - target <= target - closest) - : (closest > target + : (closest > target ? target - val <= closest - target : target - val <= target - closest)))) { closest = val; @@ -2090,38 +2102,41 @@ void undo_time(long step, bool sec, bool file, bool absolute) break; } - /* go down in the tree if we haven't been there */ + // go down in the tree if we haven't been there if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark - && uhp->uh_prev.ptr->uh_walk != mark) + && uhp->uh_prev.ptr->uh_walk != mark) { uhp = uhp->uh_prev.ptr; - - /* go to alternate branch if we haven't been there */ + } + // go to alternate branch if we haven't been there else if (uhp->uh_alt_next.ptr != NULL && uhp->uh_alt_next.ptr->uh_walk != nomark - && uhp->uh_alt_next.ptr->uh_walk != mark) + && uhp->uh_alt_next.ptr->uh_walk != mark) { uhp = uhp->uh_alt_next.ptr; - + } /* go up in the tree if we haven't been there and we are at the * start of alternate branches */ else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL && uhp->uh_next.ptr->uh_walk != nomark && uhp->uh_next.ptr->uh_walk != mark) { - /* If still at the start we don't go through this change. */ - if (uhp == curbuf->b_u_curhead) + // If still at the start we don't go through this change. + if (uhp == curbuf->b_u_curhead) { uhp->uh_walk = nomark; + } uhp = uhp->uh_next.ptr; } else { - /* need to backtrack; mark this node as useless */ + // need to backtrack; mark this node as useless uhp->uh_walk = nomark; - if (uhp->uh_alt_prev.ptr != NULL) + if (uhp->uh_alt_prev.ptr != NULL) { uhp = uhp->uh_alt_prev.ptr; - else + } else { uhp = uhp->uh_next.ptr; + } } } - if (uhp != NULL) /* found it */ + if (uhp != NULL) { // found it break; + } if (absolute) { EMSGN(_("E830: Undo number %" PRId64 " not found"), step); @@ -2129,10 +2144,11 @@ void undo_time(long step, bool sec, bool file, bool absolute) } if (closest == closest_start) { - if (step < 0) + if (step < 0) { MSG(_("Already at oldest change")); - else + } else { MSG(_("Already at newest change")); + } return; } @@ -2153,10 +2169,11 @@ target_zero: change_warning(curbuf, 0); uhp = curbuf->b_u_curhead; - if (uhp == NULL) + if (uhp == NULL) { uhp = curbuf->b_u_newhead; - else + } else { uhp = uhp->uh_next.ptr; + } if (uhp == NULL || (target > 0 && uhp->uh_walk != mark) || (uhp->uh_seq == target && !above)) { @@ -2264,21 +2281,21 @@ target_zero: /// @param do_buf_event If `true`, send buffer updates. static void u_undoredo(int undo, bool do_buf_event) { - char_u **newarray = NULL; + char_u **newarray = NULL; linenr_T oldsize; linenr_T newsize; linenr_T top, bot; linenr_T lnum; linenr_T newlnum = MAXLNUM; long i; - u_entry_T *uep, *nuep; - u_entry_T *newlist = NULL; + u_entry_T *uep, *nuep; + u_entry_T *newlist = NULL; int old_flags; int new_flags; fmark_T namedm[NMARKS]; visualinfo_T visualinfo; bool empty_buffer; // buffer became empty - u_header_T *curhead = curbuf->b_u_curhead; + u_header_T *curhead = curbuf->b_u_curhead; /* Don't want autocommands using the undo structures here, they are * invalid till the end. */ @@ -2307,8 +2324,9 @@ static void u_undoredo(int undo, bool do_buf_event) for (uep = curhead->uh_entry; uep != NULL; uep = nuep) { top = uep->ue_top; bot = uep->ue_bot; - if (bot == 0) + if (bot == 0) { bot = curbuf->b_ml.ml_line_count + 1; + } if (top > curbuf->b_ml.ml_line_count || top >= bot || bot > curbuf->b_ml.ml_line_count + 1) { unblock_autocmds(); @@ -2317,8 +2335,8 @@ static void u_undoredo(int undo, bool do_buf_event) return; } - oldsize = bot - top - 1; /* number of lines before undo */ - newsize = uep->ue_size; /* number of lines after undo */ + oldsize = bot - top - 1; // number of lines before undo + newsize = uep->ue_size; // number of lines after undo if (top < newlnum) { /* If the saved cursor is somewhere in this undo block, move it to @@ -2332,13 +2350,15 @@ static void u_undoredo(int undo, bool do_buf_event) /* Use the first line that actually changed. Avoids that * undoing auto-formatting puts the cursor in the previous * line. */ - for (i = 0; i < newsize && i < oldsize; ++i) - if (STRCMP(uep->ue_array[i], ml_get(top + 1 + i)) != 0) + for (i = 0; i < newsize && i < oldsize; ++i) { + if (STRCMP(uep->ue_array[i], ml_get(top + 1 + i)) != 0) { break; + } + } if (i == newsize && newlnum == MAXLNUM && uep->ue_next == NULL) { newlnum = top; curwin->w_cursor.lnum = newlnum + 1; - } else if (i < newsize) { + } else if (i < newsize) { newlnum = top + i; curwin->w_cursor.lnum = newlnum + 1; } @@ -2347,12 +2367,12 @@ static void u_undoredo(int undo, bool do_buf_event) empty_buffer = false; - /* delete the lines between top and bot and save them in newarray */ + // delete the lines between top and bot and save them in newarray if (oldsize > 0) { newarray = xmalloc(sizeof(char_u *) * (size_t)oldsize); - /* delete backwards, it goes faster in most cases */ + // delete backwards, it goes faster in most cases for (lnum = bot - 1, i = oldsize; --i >= 0; --lnum) { - /* what can we do when we run out of memory? */ + // what can we do when we run out of memory? newarray[i] = u_save_line(lnum); /* remember we deleted the last line in the buffer, and a * dummy empty line will be inserted */ @@ -2361,10 +2381,11 @@ static void u_undoredo(int undo, bool do_buf_event) } ml_delete(lnum, false); } - } else + } else { newarray = NULL; + } - /* insert the lines in u_array between top and bot */ + // insert the lines in u_array between top and bot if (newsize) { for (lnum = top, i = 0; i < newsize; ++i, ++lnum) { /* @@ -2395,13 +2416,15 @@ static void u_undoredo(int undo, bool do_buf_event) changed_lines(top + 1, 0, bot, newsize - oldsize, do_buf_event); - /* set '[ and '] mark */ - if (top + 1 < curbuf->b_op_start.lnum) + // set '[ and '] mark + if (top + 1 < curbuf->b_op_start.lnum) { curbuf->b_op_start.lnum = top + 1; - if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) + } + if (newsize == 0 && top + 1 > curbuf->b_op_end.lnum) { curbuf->b_op_end.lnum = top + 1; - else if (top + newsize > curbuf->b_op_end.lnum) + } else if (top + newsize > curbuf->b_op_end.lnum) { curbuf->b_op_end.lnum = top + newsize; + } u_newcount += newsize; u_oldcount += oldsize; @@ -2424,7 +2447,7 @@ static void u_undoredo(int undo, bool do_buf_event) undo_info = kv_A(curhead->uh_extmark, i); extmark_apply_undo(undo_info, undo); } - // redo + // redo } else { for (i = 0; i < (int)kv_size(curhead->uh_extmark); i++) { undo_info = kv_A(curhead->uh_extmark, i); @@ -2482,17 +2505,20 @@ static void u_undoredo(int undo, bool do_buf_event) * Otherwise the cursor should go to the first undone line. */ if (curhead->uh_cursor.lnum + 1 == curwin->w_cursor.lnum - && curwin->w_cursor.lnum > 1) + && curwin->w_cursor.lnum > 1) { --curwin->w_cursor.lnum; + } 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) + if (virtual_active() && curhead->uh_cursor_vcol >= 0) { coladvance((colnr_T)curhead->uh_cursor_vcol); - else + } else { curwin->w_cursor.coladd = 0; - } else + } + } else { beginline(BL_SOL | BL_FIX); + } } else { /* We get here with the current cursor line being past the end (eg * after adding lines at the end of the file, and then undoing it). @@ -2502,23 +2528,25 @@ static void u_undoredo(int undo, bool do_buf_event) curwin->w_cursor.coladd = 0; } - /* Make sure the cursor is on an existing line and column. */ + // Make sure the cursor is on an existing line and column. check_cursor(); - /* Remember where we are for "g-" and ":earlier 10s". */ + // Remember where we are for "g-" and ":earlier 10s". curbuf->b_u_seq_cur = curhead->uh_seq; - if (undo) + if (undo) { /* We are below the previous undo. However, to make ":earlier 1s" * work we compute this as being just above the just undone change. */ curbuf->b_u_seq_cur = curhead->uh_next.ptr ? - curhead->uh_next.ptr->uh_seq : 0; + curhead->uh_next.ptr->uh_seq : 0; + } - /* Remember where we are for ":earlier 1f" and ":later 1f". */ + // Remember where we are for ":earlier 1f" and ":later 1f". if (curhead->uh_save_nr != 0) { - if (undo) + if (undo) { curbuf->b_u_save_nr_cur = curhead->uh_save_nr - 1; - else + } else { curbuf->b_u_save_nr_cur = curhead->uh_save_nr; + } } /* The timestamp can be the same for multiple changes, just use the one of @@ -2534,17 +2562,18 @@ static void u_undoredo(int undo, bool do_buf_event) /// If we deleted or added lines, report the number of less/more lines. /// Otherwise, report the number of changes (this may be incorrect /// in some cases, but it's better than nothing). -static void u_undo_end( - bool did_undo, ///< just did an undo - bool absolute, ///< used ":undo N" - bool quiet) +/// +/// @param did_undo just did an undo +/// @param absolute used ":undo N" +static void u_undo_end(bool did_undo, bool absolute, bool quiet) { - char *msgstr; - u_header_T *uhp; + char *msgstr; + u_header_T *uhp; char_u msgbuf[80]; - if ((fdo_flags & FDO_UNDO) && KeyTyped) + if ((fdo_flags & FDO_UNDO) && KeyTyped) { foldOpenCursor(); + } if (quiet || global_busy // no messages until global is finished @@ -2552,28 +2581,30 @@ static void u_undo_end( return; } - if (curbuf->b_ml.ml_flags & ML_EMPTY) + if (curbuf->b_ml.ml_flags & ML_EMPTY) { --u_newcount; + } u_oldcount -= u_newcount; - if (u_oldcount == -1) + if (u_oldcount == -1) { msgstr = N_("more line"); - else if (u_oldcount < 0) + } else if (u_oldcount < 0) { msgstr = N_("more lines"); - else if (u_oldcount == 1) + } else if (u_oldcount == 1) { msgstr = N_("line less"); - else if (u_oldcount > 1) + } else if (u_oldcount > 1) { msgstr = N_("fewer lines"); - else { + } else { u_oldcount = u_newcount; - if (u_newcount == 1) + if (u_newcount == 1) { msgstr = N_("change"); - else + } else { msgstr = N_("changes"); + } } if (curbuf->b_u_curhead != NULL) { - /* For ":undo N" we prefer a "after #N" message. */ + // For ":undo N" we prefer a "after #N" message. if (absolute && curbuf->b_u_curhead->uh_next.ptr != NULL) { uhp = curbuf->b_u_curhead->uh_next.ptr; did_undo = false; @@ -2600,14 +2631,13 @@ static void u_undo_end( } } - smsg_attr_keep( - 0, - _("%" PRId64 " %s; %s #%" PRId64 " %s"), - u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount, - _(msgstr), - did_undo ? _("before") : _("after"), - uhp == NULL ? (int64_t)0L : (int64_t)uhp->uh_seq, - msgbuf); + smsg_attr_keep(0, + _("%" PRId64 " %s; %s #%" PRId64 " %s"), + u_oldcount < 0 ? (int64_t)-u_oldcount : (int64_t)u_oldcount, + _(msgstr), + did_undo ? _("before") : _("after"), + uhp == NULL ? (int64_t)0L : (int64_t)uhp->uh_seq, + msgbuf); } /// u_sync: stop adding to the current entry list @@ -2634,7 +2664,7 @@ void u_sync(bool force) void ex_undolist(exarg_T *eap) { garray_T ga; - u_header_T *uhp; + u_header_T *uhp; int mark; int nomark; int changes = 1; @@ -2657,28 +2687,29 @@ void ex_undolist(exarg_T *eap) add_time(IObuff + STRLEN(IObuff), IOSIZE - STRLEN(IObuff), uhp->uh_time); if (uhp->uh_save_nr > 0) { - while (STRLEN(IObuff) < 33) + while (STRLEN(IObuff) < 33) { STRCAT(IObuff, " "); + } vim_snprintf_add((char *)IObuff, IOSIZE, - " %3ld", uhp->uh_save_nr); + " %3ld", uhp->uh_save_nr); } GA_APPEND(char_u *, &ga, vim_strsave(IObuff)); } uhp->uh_walk = mark; - /* go down in the tree if we haven't been there */ + // go down in the tree if we haven't been there if (uhp->uh_prev.ptr != NULL && uhp->uh_prev.ptr->uh_walk != nomark && uhp->uh_prev.ptr->uh_walk != mark) { uhp = uhp->uh_prev.ptr; ++changes; } - /* go to alternate branch if we haven't been there */ + // go to alternate branch if we haven't been there else if (uhp->uh_alt_next.ptr != NULL && uhp->uh_alt_next.ptr->uh_walk != nomark - && uhp->uh_alt_next.ptr->uh_walk != mark) + && uhp->uh_alt_next.ptr->uh_walk != mark) { uhp = uhp->uh_alt_next.ptr; - + } /* go up in the tree if we haven't been there and we are at the * start of alternate branches */ else if (uhp->uh_next.ptr != NULL && uhp->uh_alt_prev.ptr == NULL @@ -2687,20 +2718,20 @@ void ex_undolist(exarg_T *eap) uhp = uhp->uh_next.ptr; --changes; } else { - /* need to backtrack; mark this node as done */ + // need to backtrack; mark this node as done uhp->uh_walk = nomark; - if (uhp->uh_alt_prev.ptr != NULL) + if (uhp->uh_alt_prev.ptr != NULL) { uhp = uhp->uh_alt_prev.ptr; - else { + } else { uhp = uhp->uh_next.ptr; --changes; } } } - if (GA_EMPTY(&ga)) + if (GA_EMPTY(&ga)) { MSG(_("Nothing to undo")); - else { + } else { sort_strings((char_u **)ga.ga_data, ga.ga_len); msg_start(); @@ -2757,17 +2788,18 @@ void u_unchanged(buf_T *buf) */ void u_find_first_changed(void) { - u_header_T *uhp = curbuf->b_u_newhead; - u_entry_T *uep; + u_header_T *uhp = curbuf->b_u_newhead; + u_entry_T *uep; linenr_T lnum; - if (curbuf->b_u_curhead != NULL || uhp == NULL) - return; /* undid something in an autocmd? */ - - /* Check that the last undo block was for the whole file. */ + if (curbuf->b_u_curhead != NULL || uhp == NULL) { + return; // undid something in an autocmd? + } + // Check that the last undo block was for the whole file. uep = uhp->uh_entry; - if (uep->ue_top != 0 || uep->ue_bot != 0) + if (uep->ue_top != 0 || uep->ue_bot != 0) { return; + } for (lnum = 1; lnum < curbuf->b_ml.ml_line_count && lnum <= uep->ue_size; lnum++) { @@ -2778,7 +2810,7 @@ void u_find_first_changed(void) } } if (curbuf->b_ml.ml_line_count != uep->ue_size) { - /* lines added or deleted at the end, put the cursor there */ + // lines added or deleted at the end, put the cursor there clearpos(&(uhp->uh_cursor)); uhp->uh_cursor.lnum = lnum; } @@ -2790,27 +2822,30 @@ void u_find_first_changed(void) */ void u_update_save_nr(buf_T *buf) { - u_header_T *uhp; + u_header_T *uhp; ++buf->b_u_save_nr_last; buf->b_u_save_nr_cur = buf->b_u_save_nr_last; uhp = buf->b_u_curhead; - if (uhp != NULL) + if (uhp != NULL) { uhp = uhp->uh_next.ptr; - else + } else { uhp = buf->b_u_newhead; - if (uhp != NULL) + } + if (uhp != NULL) { uhp->uh_save_nr = buf->b_u_save_nr_last; + } } static void u_unch_branch(u_header_T *uhp) { - u_header_T *uh; + u_header_T *uh; for (uh = uhp; uh != NULL; uh = uh->uh_prev.ptr) { uh->uh_flags |= UH_CHANGED; - if (uh->uh_alt_next.ptr != NULL) - u_unch_branch(uh->uh_alt_next.ptr); /* recursive */ + if (uh->uh_alt_next.ptr != NULL) { + u_unch_branch(uh->uh_alt_next.ptr); // recursive + } } } @@ -2829,11 +2864,11 @@ static u_entry_T *u_get_headentry(buf_T *buf) /* * u_getbot(): compute the line number of the previous u_save - * It is called only when b_u_synced is false. + * It is called only when b_u_synced is false. */ static void u_getbot(buf_T *buf) { - u_entry_T *uep; + u_entry_T *uep; linenr_T extra; uep = u_get_headentry(buf); // check for corrupt undo list @@ -2864,95 +2899,91 @@ static void u_getbot(buf_T *buf) buf->b_u_synced = true; } -/* - * Free one header "uhp" and its entry list and adjust the pointers. - */ -static void -u_freeheader( - buf_T *buf, - u_header_T *uhp, - u_header_T **uhpp // if not NULL reset when freeing this header -) +/// Free one header "uhp" and its entry list and adjust the pointers. +/// +/// @param uhpp if not NULL reset when freeing this header +static void u_freeheader(buf_T *buf, u_header_T *uhp, u_header_T **uhpp) { - u_header_T *uhap; + u_header_T *uhap; /* When there is an alternate redo list free that branch completely, * because we can never go there. */ - if (uhp->uh_alt_next.ptr != NULL) + if (uhp->uh_alt_next.ptr != NULL) { u_freebranch(buf, uhp->uh_alt_next.ptr, uhpp); + } - if (uhp->uh_alt_prev.ptr != NULL) + if (uhp->uh_alt_prev.ptr != NULL) { uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL; + } - /* Update the links in the list to remove the header. */ - if (uhp->uh_next.ptr == NULL) + // Update the links in the list to remove the header. + if (uhp->uh_next.ptr == NULL) { buf->b_u_oldhead = uhp->uh_prev.ptr; - else + } else { uhp->uh_next.ptr->uh_prev.ptr = uhp->uh_prev.ptr; + } - if (uhp->uh_prev.ptr == NULL) + if (uhp->uh_prev.ptr == NULL) { buf->b_u_newhead = uhp->uh_next.ptr; - else + } else { for (uhap = uhp->uh_prev.ptr; uhap != NULL; - uhap = uhap->uh_alt_next.ptr) + uhap = uhap->uh_alt_next.ptr) { uhap->uh_next.ptr = uhp->uh_next.ptr; + } + } u_freeentries(buf, uhp, uhpp); } -/* - * Free an alternate branch and any following alternate branches. - */ -static void -u_freebranch( - buf_T *buf, - u_header_T *uhp, - u_header_T **uhpp // if not NULL reset when freeing this header -) +/// Free an alternate branch and any following alternate branches. +/// +/// @param uhpp if not NULL reset when freeing this header +static void u_freebranch(buf_T *buf, u_header_T *uhp, u_header_T **uhpp) { - u_header_T *tofree, *next; + u_header_T *tofree, *next; /* If this is the top branch we may need to use u_freeheader() to update * all the pointers. */ if (uhp == buf->b_u_oldhead) { - while (buf->b_u_oldhead != NULL) + while (buf->b_u_oldhead != NULL) { u_freeheader(buf, buf->b_u_oldhead, uhpp); + } return; } - if (uhp->uh_alt_prev.ptr != NULL) + if (uhp->uh_alt_prev.ptr != NULL) { uhp->uh_alt_prev.ptr->uh_alt_next.ptr = NULL; + } next = uhp; while (next != NULL) { tofree = next; - if (tofree->uh_alt_next.ptr != NULL) - u_freebranch(buf, tofree->uh_alt_next.ptr, uhpp); /* recursive */ + if (tofree->uh_alt_next.ptr != NULL) { + u_freebranch(buf, tofree->uh_alt_next.ptr, uhpp); // recursive + } next = tofree->uh_prev.ptr; u_freeentries(buf, tofree, uhpp); } } -/* - * Free all the undo entries for one header and the header itself. - * This means that "uhp" is invalid when returning. - */ -static void -u_freeentries( - buf_T *buf, - u_header_T *uhp, - u_header_T **uhpp // if not NULL reset when freeing this header -) +/// Free all the undo entries for one header and the header itself. +/// This means that "uhp" is invalid when returning. +/// +/// @param uhpp if not NULL reset when freeing this header +static void u_freeentries(buf_T *buf, u_header_T *uhp, u_header_T **uhpp) { - u_entry_T *uep, *nuep; + u_entry_T *uep, *nuep; - /* Check for pointers to the header that become invalid now. */ - if (buf->b_u_curhead == uhp) + // Check for pointers to the header that become invalid now. + if (buf->b_u_curhead == uhp) { buf->b_u_curhead = NULL; - if (buf->b_u_newhead == uhp) - buf->b_u_newhead = NULL; /* freeing the newest entry */ - if (uhpp != NULL && uhp == *uhpp) + } + if (buf->b_u_newhead == uhp) { + buf->b_u_newhead = NULL; // freeing the newest entry + } + if (uhpp != NULL && uhp == *uhpp) { *uhpp = NULL; + } for (uep = uhp->uh_entry; uep != NULL; uep = nuep) { nuep = uep->ue_next; @@ -2973,8 +3004,9 @@ u_freeentries( */ static void u_freeentry(u_entry_T *uep, long n) { - while (n > 0) + while (n > 0) { xfree(uep->ue_array[--n]); + } xfree((char_u *)uep->ue_array); #ifdef U_DEBUG uep->ue_magic = 0; @@ -2999,16 +3031,19 @@ void u_clearall(buf_T *buf) */ void u_saveline(linenr_T lnum) { - if (lnum == curbuf->b_u_line_lnum) /* line is already saved */ + if (lnum == curbuf->b_u_line_lnum) { // line is already saved return; - if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) /* should never happen */ + } + if (lnum < 1 || lnum > curbuf->b_ml.ml_line_count) { // should never happen return; + } u_clearline(); curbuf->b_u_line_lnum = lnum; - if (curwin->w_cursor.lnum == lnum) + if (curwin->w_cursor.lnum == lnum) { curbuf->b_u_line_colnr = curwin->w_cursor.col; - else + } else { curbuf->b_u_line_colnr = 0; + } curbuf->b_u_line_ptr = u_save_line(lnum); } @@ -3033,7 +3068,7 @@ void u_clearline(void) void u_undoline(void) { colnr_T t; - char_u *oldp; + char_u *oldp; if (curbuf->b_u_line_ptr == NULL || curbuf->b_u_line_lnum > curbuf->b_ml.ml_line_count) { @@ -3050,12 +3085,15 @@ void u_undoline(void) oldp = u_save_line(curbuf->b_u_line_lnum); ml_replace(curbuf->b_u_line_lnum, curbuf->b_u_line_ptr, true); changed_bytes(curbuf->b_u_line_lnum, 0); + extmark_splice_cols(curbuf, (int)curbuf->b_u_line_lnum-1, 0, (colnr_T)STRLEN(oldp), + (colnr_T)STRLEN(curbuf->b_u_line_ptr), kExtmarkUndo); xfree(curbuf->b_u_line_ptr); curbuf->b_u_line_ptr = oldp; t = curbuf->b_u_line_colnr; - if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum) + if (curwin->w_cursor.lnum == curbuf->b_u_line_lnum) { curbuf->b_u_line_colnr = curwin->w_cursor.col; + } curwin->w_cursor.col = t; curwin->w_cursor.lnum = curbuf->b_u_line_lnum; check_cursor_col(); @@ -3106,8 +3144,8 @@ bool bufIsChanged(buf_T *buf) { // In a "prompt" buffer we do respect 'modified', so that we can control // closing the window by setting or resetting that option. - return (!bt_dontwrite(buf) || bt_prompt(buf)) - && (buf->b_changed || file_ff_differs(buf, true)); + return (!bt_dontwrite(buf) || bt_prompt(buf)) + && (buf->b_changed || file_ff_differs(buf, true)); } // Return true if any buffer has changes. Also buffers that are not written. diff --git a/src/nvim/version.c b/src/nvim/version.c index 7c197f1b7f..bc06ef0b98 100644 --- a/src/nvim/version.c +++ b/src/nvim/version.c @@ -6,32 +6,32 @@ /// Nvim was forked from Vim 7.4.160. /// Vim originated from Stevie version 3.6 (Fish disk 217) by GRWalter (Fred). -#include <inttypes.h> #include <assert.h> +#include <inttypes.h> #include <limits.h> #include "nvim/api/private/helpers.h" -#include "nvim/vim.h" #include "nvim/ascii.h" #include "nvim/buffer.h" -#include "nvim/iconv.h" -#include "nvim/version.h" #include "nvim/charset.h" +#include "nvim/iconv.h" +#include "nvim/lua/executor.h" #include "nvim/memline.h" #include "nvim/memory.h" #include "nvim/message.h" #include "nvim/screen.h" #include "nvim/strings.h" -#include "nvim/lua/executor.h" +#include "nvim/version.h" +#include "nvim/vim.h" // version info generated by the build system #include "auto/versiondef.h" // for ":version", ":intro", and "nvim --version" #ifndef NVIM_VERSION_MEDIUM -#define NVIM_VERSION_MEDIUM "v" STR(NVIM_VERSION_MAJOR)\ -"." STR(NVIM_VERSION_MINOR) "." STR(NVIM_VERSION_PATCH)\ -NVIM_VERSION_PRERELEASE +# define NVIM_VERSION_MEDIUM "v" STR(NVIM_VERSION_MAJOR)\ + "." STR(NVIM_VERSION_MINOR) "." STR(NVIM_VERSION_PATCH)\ + NVIM_VERSION_PRERELEASE #endif #define NVIM_VERSION_LONG "NVIM " NVIM_VERSION_MEDIUM @@ -50,23 +50,23 @@ char *version_cflags = "Compilation: " NVIM_VERSION_CFLAGS; static char *features[] = { #ifdef HAVE_ACL -"+acl", + "+acl", #else -"-acl", + "-acl", #endif #if defined(HAVE_ICONV) -"+iconv", + "+iconv", #else -"-iconv", + "-iconv", #endif #ifdef FEAT_TUI -"+tui", + "+tui", #else -"-tui", + "-tui", #endif -NULL + NULL }; // clang-format off @@ -2019,7 +2019,7 @@ void ex_version(exarg_T *eap) /// @param wrap static void version_msg_wrap(char_u *s, int wrap) { - int len = (int)vim_strsize(s) + (wrap ? 2 : 0); + int len = vim_strsize(s) + (wrap ? 2 : 0); if (!got_int && (len < Columns) @@ -2070,7 +2070,7 @@ void list_in_columns(char_u **items, int size, int current) // Find the length of the longest item, use that + 1 as the column width. int i; for (i = 0; size < 0 ? items[i] != NULL : i < size; i++) { - int l = (int)vim_strsize(items[i]) + (i == current ? 2 : 0); + int l = vim_strsize(items[i]) + (i == current ? 2 : 0); if (l > width) { width = l; diff --git a/src/nvim/window.c b/src/nvim/window.c index c0f537aab3..ff97eaa757 100644 --- a/src/nvim/window.c +++ b/src/nvim/window.c @@ -853,12 +853,12 @@ void ui_ext_win_position(win_T *wp) bool east = c.anchor & kFloatAnchorEast; bool south = c.anchor & kFloatAnchorSouth; - int comp_row = (int)row - (south ? wp->w_height : 0); - int comp_col = (int)col - (east ? wp->w_width : 0); + int comp_row = (int)row - (south ? wp->w_height_outer : 0); + int comp_col = (int)col - (east ? wp->w_width_outer : 0); comp_row += grid->comp_row; comp_col += grid->comp_col; - comp_row = MAX(MIN(comp_row, Rows-wp->w_height_outer-1), 0); - comp_col = MAX(MIN(comp_col, Columns-wp->w_width_outer), 0); + comp_row = MAX(MIN(comp_row, Rows - wp->w_height_outer - 1), 0); + comp_col = MAX(MIN(comp_col, Columns - wp->w_width_outer), 0); wp->w_winrow = comp_row; wp->w_wincol = comp_col; bool valid = (wp->w_redr_type == 0); diff --git a/src/uncrustify.cfg b/src/uncrustify.cfg index 5d73e70ed0..db0c50ff22 100644 --- a/src/uncrustify.cfg +++ b/src/uncrustify.cfg @@ -1,4 +1,4 @@ -# Uncrustify-0.73.0-186-03faf73c +# Uncrustify-0.73.0-195-1f883c691 # # General options @@ -535,14 +535,21 @@ sp_inside_braces_struct = ignore # ignore/add/remove/force/not_defined sp_inside_braces_oc_dict = ignore # ignore/add/remove/force/not_defined # Add or remove space after open brace in an unnamed temporary -# direct-list-initialization. +# 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 # Add or remove space before close brace in an unnamed temporary -# direct-list-initialization. +# 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 -# Add or remove space inside an unnamed temporary direct-list-initialization. +# 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 # Add or remove space inside '{' and '}'. diff --git a/src/xdiff/xdiffi.c b/src/xdiff/xdiffi.c index f35ac5d0b0..cfcbb5d982 100644 --- a/src/xdiff/xdiffi.c +++ b/src/xdiff/xdiffi.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - /* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi diff --git a/src/xdiff/xemit.c b/src/xdiff/xemit.c index 23c6e2d993..b578e7a9d5 100644 --- a/src/xdiff/xemit.c +++ b/src/xdiff/xemit.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - /* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi diff --git a/src/xdiff/xhistogram.c b/src/xdiff/xhistogram.c index 3c84f35626..8598a8550d 100644 --- a/src/xdiff/xhistogram.c +++ b/src/xdiff/xhistogram.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - /* * Copyright (C) 2010, Google Inc. * and other copyright owners as documented in JGit's IP log. diff --git a/src/xdiff/xpatience.c b/src/xdiff/xpatience.c index 5f547ca5c0..f78c897ad8 100644 --- a/src/xdiff/xpatience.c +++ b/src/xdiff/xpatience.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - /* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003-2016 Davide Libenzi, Johannes E. Schindelin diff --git a/src/xdiff/xprepare.c b/src/xdiff/xprepare.c index f13822e4fa..abeb8fb84e 100644 --- a/src/xdiff/xprepare.c +++ b/src/xdiff/xprepare.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - /* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi diff --git a/src/xdiff/xutils.c b/src/xdiff/xutils.c index 65aa50497d..f13a854536 100644 --- a/src/xdiff/xutils.c +++ b/src/xdiff/xutils.c @@ -1,6 +1,3 @@ -// This is an open source non-commercial project. Dear PVS-Studio, please check -// it. PVS-Studio Static Code Analyzer for C, C++ and C#: http://www.viva64.com - /* * LibXDiff by Davide Libenzi ( File Differential Library ) * Copyright (C) 2003 Davide Libenzi |