diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cjson/lua_cjson.c | 121 | ||||
-rw-r--r-- | src/nvim/api/autocmd.c | 6 | ||||
-rw-r--r-- | src/nvim/autocmd.c | 6 | ||||
-rw-r--r-- | src/nvim/autocmd_defs.h | 1 | ||||
-rw-r--r-- | src/nvim/edit.c | 2 | ||||
-rw-r--r-- | src/nvim/ex_docmd.c | 14 | ||||
-rw-r--r-- | src/nvim/generators/gen_options.lua | 6 | ||||
-rw-r--r-- | src/nvim/insexpand.c | 34 | ||||
-rw-r--r-- | src/nvim/message.c | 221 | ||||
-rw-r--r-- | src/nvim/normal.c | 4 | ||||
-rw-r--r-- | src/nvim/option.c | 14 | ||||
-rw-r--r-- | src/nvim/option_vars.h | 2 | ||||
-rw-r--r-- | src/nvim/options.lua | 49 | ||||
-rw-r--r-- | src/nvim/optionstr.c | 18 |
14 files changed, 335 insertions, 163 deletions
diff --git a/src/cjson/lua_cjson.c b/src/cjson/lua_cjson.c index 254355e5a2..e4bd0bcf6b 100644 --- a/src/cjson/lua_cjson.c +++ b/src/cjson/lua_cjson.c @@ -173,6 +173,16 @@ typedef struct { } json_config_t; typedef struct { + const char **char2escape[256]; +} json_encode_options_t; + +typedef struct { + json_config_t *cfg; + json_encode_options_t *options; + strbuf_t *json; +} json_encode_t; + +typedef struct { /* convert null in json objects to lua nil instead of vim.NIL */ bool luanil_object; /* convert null in json arrays to lua nil instead of vim.NIL */ @@ -209,7 +219,7 @@ static const char *char2escape[256] = { "\\u0018", "\\u0019", "\\u001a", "\\u001b", "\\u001c", "\\u001d", "\\u001e", "\\u001f", NULL, NULL, "\\\"", NULL, NULL, NULL, NULL, NULL, - NULL, NULL, NULL, NULL, NULL, NULL, NULL, "\\/", + NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, @@ -555,11 +565,11 @@ static void json_create_config(lua_State *l) /* ===== ENCODING ===== */ -static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *json, int lindex, +static void json_encode_exception(lua_State *l, json_encode_t *ctx, int lindex, const char *reason) { - if (!cfg->encode_keep_buffer) - strbuf_free(json); + if (!ctx->cfg->encode_keep_buffer) + strbuf_free(ctx->json); luaL_error(l, "Cannot serialise %s: %s", lua_typename(l, lua_type(l, lindex)), reason); } @@ -570,12 +580,13 @@ static void json_encode_exception(lua_State *l, json_config_t *cfg, strbuf_t *js * - String (Lua stack index) * * Returns nothing. Doesn't remove string from Lua stack */ -static void json_append_string(lua_State *l, strbuf_t *json, int lindex) +static void json_append_string(lua_State *l, json_encode_t *ctx, int lindex) { const char *escstr; unsigned i; const char *str; size_t len; + strbuf_t *json = ctx->json; str = lua_tolstring(l, lindex, &len); @@ -587,7 +598,7 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex) strbuf_append_char_unsafe(json, '\"'); for (i = 0; i < len; i++) { - escstr = char2escape[(unsigned char)str[i]]; + escstr = (*ctx->options->char2escape)[(unsigned char)str[i]]; if (escstr) strbuf_append_string(json, escstr); else @@ -600,11 +611,12 @@ static void json_append_string(lua_State *l, strbuf_t *json, int lindex) * -1 object (not a pure array) * >=0 elements in array */ -static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json) +static int lua_array_length(lua_State *l, json_encode_t *ctx) { double k; int max; int items; + json_config_t *cfg = ctx->cfg; max = 0; items = 0; @@ -635,7 +647,7 @@ static int lua_array_length(lua_State *l, json_config_t *cfg, strbuf_t *json) max > items * cfg->encode_sparse_ratio && max > cfg->encode_sparse_safe) { if (!cfg->encode_sparse_convert) - json_encode_exception(l, cfg, json, -1, "excessively sparse array"); + json_encode_exception(l, ctx, -1, "excessively sparse array"); return -1; } @@ -666,17 +678,18 @@ static void json_check_encode_depth(lua_State *l, json_config_t *cfg, current_depth); } -static void json_append_data(lua_State *l, json_config_t *cfg, - int current_depth, strbuf_t *json); +static void json_append_data(lua_State *l, json_encode_t *cfg, + int current_depth); /* json_append_array args: * - lua_State * - JSON strbuf * - Size of passwd Lua array (top of stack) */ -static void json_append_array(lua_State *l, json_config_t *cfg, int current_depth, - strbuf_t *json, int array_length) +static void json_append_array(lua_State *l, json_encode_t *ctx, int current_depth, + int array_length) { int comma, i; + strbuf_t *json = ctx->json; strbuf_append_char(json, '['); @@ -688,23 +701,25 @@ static void json_append_array(lua_State *l, json_config_t *cfg, int current_dept comma = 1; lua_rawgeti(l, -1, i); - json_append_data(l, cfg, current_depth, json); + json_append_data(l, ctx, current_depth); lua_pop(l, 1); } strbuf_append_char(json, ']'); } -static void json_append_number(lua_State *l, json_config_t *cfg, - strbuf_t *json, int lindex) +static void json_append_number(lua_State *l, json_encode_t *ctx, + int lindex) { double num = lua_tonumber(l, lindex); int len; + json_config_t *cfg = ctx->cfg; + strbuf_t *json = ctx->json; if (cfg->encode_invalid_numbers == 0) { /* Prevent encoding invalid numbers */ if (isinf(num) || isnan(num)) - json_encode_exception(l, cfg, json, lindex, + json_encode_exception(l, ctx, lindex, "must not be NaN or Infinity"); } else if (cfg->encode_invalid_numbers == 1) { /* Encode NaN/Infinity separately to ensure Javascript compatible @@ -733,10 +748,11 @@ static void json_append_number(lua_State *l, json_config_t *cfg, strbuf_extend_length(json, len); } -static void json_append_object(lua_State *l, json_config_t *cfg, - int current_depth, strbuf_t *json) +static void json_append_object(lua_State *l, json_encode_t *ctx, + int current_depth) { int comma, keytype; + strbuf_t *json = ctx->json; /* Object */ strbuf_append_char(json, '{'); @@ -754,19 +770,19 @@ static void json_append_object(lua_State *l, json_config_t *cfg, keytype = lua_type(l, -2); if (keytype == LUA_TNUMBER) { strbuf_append_char(json, '"'); - json_append_number(l, cfg, json, -2); + json_append_number(l, ctx, -2); strbuf_append_mem(json, "\":", 2); } else if (keytype == LUA_TSTRING) { - json_append_string(l, json, -2); + json_append_string(l, ctx, -2); strbuf_append_char(json, ':'); } else { - json_encode_exception(l, cfg, json, -2, + json_encode_exception(l, ctx, -2, "table key must be a number or string"); /* never returns */ } /* table, key, value */ - json_append_data(l, cfg, current_depth, json); + json_append_data(l, ctx, current_depth); lua_pop(l, 1); /* table, key */ } @@ -775,20 +791,22 @@ static void json_append_object(lua_State *l, json_config_t *cfg, } /* Serialise Lua data into JSON string. */ -static void json_append_data(lua_State *l, json_config_t *cfg, - int current_depth, strbuf_t *json) +static void json_append_data(lua_State *l, json_encode_t *ctx, + int current_depth) { int len; int as_array = 0; int as_empty_dict = 0; int has_metatable; + json_config_t *cfg = ctx->cfg; + strbuf_t *json = ctx->json; switch (lua_type(l, -1)) { case LUA_TSTRING: - json_append_string(l, json, -1); + json_append_string(l, ctx, -1); break; case LUA_TNUMBER: - json_append_number(l, cfg, json, -1); + json_append_number(l, ctx, -1); break; case LUA_TBOOLEAN: if (lua_toboolean(l, -1)) @@ -818,12 +836,12 @@ static void json_append_data(lua_State *l, json_config_t *cfg, if (as_array) { len = lua_objlen(l, -1); - json_append_array(l, cfg, current_depth, json, len); + json_append_array(l, ctx, current_depth, len); } else { - len = lua_array_length(l, cfg, json); + len = lua_array_length(l, ctx); if (len > 0 || (len == 0 && !cfg->encode_empty_table_as_object && !as_empty_dict)) { - json_append_array(l, cfg, current_depth, json, len); + json_append_array(l, ctx, current_depth, len); } else { if (has_metatable) { lua_getmetatable(l, -1); @@ -833,11 +851,11 @@ static void json_append_data(lua_State *l, json_config_t *cfg, as_array = lua_rawequal(l, -1, -2); lua_pop(l, 2); /* pop pointer + metatable */ if (as_array) { - json_append_array(l, cfg, current_depth, json, 0); + json_append_array(l, ctx, current_depth, 0); break; } } - json_append_object(l, cfg, current_depth, json); + json_append_object(l, ctx, current_depth); } } break; @@ -846,7 +864,7 @@ static void json_append_data(lua_State *l, json_config_t *cfg, break; case LUA_TLIGHTUSERDATA: if (lua_touserdata(l, -1) == &json_array) { - json_append_array(l, cfg, current_depth, json, 0); + json_append_array(l, ctx, current_depth, 0); } break; case LUA_TUSERDATA: @@ -862,7 +880,7 @@ static void json_append_data(lua_State *l, json_config_t *cfg, default: /* Remaining types (LUA_TFUNCTION, LUA_TUSERDATA, LUA_TTHREAD, * and LUA_TLIGHTUSERDATA) cannot be serialised */ - json_encode_exception(l, cfg, json, -1, "type not supported"); + json_encode_exception(l, ctx, -1, "type not supported"); /* never returns */ } } @@ -870,12 +888,44 @@ static void json_append_data(lua_State *l, json_config_t *cfg, static int json_encode(lua_State *l) { json_config_t *cfg = json_fetch_config(l); + json_encode_options_t options = { .char2escape = { char2escape } }; + json_encode_t ctx = { .options = &options, .cfg = cfg }; strbuf_t local_encode_buf; strbuf_t *encode_buf; char *json; int len; + const char *customChar2escape[256]; - 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, "escape_slash"); + + /* We only handle the escape_slash option for now */ + if (lua_isnil(l, -1)) { + lua_pop(l, 2); + break; + } + + luaL_checktype(l, -1, LUA_TBOOLEAN); + + int escape_slash = lua_toboolean(l, -1); + + if (escape_slash) { + /* This can be optimised by adding a new hard-coded escape table for this case, + * but this path will rarely if ever be used, so let's just memcpy.*/ + memcpy(customChar2escape, char2escape, sizeof(char2escape)); + customChar2escape['/'] = "\\/"; + *ctx.options->char2escape = customChar2escape; + } + + lua_pop(l, 2); + break; + default: + return luaL_error (l, "expected 1 or 2 arguments"); + } if (!cfg->encode_keep_buffer) { /* Use private buffer */ @@ -887,7 +937,8 @@ static int json_encode(lua_State *l) strbuf_reset(encode_buf); } - json_append_data(l, cfg, 0, encode_buf); + ctx.json = encode_buf; + json_append_data(l, &ctx, 0); json = strbuf_string(encode_buf, &len); lua_pushlstring(l, json, len); diff --git a/src/nvim/api/autocmd.c b/src/nvim/api/autocmd.c index db87500d08..45e2de69e0 100644 --- a/src/nvim/api/autocmd.c +++ b/src/nvim/api/autocmd.c @@ -386,9 +386,9 @@ cleanup: /// - id: (number) autocommand id /// - event: (string) name of the triggered event |autocmd-events| /// - group: (number|nil) autocommand group id, if any -/// - match: (string) expanded value of [<amatch>] -/// - buf: (number) expanded value of [<abuf>] -/// - file: (string) expanded value of [<afile>] +/// - file: (string) [<afile>] (not expanded to a full path) +/// - match: (string) [<amatch>] (expanded to a full path) +/// - buf: (number) [<abuf>] /// - data: (any) arbitrary data passed from [nvim_exec_autocmds()] [event-data]() /// - command (string) optional: Vim command to execute on event. Cannot be used with /// {callback} diff --git a/src/nvim/autocmd.c b/src/nvim/autocmd.c index c08ef7a4c1..118a50e15d 100644 --- a/src/nvim/autocmd.c +++ b/src/nvim/autocmd.c @@ -1666,7 +1666,9 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force } else { autocmd_fname = fname_io; } + char *afile_orig = NULL; ///< Unexpanded <afile> if (autocmd_fname != NULL) { + afile_orig = xstrdup(autocmd_fname); // Allocate MAXPATHL for when eval_vars() resolves the fullpath. autocmd_fname = xstrnsave(autocmd_fname, MAXPATHL); } @@ -1798,6 +1800,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force // save vector size, to avoid an endless loop when more patterns // are added when executing autocommands .ausize = kv_size(autocmds[(int)event]), + .afile_orig = afile_orig, .fname = fname, .sfname = sfname, .tail = tail, @@ -1865,6 +1868,7 @@ bool apply_autocmds_group(event_T event, char *fname, char *fname_io, bool force autocmd_nested = save_autocmd_nested; xfree(SOURCING_NAME); estack_pop(); + xfree(afile_orig); xfree(autocmd_fname); autocmd_fname = save_autocmd_fname; autocmd_fname_full = save_autocmd_fname_full; @@ -2029,8 +2033,8 @@ static bool call_autocmd_callback(const AutoCmd *ac, const AutoPatCmd *apc) MAXSIZE_TEMP_DICT(data, 7); PUT_C(data, "id", INTEGER_OBJ(ac->id)); PUT_C(data, "event", CSTR_AS_OBJ(event_nr2name(apc->event))); + PUT_C(data, "file", CSTR_AS_OBJ(apc->afile_orig)); PUT_C(data, "match", CSTR_AS_OBJ(autocmd_match)); - PUT_C(data, "file", CSTR_AS_OBJ(autocmd_fname)); PUT_C(data, "buf", INTEGER_OBJ(autocmd_bufnr)); if (apc->data) { diff --git a/src/nvim/autocmd_defs.h b/src/nvim/autocmd_defs.h index 490782b209..cba947e85f 100644 --- a/src/nvim/autocmd_defs.h +++ b/src/nvim/autocmd_defs.h @@ -52,6 +52,7 @@ struct AutoPatCmd_S { AutoPat *lastpat; ///< Last matched AutoPat size_t auidx; ///< Current autocmd index to execute size_t ausize; ///< Saved AutoCmd vector size + char *afile_orig; ///< Unexpanded <afile> char *fname; ///< Fname to match with char *sfname; ///< Sfname to match with char *tail; ///< Tail of fname diff --git a/src/nvim/edit.c b/src/nvim/edit.c index 248f419807..f5e11a188f 100644 --- a/src/nvim/edit.c +++ b/src/nvim/edit.c @@ -604,7 +604,7 @@ static int insert_execute(VimState *state, int key) || (ins_compl_enter_selects() && (s->c == CAR || s->c == K_KENTER || s->c == NL))) && stop_arrow() == OK) { - ins_compl_delete(); + ins_compl_delete(false); ins_compl_insert(false); } } diff --git a/src/nvim/ex_docmd.c b/src/nvim/ex_docmd.c index 9968f32de1..b7c83ea1ac 100644 --- a/src/nvim/ex_docmd.c +++ b/src/nvim/ex_docmd.c @@ -6101,12 +6101,18 @@ static void ex_sleep(exarg_T *eap) default: semsg(_(e_invarg2), eap->arg); return; } - do_sleep(len); + do_sleep(len, false); } /// Sleep for "msec" milliseconds, but return early on CTRL-C. -void do_sleep(int64_t msec) +/// +/// @param hide_cursor hide the cursor if true +void do_sleep(int64_t msec, bool hide_cursor) { + if (hide_cursor) { + ui_busy_start(); + } + ui_flush(); // flush before waiting LOOP_PROCESS_EVENTS_UNTIL(&main_loop, main_loop.events, msec, got_int); @@ -6115,6 +6121,10 @@ void do_sleep(int64_t msec) if (got_int) { vpeekc(); } + + if (hide_cursor) { + ui_busy_stop(); + } } /// ":winsize" command (obsolete). diff --git a/src/nvim/generators/gen_options.lua b/src/nvim/generators/gen_options.lua index 779b31e7a0..c79683dc00 100644 --- a/src/nvim/generators/gen_options.lua +++ b/src/nvim/generators/gen_options.lua @@ -47,7 +47,9 @@ end --- @param s string --- @return string local lowercase_to_titlecase = function(s) - return s:sub(1, 1):upper() .. s:sub(2) + return table.concat(vim.tbl_map(function(word) --- @param word string + return word:sub(1, 1):upper() .. word:sub(2) + end, vim.split(s, '[-_]'))) end -- Generate options enum file @@ -177,7 +179,7 @@ for _, option in ipairs(options_meta) do vars_w( (' kOpt%sFlag%s = 0x%02x,'):format( opt_name, - lowercase_to_titlecase(flag_name), + lowercase_to_titlecase(flag_name:gsub(':$', '')), enum_values[flag_name] ) ) diff --git a/src/nvim/insexpand.c b/src/nvim/insexpand.c index 93d081153c..b18c4ead41 100644 --- a/src/nvim/insexpand.c +++ b/src/nvim/insexpand.c @@ -951,14 +951,14 @@ static void ins_compl_longest_match(compl_T *match) compl_leader = xstrdup(match->cp_str); bool had_match = (curwin->w_cursor.col > compl_col); - ins_compl_delete(); + ins_compl_delete(false); ins_bytes(compl_leader + get_compl_len()); ins_redraw(false); // When the match isn't there (to avoid matching itself) remove it // again after redrawing. if (!had_match) { - ins_compl_delete(); + ins_compl_delete(false); } compl_used_match = false; @@ -985,14 +985,14 @@ static void ins_compl_longest_match(compl_T *match) // Leader was shortened, need to change the inserted text. *p = NUL; bool had_match = (curwin->w_cursor.col > compl_col); - ins_compl_delete(); + ins_compl_delete(false); ins_bytes(compl_leader + get_compl_len()); ins_redraw(false); // When the match isn't there (to avoid matching itself) remove it // again after redrawing. if (!had_match) { - ins_compl_delete(); + ins_compl_delete(false); } } @@ -1811,9 +1811,8 @@ static bool ins_compl_need_restart(void) static void ins_compl_new_leader(void) { ins_compl_del_pum(); - ins_compl_delete(); + ins_compl_delete(true); ins_bytes(compl_leader + get_compl_len()); - restore_orig_extmarks(); compl_used_match = false; if (compl_started) { @@ -2137,7 +2136,7 @@ static bool ins_compl_stop(const int c, const int prev_mode, bool retval) // CTRL-E means completion is Ended, go back to the typed text. // but only do this, if the Popup is still visible if (c == Ctrl_E) { - ins_compl_delete(); + ins_compl_delete(false); char *p = NULL; if (compl_leader != NULL) { p = compl_leader; @@ -3610,11 +3609,24 @@ static void ins_compl_update_shown_match(void) } /// Delete the old text being completed. -void ins_compl_delete(void) +void ins_compl_delete(bool new_leader) { + // Avoid deleting text that will be reinserted when changing leader. This + // allows marks present on the original text to shrink/grow appropriately. + int orig_col = 0; + if (new_leader) { + char *orig = compl_orig_text; + char *leader = ins_compl_leader(); + while (*orig != NUL && utf_ptr2char(orig) == utf_ptr2char(leader)) { + leader += utf_ptr2len(leader); + orig += utf_ptr2len(orig); + } + orig_col = (int)(orig - compl_orig_text); + } + // In insert mode: Delete the typed part. // In replace mode: Put the old characters back, if any. - int col = compl_col + (compl_status_adding() ? compl_length : 0); + int col = compl_col + (compl_status_adding() ? compl_length : orig_col); if ((int)curwin->w_cursor.col > col) { if (stop_arrow() == FAIL) { return; @@ -3858,7 +3870,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match if (allow_get_expansion && insert_match && (!compl_get_longest || compl_used_match)) { // Delete old text to be replaced - ins_compl_delete(); + ins_compl_delete(false); } // When finding the longest common text we stick at the original text, @@ -3911,7 +3923,7 @@ static int ins_compl_next(bool allow_get_expansion, int count, bool insert_match // Delete old text to be replaced, since we're still searching and // don't want to match ourselves! - ins_compl_delete(); + ins_compl_delete(false); } // Enter will select a match when the match wasn't inserted and the popup diff --git a/src/nvim/message.c b/src/nvim/message.c index 0b1156a6bd..a32a06edca 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -26,6 +26,7 @@ #include "nvim/event/loop.h" #include "nvim/event/multiqueue.h" #include "nvim/ex_cmds_defs.h" +#include "nvim/ex_docmd.h" #include "nvim/ex_eval.h" #include "nvim/fileio.h" #include "nvim/garray.h" @@ -94,6 +95,16 @@ static char *confirm_msg_tail; // tail of confirm_msg MessageHistoryEntry *first_msg_hist = NULL; MessageHistoryEntry *last_msg_hist = NULL; static int msg_hist_len = 0; +static int msg_hist_max = 500; // The default max value is 500 + +// args in 'messagesopt' option +#define MESSAGES_OPT_HIT_ENTER "hit-enter" +#define MESSAGES_OPT_WAIT "wait:" +#define MESSAGES_OPT_HISTORY "history:" + +// The default is "hit-enter,history:500" +static int msg_flags = kOptMoptFlagHitEnter | kOptMoptFlagHistory; +static int msg_wait = 0; static FILE *verbose_fd = NULL; static bool verbose_did_open = false; @@ -1038,14 +1049,69 @@ int delete_first_msg(void) return OK; } -void check_msg_hist(void) +static void check_msg_hist(void) { // Don't let the message history get too big - while (msg_hist_len > 0 && msg_hist_len > p_mhi) { + while (msg_hist_len > 0 && msg_hist_len > msg_hist_max) { (void)delete_first_msg(); } } +int messagesopt_changed(void) +{ + int messages_flags_new = 0; + int messages_wait_new = 0; + int messages_history_new = 0; + + char *p = p_meo; + while (*p != NUL) { + if (strnequal(p, S_LEN(MESSAGES_OPT_HIT_ENTER))) { + p += STRLEN_LITERAL(MESSAGES_OPT_HIT_ENTER); + messages_flags_new |= kOptMoptFlagHitEnter; + } else if (strnequal(p, S_LEN(MESSAGES_OPT_WAIT)) + && ascii_isdigit(p[STRLEN_LITERAL(MESSAGES_OPT_WAIT)])) { + p += STRLEN_LITERAL(MESSAGES_OPT_WAIT); + messages_wait_new = getdigits_int(&p, false, INT_MAX); + messages_flags_new |= kOptMoptFlagWait; + } else if (strnequal(p, S_LEN(MESSAGES_OPT_HISTORY)) + && ascii_isdigit(p[STRLEN_LITERAL(MESSAGES_OPT_HISTORY)])) { + p += STRLEN_LITERAL(MESSAGES_OPT_HISTORY); + messages_history_new = getdigits_int(&p, false, INT_MAX); + messages_flags_new |= kOptMoptFlagHistory; + } + + if (*p != ',' && *p != NUL) { + return FAIL; + } + if (*p == ',') { + p++; + } + } + + // Either "wait" or "hit-enter" is required + if (!(messages_flags_new & (kOptMoptFlagHitEnter | kOptMoptFlagWait))) { + return FAIL; + } + + // "history" must be set + if (!(messages_flags_new & kOptMoptFlagHistory)) { + return FAIL; + } + + // "history" must be <= 10000 + if (messages_history_new > 10000) { + return FAIL; + } + + msg_flags = messages_flags_new; + msg_wait = messages_wait_new; + + msg_hist_max = messages_history_new; + check_msg_hist(); + + return OK; +} + /// :messages command implementation void ex_messages(exarg_T *eap) FUNC_ATTR_NONNULL_ALL @@ -1209,83 +1275,88 @@ void wait_return(int redraw) cmdline_row = Rows - 1; } - hit_return_msg(true); - - do { - // Remember "got_int", if it is set vgetc() probably returns a - // CTRL-C, but we need to loop then. - had_got_int = got_int; - - // Don't do mappings here, we put the character back in the - // typeahead buffer. - no_mapping++; - allow_keys++; - - // Temporarily disable Recording. If Recording is active, the - // character will be recorded later, since it will be added to the - // typebuf after the loop - const int save_reg_recording = reg_recording; - save_scriptout = scriptout; - reg_recording = 0; - scriptout = NULL; - c = safe_vgetc(); - if (had_got_int && !global_busy) { - got_int = false; - } - no_mapping--; - allow_keys--; - reg_recording = save_reg_recording; - scriptout = save_scriptout; - - // Allow scrolling back in the messages. - // Also accept scroll-down commands when messages fill the screen, - // to avoid that typing one 'j' too many makes the messages - // disappear. - if (p_more) { - if (c == 'b' || c == 'k' || c == 'u' || c == 'g' - || c == K_UP || c == K_PAGEUP) { - if (msg_scrolled > Rows) { - // scroll back to show older messages - do_more_prompt(c); - } else { - msg_didout = false; - c = K_IGNORE; - msg_col = 0; - } - if (quit_more) { - c = CAR; // just pretend CR was hit - quit_more = false; - got_int = false; - } else if (c != K_IGNORE) { + if (msg_flags & kOptMoptFlagHitEnter) { + hit_return_msg(true); + + do { + // Remember "got_int", if it is set vgetc() probably returns a + // CTRL-C, but we need to loop then. + had_got_int = got_int; + + // Don't do mappings here, we put the character back in the + // typeahead buffer. + no_mapping++; + allow_keys++; + + // Temporarily disable Recording. If Recording is active, the + // character will be recorded later, since it will be added to the + // typebuf after the loop + const int save_reg_recording = reg_recording; + save_scriptout = scriptout; + reg_recording = 0; + scriptout = NULL; + c = safe_vgetc(); + if (had_got_int && !global_busy) { + got_int = false; + } + no_mapping--; + allow_keys--; + reg_recording = save_reg_recording; + scriptout = save_scriptout; + + // Allow scrolling back in the messages. + // Also accept scroll-down commands when messages fill the screen, + // to avoid that typing one 'j' too many makes the messages + // disappear. + if (p_more) { + if (c == 'b' || c == 'k' || c == 'u' || c == 'g' + || c == K_UP || c == K_PAGEUP) { + if (msg_scrolled > Rows) { + // scroll back to show older messages + do_more_prompt(c); + } else { + msg_didout = false; + c = K_IGNORE; + msg_col = 0; + } + if (quit_more) { + c = CAR; // just pretend CR was hit + quit_more = false; + got_int = false; + } else if (c != K_IGNORE) { + c = K_IGNORE; + hit_return_msg(false); + } + } else if (msg_scrolled > Rows - 2 + && (c == 'j' || c == 'd' || c == 'f' + || c == K_DOWN || c == K_PAGEDOWN)) { c = K_IGNORE; - hit_return_msg(false); } - } else if (msg_scrolled > Rows - 2 - && (c == 'j' || c == 'd' || c == 'f' - || c == K_DOWN || c == K_PAGEDOWN)) { - c = K_IGNORE; } + } while ((had_got_int && c == Ctrl_C) + || c == K_IGNORE + || c == K_LEFTDRAG || c == K_LEFTRELEASE + || c == K_MIDDLEDRAG || c == K_MIDDLERELEASE + || c == K_RIGHTDRAG || c == K_RIGHTRELEASE + || c == K_MOUSELEFT || c == K_MOUSERIGHT + || c == K_MOUSEDOWN || c == K_MOUSEUP + || c == K_MOUSEMOVE); + os_breakcheck(); + + // Avoid that the mouse-up event causes visual mode to start. + if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE + || c == K_X1MOUSE || c == K_X2MOUSE) { + jump_to_mouse(MOUSE_SETPOS, NULL, 0); + } else if (vim_strchr("\r\n ", c) == NULL && c != Ctrl_C) { + // Put the character back in the typeahead buffer. Don't use the + // stuff buffer, because lmaps wouldn't work. + ins_char_typebuf(vgetc_char, vgetc_mod_mask, true); + do_redraw = true; // need a redraw even though there is typeahead } - } while ((had_got_int && c == Ctrl_C) - || c == K_IGNORE - || c == K_LEFTDRAG || c == K_LEFTRELEASE - || c == K_MIDDLEDRAG || c == K_MIDDLERELEASE - || c == K_RIGHTDRAG || c == K_RIGHTRELEASE - || c == K_MOUSELEFT || c == K_MOUSERIGHT - || c == K_MOUSEDOWN || c == K_MOUSEUP - || c == K_MOUSEMOVE); - os_breakcheck(); - - // Avoid that the mouse-up event causes visual mode to start. - if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE - || c == K_X1MOUSE || c == K_X2MOUSE) { - jump_to_mouse(MOUSE_SETPOS, NULL, 0); - } else if (vim_strchr("\r\n ", c) == NULL && c != Ctrl_C) { - // Put the character back in the typeahead buffer. Don't use the - // stuff buffer, because lmaps wouldn't work. - ins_char_typebuf(vgetc_char, vgetc_mod_mask, true); - do_redraw = true; // need a redraw even though there is - // typeahead + } else { + c = CAR; + // Wait to allow the user to verify the output. + do_sleep(msg_wait, true); } } redir_off = false; diff --git a/src/nvim/normal.c b/src/nvim/normal.c index ba84380529..92a6068c5a 100644 --- a/src/nvim/normal.c +++ b/src/nvim/normal.c @@ -812,7 +812,7 @@ static void normal_get_additional_char(NormalState *s) // There is a busy wait here when typing "f<C-\>" and then // something different from CTRL-N. Can't be avoided. while ((s->c = vpeekc()) <= 0 && towait > 0) { - do_sleep(towait > 50 ? 50 : towait); + do_sleep(towait > 50 ? 50 : towait, false); towait -= 50; } if (s->c > 0) { @@ -5561,7 +5561,7 @@ static void nv_g_cmd(cmdarg_T *cap) // "gs": Goto sleep. case 's': - do_sleep(cap->count1 * 1000); + do_sleep(cap->count1 * 1000, false); break; // "ga": Display the ascii value of the character under the diff --git a/src/nvim/option.c b/src/nvim/option.c index fd0ac375a6..e261f06b42 100644 --- a/src/nvim/option.c +++ b/src/nvim/option.c @@ -2199,13 +2199,6 @@ static const char *did_set_modified(optset_T *args) return NULL; } -/// Process the updated 'msghistory' option value. -static const char *did_set_msghistory(optset_T *args FUNC_ATTR_UNUSED) -{ - check_msg_hist(); - return NULL; -} - /// Process the updated 'number' or 'relativenumber' option value. static const char *did_set_number_relativenumber(optset_T *args) { @@ -2886,13 +2879,6 @@ static const char *validate_num_option(OptIndex opt_idx, OptInt *newval, char *e return e_invarg; } break; - case kOptMsghistory: - if (value < 0) { - return e_positive; - } else if (value > 10000) { - return e_invarg; - } - break; case kOptPyxversion: if (value == 0) { *newval = 3; diff --git a/src/nvim/option_vars.h b/src/nvim/option_vars.h index 3bb2035e7c..aca876bddb 100644 --- a/src/nvim/option_vars.h +++ b/src/nvim/option_vars.h @@ -448,6 +448,7 @@ EXTERN OptInt p_mfd; ///< 'maxfuncdepth' EXTERN OptInt p_mmd; ///< 'maxmapdepth' EXTERN OptInt p_mmp; ///< 'maxmempattern' EXTERN OptInt p_mis; ///< 'menuitems' +EXTERN char *p_meo; ///< 'messagesopt' EXTERN char *p_msm; ///< 'mkspellmem' EXTERN int p_ml; ///< 'modeline' EXTERN int p_mle; ///< 'modelineexpr' @@ -464,7 +465,6 @@ EXTERN OptInt p_mousescroll_vert INIT( = MOUSESCROLL_VERT_DFLT); EXTERN OptInt p_mousescroll_hor INIT( = MOUSESCROLL_HOR_DFLT); EXTERN OptInt p_mouset; ///< 'mousetime' EXTERN int p_more; ///< 'more' -EXTERN OptInt p_mhi; ///< 'msghistory' EXTERN char *p_nf; ///< 'nrformats' EXTERN char *p_opfunc; ///< 'operatorfunc' EXTERN char *p_para; ///< 'paragraphs' diff --git a/src/nvim/options.lua b/src/nvim/options.lua index 97fe09f376..a5d5a45b59 100644 --- a/src/nvim/options.lua +++ b/src/nvim/options.lua @@ -4094,7 +4094,7 @@ return { desc = [=[ A history of ":" commands, and a history of previous search patterns is remembered. This option decides how many entries may be stored in - each of these histories (see |cmdline-editing| and 'msghistory' for + each of these histories (see |cmdline-editing| and 'messagesopt' for the number of messages to remember). The maximum value is 10000. ]=], @@ -5449,6 +5449,38 @@ return { varname = 'p_mis', }, { + abbreviation = 'mopt', + cb = 'did_set_messagesopt', + defaults = { if_true = 'hit-enter,history:500' }, + values = { 'hit-enter', 'wait:', 'history:' }, + flags = true, + deny_duplicates = true, + desc = [=[ + Option settings when outputting messages. It can consist of the + following items. Items must be separated by a comma. + + hit-enter Use |hit-enter| prompt when the message is longer than + 'cmdheight' size. + + wait:{n} Ignored when "hit-enter" is present. Instead of using + |hit-enter| prompt, will simply wait for {n} + milliseconds so the user has a chance to read the + message, use 0 to disable sleep (but then the user may + miss an important message). + + history:{n} Determines how many entries are remembered in the + |:messages| history. The maximum value is 10000. + Setting it to zero clears the message history. + ]=], + expand_cb = 'expand_set_messagesopt', + full_name = 'messagesopt', + list = 'onecommacolon', + scope = { 'global' }, + short_desc = N_('options for outputting messages'), + type = 'string', + varname = 'p_meo', + }, + { abbreviation = 'msm', cb = 'did_set_mkspellmem', defaults = { if_true = '460000,2000,500' }, @@ -5893,21 +5925,6 @@ return { varname = 'p_mouset', }, { - abbreviation = 'mhi', - cb = 'did_set_msghistory', - defaults = { if_true = 500 }, - desc = [=[ - Determines how many entries are remembered in the |:messages| history. - The maximum value is 10000. - Setting it to zero clears the message history. - ]=], - full_name = 'msghistory', - scope = { 'global' }, - short_desc = N_('how many messages are remembered'), - type = 'number', - varname = 'p_mhi', - }, - { abbreviation = 'nf', cb = 'did_set_nrformats', defaults = { if_true = 'bin,hex' }, diff --git a/src/nvim/optionstr.c b/src/nvim/optionstr.c index 918443db9f..75b6585553 100644 --- a/src/nvim/optionstr.c +++ b/src/nvim/optionstr.c @@ -1682,6 +1682,24 @@ const char *did_set_matchpairs(optset_T *args) return NULL; } +/// Process the updated 'messagesopt' option value. +const char *did_set_messagesopt(optset_T *args FUNC_ATTR_UNUSED) +{ + if (messagesopt_changed() == FAIL) { + return e_invarg; + } + return NULL; +} + +int expand_set_messagesopt(optexpand_T *args, int *numMatches, char ***matches) +{ + return expand_set_opt_string(args, + opt_mopt_values, + ARRAY_SIZE(opt_mopt_values) - 1, + numMatches, + matches); +} + /// The 'mkspellmem' option is changed. const char *did_set_mkspellmem(optset_T *args FUNC_ATTR_UNUSED) { |