aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cjson/lua_cjson.c121
-rw-r--r--src/nvim/api/autocmd.c6
-rw-r--r--src/nvim/autocmd.c6
-rw-r--r--src/nvim/autocmd_defs.h1
-rw-r--r--src/nvim/edit.c2
-rw-r--r--src/nvim/ex_docmd.c14
-rw-r--r--src/nvim/generators/gen_options.lua6
-rw-r--r--src/nvim/insexpand.c34
-rw-r--r--src/nvim/message.c221
-rw-r--r--src/nvim/normal.c4
-rw-r--r--src/nvim/option.c14
-rw-r--r--src/nvim/option_vars.h2
-rw-r--r--src/nvim/options.lua49
-rw-r--r--src/nvim/optionstr.c18
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)
{