From 7f2e43c637e56055831898b0f63a27ec1c3ca026 Mon Sep 17 00:00:00 2001 From: Alexandre Dubray Date: Mon, 5 Feb 2018 12:34:10 +0100 Subject: message.c: add msg_echo_attr functions, use it for lua error messages The added function behaves like the non-echo function but display message in a echo-style way (i.e. tab and newline are preserved) --- src/nvim/lua/executor.c | 2 +- src/nvim/message.c | 156 +++++++++++++++++++++++++++++++++++++++--------- 2 files changed, 130 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index a7bda9d037..bc81df4c0b 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -50,7 +50,7 @@ static void nlua_error(lua_State *const lstate, const char *const msg) size_t len; const char *const str = lua_tolstring(lstate, -1, &len); - emsgf(msg, (int)len, str); + emsgf_echo(msg, (int)len, str); lua_pop(lstate, 1); } diff --git a/src/nvim/message.c b/src/nvim/message.c index 37e40c3cc1..7544048434 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -54,6 +54,8 @@ struct msgchunk_S { char_u sb_text[1]; /* text to be displayed, actually longer */ }; +typedef int (*FuncMsgAttr)(const char *s, const int attr); + /* Magic chars used in confirm dialog strings */ #define DLG_BUTTON_SEP '\n' #define DLG_HOTKEY_CHAR '&' @@ -132,31 +134,29 @@ int verb_msg(char_u *s) return n; } -int msg_attr(const char *s, const int attr) FUNC_ATTR_NONNULL_ARG(1) +int msg_attr(const char *s, const int attr) + FUNC_ATTR_NONNULL_ARG(1) { return msg_attr_keep((char_u *)s, attr, false); } -int -msg_attr_keep ( - char_u *s, - int attr, - int keep /* TRUE: set keep_msg if it doesn't scroll */ -) - FUNC_ATTR_NONNULL_ARG(1) +int msg_echo_attr(const char *s, const int attr) + FUNC_ATTR_NONNULL_ALL { - static int entered = 0; - int retval; - char_u *buf = NULL; + return msg_echo_attr_keep(s, attr, false); +} +bool msg_attr_skip(const char *s, const int attr, int *const call) + FUNC_ATTR_NONNULL_ALL +{ // Skip messages not match ":filter pattern". // Don't filter when there is an error. - if (!emsg_on_display && message_filtered(s)) { + if (!emsg_on_display && message_filtered((char_u *)s)) { return true; } if (attr == 0) { - set_vim_var_string(VV_STATUSMSG, (char *) s, -1); + set_vim_var_string(VV_STATUSMSG, s, -1); } /* @@ -164,9 +164,86 @@ msg_attr_keep ( * when redrawing the window), which causes another message, etc.. To * break this loop, limit the recursiveness to 3 levels. */ - if (entered >= 3) - return TRUE; - ++entered; + if (*call >= 3) { + return true; + } + + (*call)++; + + return false; +} + + +bool msg_echo_attr_keep(const char *s, const int attr, const int keep) + FUNC_ATTR_NONNULL_ALL +{ + static int entered = 0; + + if (msg_attr_skip(s, attr, &entered)) { + return true; + } + + msg_start(); + + char *const buf = (char *)msg_strtrunc((char_u *)s, false); + if (buf != NULL) { + s = buf; + } + + const char *next_spec = s; + + while (next_spec != NULL) { + next_spec = strpbrk(s, "\t\n\r"); + + if (next_spec != NULL) { + // Printing all char that are before the char found by strpbrk + msg_outtrans_len_attr((char_u *)s, next_spec - s, attr); + + if (*next_spec != TAB) { + msg_clr_eos(); + } + msg_putchar_attr((uint8_t)(*next_spec), attr); + s = next_spec + 1; + } + } + + // Print the rest of the message. We know there is no special + // character because strpbrk returned NULL + if (*s != NUL) { + msg_outtrans_attr((char_u *)s, attr); + } + + msg_clr_eos(); + const bool retval = msg_end(); + + if (keep && retval && vim_strsize((char_u *)s) < (int)(Rows - cmdline_row -1) + * Columns + sc_col) { + set_keep_msg((char_u *)s, 0); + } + + xfree((void *)buf); + entered--; + return retval; +} + + +int +msg_attr_keep ( + char_u *s, + int attr, + int keep /* TRUE: set keep_msg if it doesn't scroll */ +) + FUNC_ATTR_NONNULL_ARG(1) +{ + static int entered = 0; + + if (msg_attr_skip((const char *)s, attr, &entered)) { + return true; + } + + int retval; + char_u *buf = NULL; + /* Add message to history (unless it's a repeated kept message or a * truncated message) */ @@ -468,17 +545,8 @@ int emsg_not_now(void) return FALSE; } -/* - * emsg() - display an error message - * - * Rings the bell, if appropriate, and calls message() to do the real work - * When terminal not initialized (yet) mch_errmsg(..) is used. - * - * return TRUE if wait_return not called - */ -int emsg(const char_u *s_) +static int _emsg(const char *s, FuncMsgAttr display_msg) { - const char *s = (const char *)s_; int attr; int ignore = false; int severe; @@ -573,7 +641,20 @@ int emsg(const char_u *s_) // Display the error message itself. msg_nowait = false; // Wait for this msg. - return msg_attr(s, attr); + return display_msg(s, attr); +} + +/* + * emsg() - display an error message + * + * Rings the bell, if appropriate, and calls message() to do the real work + * When terminal not initialized (yet) mch_errmsg(..) is used. + * + * return TRUE if wait_return not called + */ +int emsg(const char_u *s) +{ + return _emsg((const char *)s, &msg_attr); } void emsg_invreg(int name) @@ -595,6 +676,27 @@ bool emsgf(const char *const fmt, ...) return ret; } +bool emsgf_echo(const char *const fmt, ...) +{ + bool ret; + va_list ap; + + va_start(ap, fmt); + + static char errbuf[IOSIZE]; + if (emsg_not_now()) { + return true; + } + + vim_vsnprintf(errbuf, sizeof(errbuf), fmt, ap, NULL); + + FuncMsgAttr f = &msg_echo_attr; + ret = _emsg(errbuf, f); + va_end(ap); + + return ret; +} + /// Print an error message with unknown number of arguments static bool emsgfv(const char *fmt, va_list ap) { -- cgit From 67bac681ea6b38b458ad0b7b10f2a9dce85baef0 Mon Sep 17 00:00:00 2001 From: Alexandre Dubray Date: Sat, 17 Feb 2018 22:31:24 +0100 Subject: ex_echo: reuse code from message.c to show arg to user --- src/nvim/eval.c | 19 +------------------ src/nvim/message.c | 35 ++++++++++++++++++++--------------- 2 files changed, 21 insertions(+), 33 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 596eff5b79..3a18a9492f 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19593,24 +19593,7 @@ void ex_echo(exarg_T *eap) msg_puts_attr(" ", echo_attr); } char *tofree = encode_tv2echo(&rettv, NULL); - const char *p = tofree; - if (p != NULL) { - for (; *p != NUL && !got_int; ++p) { - if (*p == '\n' || *p == '\r' || *p == TAB) { - if (*p != TAB && needclr) { - /* remove any text still there from the command */ - msg_clr_eos(); - needclr = false; - } - msg_putchar_attr((uint8_t)(*p), echo_attr); - } else { - int i = (*mb_ptr2len)((const char_u *)p); - - (void)msg_outtrans_len_attr((char_u *)p, i, echo_attr); - p += i - 1; - } - } - } + msg_echo_show(tofree, echo_attr); xfree(tofree); } tv_clear(&rettv); diff --git a/src/nvim/message.c b/src/nvim/message.c index 7544048434..feb894e4ea 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -173,23 +173,9 @@ bool msg_attr_skip(const char *s, const int attr, int *const call) return false; } - -bool msg_echo_attr_keep(const char *s, const int attr, const int keep) +void msg_echo_show(const char *s, int attr) FUNC_ATTR_NONNULL_ALL { - static int entered = 0; - - if (msg_attr_skip(s, attr, &entered)) { - return true; - } - - msg_start(); - - char *const buf = (char *)msg_strtrunc((char_u *)s, false); - if (buf != NULL) { - s = buf; - } - const char *next_spec = s; while (next_spec != NULL) { @@ -212,6 +198,25 @@ bool msg_echo_attr_keep(const char *s, const int attr, const int keep) if (*s != NUL) { msg_outtrans_attr((char_u *)s, attr); } +} + +bool msg_echo_attr_keep(const char *s, const int attr, const int keep) + FUNC_ATTR_NONNULL_ALL +{ + static int entered = 0; + + if (msg_attr_skip(s, attr, &entered)) { + return true; + } + + msg_start(); + + char *const buf = (char *)msg_strtrunc((char_u *)s, false); + if (buf != NULL) { + s = buf; + } + + msg_echo_show(s, attr); msg_clr_eos(); const bool retval = msg_end(); -- cgit From 27b78130252be59416f0ce29111e59a2de99b93e Mon Sep 17 00:00:00 2001 From: Björn Linse Date: Fri, 18 Jan 2019 12:16:58 +0100 Subject: cleanup: reduce some duplicate code, avoid function pointers for a condition Add 'multiline' flag to history for correct :messages output Use larger buffer size for multiline messages. if this turns out to not be enough, we could do size calculation like api_set_error --- src/nvim/eval.c | 2 +- src/nvim/lua/executor.c | 2 +- src/nvim/message.c | 172 ++++++++++++++++++------------------------------ src/nvim/message.h | 1 + src/nvim/quickfix.c | 2 +- 5 files changed, 69 insertions(+), 110 deletions(-) (limited to 'src') diff --git a/src/nvim/eval.c b/src/nvim/eval.c index 3a18a9492f..1c6fb5d2f8 100644 --- a/src/nvim/eval.c +++ b/src/nvim/eval.c @@ -19593,7 +19593,7 @@ void ex_echo(exarg_T *eap) msg_puts_attr(" ", echo_attr); } char *tofree = encode_tv2echo(&rettv, NULL); - msg_echo_show(tofree, echo_attr); + msg_multiline_attr(tofree, echo_attr); xfree(tofree); } tv_clear(&rettv); diff --git a/src/nvim/lua/executor.c b/src/nvim/lua/executor.c index bc81df4c0b..93069893cf 100644 --- a/src/nvim/lua/executor.c +++ b/src/nvim/lua/executor.c @@ -50,7 +50,7 @@ static void nlua_error(lua_State *const lstate, const char *const msg) size_t len; const char *const str = lua_tolstring(lstate, -1, &len); - emsgf_echo(msg, (int)len, str); + emsgf_multiline(msg, (int)len, str); lua_pop(lstate, 1); } diff --git a/src/nvim/message.c b/src/nvim/message.c index feb894e4ea..0f8ff74b12 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -54,8 +54,6 @@ struct msgchunk_S { char_u sb_text[1]; /* text to be displayed, actually longer */ }; -typedef int (*FuncMsgAttr)(const char *s, const int attr); - /* Magic chars used in confirm dialog strings */ #define DLG_BUTTON_SEP '\n' #define DLG_HOTKEY_CHAR '&' @@ -117,7 +115,7 @@ static int verbose_did_open = FALSE; */ int msg(char_u *s) { - return msg_attr_keep(s, 0, FALSE); + return msg_attr_keep(s, 0, false, false); } /* @@ -128,7 +126,7 @@ int verb_msg(char_u *s) int n; verbose_enter(); - n = msg_attr_keep(s, 0, FALSE); + n = msg_attr_keep(s, 0, false, false); verbose_leave(); return n; @@ -137,43 +135,11 @@ int verb_msg(char_u *s) int msg_attr(const char *s, const int attr) FUNC_ATTR_NONNULL_ARG(1) { - return msg_attr_keep((char_u *)s, attr, false); -} - -int msg_echo_attr(const char *s, const int attr) - FUNC_ATTR_NONNULL_ALL -{ - return msg_echo_attr_keep(s, attr, false); + return msg_attr_keep((char_u *)s, attr, false, false); } -bool msg_attr_skip(const char *s, const int attr, int *const call) - FUNC_ATTR_NONNULL_ALL -{ - // Skip messages not match ":filter pattern". - // Don't filter when there is an error. - if (!emsg_on_display && message_filtered((char_u *)s)) { - return true; - } - - if (attr == 0) { - set_vim_var_string(VV_STATUSMSG, s, -1); - } - - /* - * It is possible that displaying a messages causes a problem (e.g., - * when redrawing the window), which causes another message, etc.. To - * break this loop, limit the recursiveness to 3 levels. - */ - if (*call >= 3) { - return true; - } - - (*call)++; - - return false; -} - -void msg_echo_show(const char *s, int attr) +/// similar to msg_outtrans_attr, but support newlines and tabs. +void msg_multiline_attr(const char *s, int attr) FUNC_ATTR_NONNULL_ALL { const char *next_spec = s; @@ -200,55 +166,40 @@ void msg_echo_show(const char *s, int attr) } } -bool msg_echo_attr_keep(const char *s, const int attr, const int keep) + +/// @param keep set keep_msg if it doesn't scroll +bool msg_attr_keep(char_u *s, int attr, bool keep, bool multiline) FUNC_ATTR_NONNULL_ALL { static int entered = 0; + int retval; + char_u *buf = NULL; - if (msg_attr_skip(s, attr, &entered)) { - return true; - } - - msg_start(); - - char *const buf = (char *)msg_strtrunc((char_u *)s, false); - if (buf != NULL) { - s = buf; - } - - msg_echo_show(s, attr); - - msg_clr_eos(); - const bool retval = msg_end(); - - if (keep && retval && vim_strsize((char_u *)s) < (int)(Rows - cmdline_row -1) - * Columns + sc_col) { - set_keep_msg((char_u *)s, 0); + if (keep && multiline) { + // Not implemented. 'multiline' is only used by nvim-added messages, + // which should avoid 'keep' behavior (just show the message at + // the correct time already). + abort(); } - xfree((void *)buf); - entered--; - return retval; -} - - -int -msg_attr_keep ( - char_u *s, - int attr, - int keep /* TRUE: set keep_msg if it doesn't scroll */ -) - FUNC_ATTR_NONNULL_ARG(1) -{ - static int entered = 0; - - if (msg_attr_skip((const char *)s, attr, &entered)) { + // Skip messages not match ":filter pattern". + // Don't filter when there is an error. + if (!emsg_on_display && message_filtered(s)) { return true; } - int retval; - char_u *buf = NULL; + if (attr == 0) { + set_vim_var_string(VV_STATUSMSG, (char *) s, -1); + } + /* + * It is possible that displaying a messages causes a problem (e.g., + * when redrawing the window), which causes another message, etc.. To + * break this loop, limit the recursiveness to 3 levels. + */ + if (entered >= 3) + return TRUE; + ++entered; /* Add message to history (unless it's a repeated kept message or a * truncated message) */ @@ -257,7 +208,7 @@ msg_attr_keep ( && last_msg_hist != NULL && last_msg_hist->msg != NULL && STRCMP(s, last_msg_hist->msg))) { - add_msg_hist((const char *)s, -1, attr); + add_msg_hist((const char *)s, -1, attr, multiline); } /* When displaying keep_msg, don't let msg_start() free it, caller must do @@ -271,13 +222,18 @@ msg_attr_keep ( if (buf != NULL) s = buf; - msg_outtrans_attr(s, attr); + if (multiline) { + msg_multiline_attr((char *)s, attr); + } else { + msg_outtrans_attr(s, attr); + } msg_clr_eos(); retval = msg_end(); if (keep && retval && vim_strsize(s) < (int)(Rows - cmdline_row - 1) - * Columns + sc_col) + * Columns + sc_col) { set_keep_msg(s, 0); + } xfree(buf); --entered; @@ -550,7 +506,7 @@ int emsg_not_now(void) return FALSE; } -static int _emsg(const char *s, FuncMsgAttr display_msg) +static bool emsg_multiline(const char *s, bool multiline) { int attr; int ignore = false; @@ -646,20 +602,18 @@ static int _emsg(const char *s, FuncMsgAttr display_msg) // Display the error message itself. msg_nowait = false; // Wait for this msg. - return display_msg(s, attr); + return msg_attr_keep((char_u *)s, attr, false, multiline); } -/* - * emsg() - display an error message - * - * Rings the bell, if appropriate, and calls message() to do the real work - * When terminal not initialized (yet) mch_errmsg(..) is used. - * - * return TRUE if wait_return not called - */ -int emsg(const char_u *s) +/// emsg() - display an error message +/// +/// Rings the bell, if appropriate, and calls message() to do the real work +/// When terminal not initialized (yet) mch_errmsg(..) is used. +/// +/// @return true if wait_return not called +bool emsg(const char_u *s) { - return _emsg((const char *)s, &msg_attr); + return emsg_multiline((const char *)s, false); } void emsg_invreg(int name) @@ -681,24 +635,25 @@ bool emsgf(const char *const fmt, ...) return ret; } -bool emsgf_echo(const char *const fmt, ...) +#define MULTILINE_BUFSIZE 8192 + +bool emsgf_multiline(const char *const fmt, ...) { bool ret; va_list ap; - va_start(ap, fmt); - static char errbuf[IOSIZE]; + static char errbuf[MULTILINE_BUFSIZE]; if (emsg_not_now()) { return true; } + va_start(ap, fmt); vim_vsnprintf(errbuf, sizeof(errbuf), fmt, ap, NULL); - - FuncMsgAttr f = &msg_echo_attr; - ret = _emsg(errbuf, f); va_end(ap); + ret = emsg_multiline(errbuf, true); + return ret; } @@ -776,7 +731,7 @@ char_u *msg_trunc_attr(char_u *s, int force, int attr) int n; // Add message to history before truncating. - add_msg_hist((const char *)s, -1, attr); + add_msg_hist((const char *)s, -1, attr, false); s = msg_may_trunc(force, s); @@ -822,7 +777,7 @@ char_u *msg_may_trunc(int force, char_u *s) } /// @param[in] len Length of s or -1. -static void add_msg_hist(const char *s, int len, int attr) +static void add_msg_hist(const char *s, int len, int attr, bool multiline) { if (msg_hist_off || msg_silent != 0) return; @@ -846,12 +801,15 @@ static void add_msg_hist(const char *s, int len, int attr) p->msg = (char_u *)xmemdupz(s, (size_t)len); p->next = NULL; p->attr = attr; - if (last_msg_hist != NULL) + p->multiline = multiline; + if (last_msg_hist != NULL) { last_msg_hist->next = p; + } last_msg_hist = p; - if (first_msg_hist == NULL) + if (first_msg_hist == NULL) { first_msg_hist = last_msg_hist; - ++msg_hist_len; + } + msg_hist_len++; } /* @@ -918,7 +876,7 @@ void ex_messages(void *const eap_p) // Display what was not skipped. for (; p != NULL && !got_int; p = p->next) { if (p->msg != NULL) { - msg_attr((const char *)p->msg, p->attr); + msg_attr_keep(p->msg, p->attr, false, p->multiline); } } @@ -1312,7 +1270,7 @@ int msg_outtrans_len_attr(char_u *msgstr, int len, int attr) /* if MSG_HIST flag set, add message to history */ if (attr & MSG_HIST) { - add_msg_hist(str, len, attr); + add_msg_hist(str, len, attr, false); attr &= ~MSG_HIST; } @@ -1750,7 +1708,7 @@ void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr) // if MSG_HIST flag set, add message to history if (attr & MSG_HIST) { - add_msg_hist(str, (int)len, attr); + add_msg_hist(str, (int)len, attr, false); attr &= ~MSG_HIST; } diff --git a/src/nvim/message.h b/src/nvim/message.h index 82935a36a9..41d2945b9c 100644 --- a/src/nvim/message.h +++ b/src/nvim/message.h @@ -78,6 +78,7 @@ typedef struct msg_hist { struct msg_hist *next; ///< Next message. char_u *msg; ///< Message text. int attr; ///< Message highlighting. + bool multiline; ///< Multiline message. } MessageHistoryEntry; /// First message diff --git a/src/nvim/quickfix.c b/src/nvim/quickfix.c index 4eeddf1d5a..200995bbeb 100644 --- a/src/nvim/quickfix.c +++ b/src/nvim/quickfix.c @@ -2155,7 +2155,7 @@ win_found: } else if (!msg_scrolled && shortmess(SHM_OVERALL)) { msg_scroll = false; } - msg_attr_keep(IObuff, 0, true); + msg_attr_keep(IObuff, 0, true, false); msg_scroll = (int)i; } } else { -- cgit