aboutsummaryrefslogtreecommitdiff
path: root/src/nvim/message.c
diff options
context:
space:
mode:
authorJosh Rahm <joshuarahm@gmail.com>2023-11-29 21:52:58 +0000
committerJosh Rahm <joshuarahm@gmail.com>2023-11-29 21:52:58 +0000
commit931bffbda3668ddc609fc1da8f9eb576b170aa52 (patch)
treed8c1843a95da5ea0bb4acc09f7e37843d9995c86 /src/nvim/message.c
parent142d9041391780ac15b89886a54015fdc5c73995 (diff)
parent4a8bf24ac690004aedf5540fa440e788459e5e34 (diff)
downloadrneovim-931bffbda3668ddc609fc1da8f9eb576b170aa52.tar.gz
rneovim-931bffbda3668ddc609fc1da8f9eb576b170aa52.tar.bz2
rneovim-931bffbda3668ddc609fc1da8f9eb576b170aa52.zip
Merge remote-tracking branch 'upstream/master' into userreguserreg
Diffstat (limited to 'src/nvim/message.c')
-rw-r--r--src/nvim/message.c825
1 files changed, 365 insertions, 460 deletions
diff --git a/src/nvim/message.c b/src/nvim/message.c
index 7f29b19031..3268ff389a 100644
--- a/src/nvim/message.c
+++ b/src/nvim/message.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
-
// message.c: functions for displaying messages on the command line
#include <assert.h>
@@ -11,22 +8,23 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
#include "nvim/api/private/helpers.h"
-#include "nvim/ascii.h"
+#include "nvim/ascii_defs.h"
#include "nvim/buffer_defs.h"
#include "nvim/channel.h"
#include "nvim/charset.h"
#include "nvim/drawscreen.h"
#include "nvim/eval.h"
#include "nvim/eval/typval.h"
-#include "nvim/eval/typval_defs.h"
#include "nvim/event/defs.h"
#include "nvim/event/loop.h"
#include "nvim/event/multiqueue.h"
#include "nvim/ex_cmds_defs.h"
#include "nvim/ex_eval.h"
#include "nvim/fileio.h"
+#include "nvim/func_attr.h"
#include "nvim/garray.h"
#include "nvim/getchar.h"
#include "nvim/gettext.h"
@@ -44,16 +42,20 @@
#include "nvim/mouse.h"
#include "nvim/ops.h"
#include "nvim/option.h"
+#include "nvim/option_vars.h"
+#include "nvim/os/fs.h"
#include "nvim/os/input.h"
#include "nvim/os/os.h"
-#include "nvim/pos.h"
+#include "nvim/os/time.h"
+#include "nvim/pos_defs.h"
#include "nvim/regexp.h"
#include "nvim/runtime.h"
-#include "nvim/screen.h"
+#include "nvim/state_defs.h"
#include "nvim/strings.h"
+#include "nvim/types_defs.h"
#include "nvim/ui.h"
#include "nvim/ui_compositor.h"
-#include "nvim/vim.h"
+#include "nvim/vim_defs.h"
// To be able to scroll back at the "more" and "hit-enter" prompts we need to
// store the displayed text and remember where screen lines start.
@@ -64,7 +66,7 @@ struct msgchunk_S {
char sb_eol; // true when line ends after this text
int sb_msg_col; // column in which text starts
int sb_attr; // text attributes
- char sb_text[1]; // text to be displayed, actually longer
+ char sb_text[]; // text to be displayed
};
// Magic chars used in confirm dialog strings
@@ -142,7 +144,7 @@ static int msg_grid_pos_at_flush = 0;
static void ui_ext_msg_set_pos(int row, bool scrolled)
{
- char buf[MAX_MCO + 1];
+ char buf[MB_MAXCHAR + 1];
size_t size = (size_t)utf_char2bytes(curwin->w_p_fcs_chars.msgsep, buf);
buf[size] = '\0';
ui_call_msg_set_pos(msg_grid.handle, row, scrolled,
@@ -182,7 +184,7 @@ void msg_grid_validate(void)
msg_grid.dirty_col = xcalloc((size_t)Rows, sizeof(*msg_grid.dirty_col));
// Tricky: allow resize while pager or ex mode is active
- int pos = MAX(max_rows - msg_scrolled, 0);
+ int pos = (State & MODE_ASKMORE) ? 0 : MAX(max_rows - msg_scrolled, 0);
msg_grid.throttled = false; // don't throttle in 'cmdheight' area
msg_grid_set_pos(pos, msg_scrolled);
ui_comp_put_grid(&msg_grid, pos, 0, msg_grid.rows, msg_grid.cols,
@@ -213,17 +215,8 @@ void msg_grid_validate(void)
}
}
-/// Displays the string 's' on the status line
-/// When terminal not initialized (yet) os_errmsg(..) is used.
-///
-/// @return true if wait_return() not called
-int msg(char *s)
-{
- return msg_attr_keep(s, 0, false, false);
-}
-
/// Like msg() but keep it silent when 'verbosefile' is set.
-int verb_msg(char *s)
+int verb_msg(const char *s)
{
verbose_enter();
int n = msg_attr_keep(s, 0, false, false);
@@ -232,14 +225,18 @@ int verb_msg(char *s)
return n;
}
-int msg_attr(const char *s, const int attr)
+/// Displays the string 's' on the status line
+/// When terminal not initialized (yet) os_errmsg(..) is used.
+///
+/// @return true if wait_return() not called
+int msg(const char *s, const int attr)
FUNC_ATTR_NONNULL_ARG(1)
{
return msg_attr_keep(s, attr, false, false);
}
-/// Similar to msg_outtrans_attr, but support newlines and tabs.
-void msg_multiline_attr(const char *s, int attr, bool check_int, bool *need_clear)
+/// Similar to msg_outtrans, but support newlines and tabs.
+void msg_multiline(const char *s, int attr, bool check_int, bool *need_clear)
FUNC_ATTR_NONNULL_ALL
{
const char *next_spec = s;
@@ -252,7 +249,7 @@ void msg_multiline_attr(const char *s, int attr, bool check_int, bool *need_clea
if (next_spec != NULL) {
// Printing all char that are before the char found by strpbrk
- msg_outtrans_len_attr(s, (int)(next_spec - s), attr);
+ msg_outtrans_len(s, (int)(next_spec - s), attr);
if (*next_spec != TAB && *need_clear) {
msg_clr_eos();
@@ -266,7 +263,7 @@ void msg_multiline_attr(const char *s, int attr, bool check_int, bool *need_clea
// Print the rest of the message. We know there is no special
// character because strpbrk returned NULL
if (*s != NUL) {
- msg_outtrans_attr(s, attr);
+ msg_outtrans(s, attr);
}
}
@@ -279,8 +276,7 @@ void msg_multiattr(HlMessage hl_msg, const char *kind, bool history)
msg_ext_set_kind(kind);
for (uint32_t i = 0; i < kv_size(hl_msg); i++) {
HlMessageChunk chunk = kv_A(hl_msg, i);
- msg_multiline_attr((const char *)chunk.text.data, chunk.attr,
- true, &need_clear);
+ msg_multiline(chunk.text.data, chunk.attr, true, &need_clear);
}
if (history && kv_size(hl_msg)) {
add_msg_hist_multiattr(NULL, 0, 0, true, hl_msg);
@@ -294,7 +290,6 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
FUNC_ATTR_NONNULL_ALL
{
static int entered = 0;
- int retval;
char *buf = NULL;
if (keep && multiline) {
@@ -306,7 +301,7 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
// Skip messages not match ":filter pattern".
// Don't filter when there is an error.
- if (!emsg_on_display && message_filtered((char *)s)) {
+ if (!emsg_on_display && message_filtered(s)) {
return true;
}
@@ -334,24 +329,24 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
// Truncate the message if needed.
msg_start();
- buf = msg_strtrunc((char *)s, false);
+ buf = msg_strtrunc(s, false);
if (buf != NULL) {
s = buf;
}
bool need_clear = true;
if (multiline) {
- msg_multiline_attr(s, attr, false, &need_clear);
+ msg_multiline(s, attr, false, &need_clear);
} else {
- msg_outtrans_attr(s, attr);
+ msg_outtrans(s, attr);
}
if (need_clear) {
msg_clr_eos();
}
- retval = msg_end();
+ int retval = msg_end();
- if (keep && retval && vim_strsize((char *)s) < (Rows - cmdline_row - 1) * Columns + sc_col) {
- set_keep_msg((char *)s, 0);
+ if (keep && retval && vim_strsize(s) < (Rows - cmdline_row - 1) * Columns + sc_col) {
+ set_keep_msg(s, 0);
}
need_fileinfo = false;
@@ -366,17 +361,16 @@ bool msg_attr_keep(const char *s, int attr, bool keep, bool multiline)
/// @return an allocated string or NULL when no truncating is done.
///
/// @param force always truncate
-char *msg_strtrunc(char *s, int force)
+char *msg_strtrunc(const char *s, int force)
{
char *buf = NULL;
- int len;
- int room;
// May truncate message to avoid a hit-return prompt
if ((!msg_scroll && !need_wait_return && shortmess(SHM_TRUNCALL)
&& !exmode_active && msg_silent == 0 && !ui_has(kUIMessages))
|| force) {
- len = vim_strsize(s);
+ int room;
+ int len = vim_strsize(s);
if (msg_scrolled != 0) {
// Use all the columns.
room = (Rows - msg_row) * Columns - 1;
@@ -397,10 +391,9 @@ char *msg_strtrunc(char *s, int force)
/// Truncate a string "s" to "buf" with cell width "room".
/// "s" and "buf" may be equal.
-void trunc_string(char *s, char *buf, int room_in, int buflen)
+void trunc_string(const char *s, char *buf, int room_in, int buflen)
{
int room = room_in - 3; // "..." takes 3 chars
- int half;
int len = 0;
int e;
int i;
@@ -416,7 +409,7 @@ void trunc_string(char *s, char *buf, int room_in, int buflen)
if (room_in < 3) {
room = 0;
}
- half = room / 2;
+ int half = room / 2;
// First part: Start of the string.
for (e = 0; len < half && e < buflen; e++) {
@@ -441,7 +434,7 @@ void trunc_string(char *s, char *buf, int room_in, int buflen)
// Last part: End of the string.
half = i = (int)strlen(s);
- for (;;) {
+ while (true) {
do {
half = half - utf_head_off(s, s + half - 1) - 1;
} while (half > 0 && utf_iscomposing(utf_ptr2char(s + half)));
@@ -478,26 +471,19 @@ void trunc_string(char *s, char *buf, int room_in, int buflen)
buf[e + 3 + len - 1] = NUL;
} else {
// can't fit in the "...", just truncate it
- buf[e - 1] = NUL;
+ buf[buflen - 1] = NUL;
}
}
-// Note: Caller of smsg() and smsg_attr() must check the resulting string is
-// shorter than IOSIZE!!!
-
-int smsg(const char *s, ...)
- FUNC_ATTR_PRINTF(1, 2)
-{
- va_list arglist;
-
- va_start(arglist, s);
- vim_vsnprintf(IObuff, IOSIZE, s, arglist);
- va_end(arglist);
-
- return msg(IObuff);
-}
-
-int smsg_attr(int attr, const char *s, ...)
+/// Shows a printf-style message with attributes.
+///
+/// Note: Caller must check the resulting string is shorter than IOSIZE!!!
+///
+/// @see semsg
+/// @see swmsg
+///
+/// @param s printf-style format message
+int smsg(int attr, const char *s, ...)
FUNC_ATTR_PRINTF(2, 3)
{
va_list arglist;
@@ -505,7 +491,7 @@ int smsg_attr(int attr, const char *s, ...)
va_start(arglist, s);
vim_vsnprintf(IObuff, IOSIZE, s, arglist);
va_end(arglist);
- return msg_attr((const char *)IObuff, attr);
+ return msg(IObuff, attr);
}
int smsg_attr_keep(int attr, const char *s, ...)
@@ -516,7 +502,7 @@ int smsg_attr_keep(int attr, const char *s, ...)
va_start(arglist, s);
vim_vsnprintf(IObuff, IOSIZE, s, arglist);
va_end(arglist);
- return msg_attr_keep((const char *)IObuff, attr, true, false);
+ return msg_attr_keep(IObuff, attr, true, false);
}
// Remember the last sourcing name/lnum used in an error message, so that it
@@ -581,10 +567,10 @@ static char *get_emsg_lnum(void)
if (SOURCING_NAME != NULL
&& (other_sourcing_name() || SOURCING_LNUM != last_sourcing_lnum)
&& SOURCING_LNUM != 0) {
- const char *const p = _("line %4ld:");
+ const char *const p = _("line %4" PRIdLINENR ":");
const size_t buf_len = 20 + strlen(p);
char *const buf = xmalloc(buf_len);
- snprintf(buf, buf_len, p, (long)SOURCING_LNUM);
+ snprintf(buf, buf_len, p, SOURCING_LNUM);
return buf;
}
return NULL;
@@ -607,12 +593,12 @@ void msg_source(int attr)
char *p = get_emsg_source();
if (p != NULL) {
msg_scroll = true; // this will take more than one line
- msg_attr(p, attr);
+ msg(p, attr);
xfree(p);
}
p = get_emsg_lnum();
if (p != NULL) {
- msg_attr(p, HL_ATTR(HLF_N));
+ msg(p, HL_ATTR(HLF_N));
xfree(p);
last_sourcing_lnum = SOURCING_LNUM; // only once for each line
}
@@ -643,9 +629,8 @@ int emsg_not_now(void)
return false;
}
-static bool emsg_multiline(const char *s, bool multiline)
+bool emsg_multiline(const char *s, bool multiline)
{
- int attr;
bool ignore = false;
// Skip this if not giving error messages at the moment.
@@ -666,7 +651,7 @@ static bool emsg_multiline(const char *s, bool multiline)
// be found, the message will be displayed later on.) "ignore" is set
// when the message should be ignored completely (used for the
// interrupt message).
- if (cause_errthrow(s, severe, &ignore)) {
+ if (cause_errthrow(s, multiline, severe, &ignore)) {
if (!ignore) {
did_emsg++;
}
@@ -707,8 +692,8 @@ static bool emsg_multiline(const char *s, bool multiline)
// Log (silent) errors as debug messages.
if (SOURCING_NAME != NULL && SOURCING_LNUM != 0) {
- DLOG("(:silent) %s (%s (line %ld))",
- s, SOURCING_NAME, (long)SOURCING_LNUM);
+ DLOG("(:silent) %s (%s (line %" PRIdLINENR "))",
+ s, SOURCING_NAME, SOURCING_LNUM);
} else {
DLOG("(:silent) %s", s);
}
@@ -718,7 +703,7 @@ static bool emsg_multiline(const char *s, bool multiline)
// Log editor errors as INFO.
if (SOURCING_NAME != NULL && SOURCING_LNUM != 0) {
- ILOG("%s (%s (line %ld))", s, SOURCING_NAME, (long)SOURCING_LNUM);
+ ILOG("%s (%s (line %" PRIdLINENR "))", s, SOURCING_NAME, SOURCING_LNUM);
} else {
ILOG("%s", s);
}
@@ -742,7 +727,7 @@ static bool emsg_multiline(const char *s, bool multiline)
}
emsg_on_display = true; // remember there is an error message
- attr = HL_ATTR(HLF_E); // set highlight mode for error messages
+ int attr = HL_ATTR(HLF_E); // set highlight mode for error messages
if (msg_scrolled != 0) {
need_wait_return = true; // needed in case emsg() is called after
} // wait_return() has reset need_wait_return
@@ -774,10 +759,12 @@ bool emsg(const char *s)
void emsg_invreg(int name)
{
- semsg(_("E354: Invalid register name: '%s'"), transchar(name));
+ semsg(_("E354: Invalid register name: '%s'"), transchar_buf(NULL, name));
}
/// Print an error message with unknown number of arguments
+///
+/// @return whether the message was displayed
bool semsg(const char *const fmt, ...)
FUNC_ATTR_PRINTF(1, 2)
{
@@ -864,7 +851,7 @@ void siemsg(const char *s, ...)
}
/// Give an "Internal error" message.
-void internal_error(char *where)
+void internal_error(const char *where)
{
siemsg(_(e_intern2), where);
}
@@ -888,22 +875,38 @@ void msg_schedule_semsg(const char *const fmt, ...)
loop_schedule_deferred(&main_loop, event_create(msg_semsg_event, 1, s));
}
+static void msg_semsg_multiline_event(void **argv)
+{
+ char *s = argv[0];
+ (void)emsg_multiline(s, true);
+ xfree(s);
+}
+
+void msg_schedule_semsg_multiline(const char *const fmt, ...)
+{
+ va_list ap;
+ va_start(ap, fmt);
+ vim_vsnprintf(IObuff, IOSIZE, fmt, ap);
+ va_end(ap);
+
+ char *s = xstrdup(IObuff);
+ loop_schedule_deferred(&main_loop, event_create(msg_semsg_multiline_event, 1, s));
+}
+
/// Like msg(), but truncate to a single line if p_shm contains 't', or when
/// "force" is true. This truncates in another way as for normal messages.
/// Careful: The string may be changed by msg_may_trunc()!
///
/// @return a pointer to the printed message, if wait_return() not called.
-char *msg_trunc_attr(char *s, bool force, int attr)
+char *msg_trunc(char *s, bool force, int attr)
{
- int n;
-
// Add message to history before truncating.
add_msg_hist(s, -1, attr, false);
char *ts = msg_may_trunc(force, s);
msg_hist_off = true;
- n = msg_attr(ts, attr);
+ int n = msg(ts, attr);
msg_hist_off = false;
if (n) {
@@ -1009,12 +1012,10 @@ static void add_msg_hist_multiattr(const char *s, int len, int attr, bool multil
/// @return FAIL if there are no messages.
int delete_first_msg(void)
{
- struct msg_hist *p;
-
if (msg_hist_len <= 0) {
return FAIL;
}
- p = first_msg_hist;
+ struct msg_hist *p = first_msg_hist;
first_msg_hist = p->next;
if (first_msg_hist == NULL) { // history is becoming empty
assert(msg_hist_len == 1);
@@ -1028,13 +1029,9 @@ int delete_first_msg(void)
}
/// :messages command implementation
-void ex_messages(void *const eap_p)
+void ex_messages(exarg_T *eap)
FUNC_ATTR_NONNULL_ALL
{
- const exarg_T *const eap = (const exarg_T *)eap_p;
- struct msg_hist *p;
- int c = 0;
-
if (strcmp(eap->arg, "clear") == 0) {
int keep = eap->addr_count == 0 ? 0 : eap->line2;
@@ -1049,9 +1046,10 @@ void ex_messages(void *const eap_p)
return;
}
- p = first_msg_hist;
+ struct msg_hist *p = first_msg_hist;
if (eap->addr_count != 0) {
+ int c = 0;
// Count total messages
for (; p != NULL && !got_int; p = p->next) {
c++;
@@ -1072,7 +1070,7 @@ void ex_messages(void *const eap_p)
for (; p != NULL; p = p->next) {
if (kv_size(p->multiattr) || (p->msg && p->msg[0])) {
Array entry = ARRAY_DICT_INIT;
- ADD(entry, STRING_OBJ(cstr_to_string(p->kind)));
+ ADD(entry, CSTR_TO_OBJ(p->kind));
Array content = ARRAY_DICT_INIT;
if (kv_size(p->multiattr)) {
for (uint32_t i = 0; i < kv_size(p->multiattr); i++) {
@@ -1085,7 +1083,7 @@ void ex_messages(void *const eap_p)
} else if (p->msg && p->msg[0]) {
Array content_entry = ARRAY_DICT_INIT;
ADD(content_entry, INTEGER_OBJ(p->attr));
- ADD(content_entry, STRING_OBJ(cstr_to_string((char *)(p->msg))));
+ ADD(content_entry, CSTR_TO_OBJ(p->msg));
ADD(content, ARRAY_OBJ(content_entry));
}
ADD(entry, ARRAY_OBJ(content));
@@ -1130,8 +1128,6 @@ void msg_end_prompt(void)
void wait_return(int redraw)
{
int c;
- int oldState;
- int tmpState;
int had_got_int;
FILE *save_scriptout;
@@ -1165,7 +1161,7 @@ void wait_return(int redraw)
}
redir_off = true; // don't redirect this message
- oldState = State;
+ int oldState = State;
if (quit_more) {
c = CAR; // just pretend CR was hit
quit_more = false;
@@ -1226,9 +1222,7 @@ void wait_return(int redraw)
} else {
msg_didout = false;
c = K_IGNORE;
- msg_col =
- cmdmsg_rl ? Columns - 1 :
- 0;
+ msg_col = 0;
}
if (quit_more) {
c = CAR; // just pretend CR was hit
@@ -1253,6 +1247,7 @@ void wait_return(int redraw)
|| 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) {
@@ -1281,7 +1276,7 @@ void wait_return(int redraw)
// If the screen size changed screen_resize() will redraw the screen.
// Otherwise the screen is only redrawn if 'redraw' is set and no ':'
// typed.
- tmpState = State;
+ int tmpState = State;
State = oldState; // restore State before screen_resize()
setmouse();
msg_check();
@@ -1329,7 +1324,7 @@ static void hit_return_msg(void)
}
/// Set "keep_msg" to "s". Free the old value and check for NULL pointer.
-void set_keep_msg(char *s, int attr)
+void set_keep_msg(const char *s, int attr)
{
xfree(keep_msg);
if (s != NULL && msg_silent == 0) {
@@ -1341,9 +1336,17 @@ void set_keep_msg(char *s, int attr)
keep_msg_attr = attr;
}
-void msgmore(long n)
+/// Return true if printing messages should currently be done.
+bool messaging(void)
{
- long pn;
+ // TODO(bfredl): with general support for "async" messages with p_ch,
+ // this should be re-enabled.
+ return !(p_lz && char_avail() && !KeyTyped) && (p_ch > 0 || ui_has(kUIMessages));
+}
+
+void msgmore(int n)
+{
+ int pn;
if (global_busy // no messages now, wait until global is finished
|| !messaging()) { // 'lazyredraw' set, don't do messages now
@@ -1366,17 +1369,17 @@ void msgmore(long n)
if (pn > p_report) {
if (n > 0) {
vim_snprintf(msg_buf, MSG_BUF_LEN,
- NGETTEXT("%ld more line", "%ld more lines", pn),
+ NGETTEXT("%d more line", "%d more lines", pn),
pn);
} else {
vim_snprintf(msg_buf, MSG_BUF_LEN,
- NGETTEXT("%ld line less", "%ld fewer lines", pn),
+ NGETTEXT("%d line less", "%d fewer lines", pn),
pn);
}
if (got_int) {
xstrlcat(msg_buf, _(" (Interrupted)"), MSG_BUF_LEN);
}
- if (msg(msg_buf)) {
+ if (msg(msg_buf, 0)) {
set_keep_msg(msg_buf, 0);
keep_msg_more = true;
}
@@ -1397,7 +1400,11 @@ void msg_ext_set_kind(const char *msg_kind)
/// Prepare for outputting characters in the command line.
void msg_start(void)
{
- int did_return = false;
+ bool did_return = false;
+
+ if (msg_row < cmdline_row) {
+ msg_row = cmdline_row;
+ }
if (!msg_silent) {
XFREE_CLEAR(keep_msg); // don't display old message now
@@ -1421,7 +1428,7 @@ void msg_start(void)
if (!msg_scroll && full_screen) { // overwrite last message
msg_row = cmdline_row;
- msg_col = cmdmsg_rl ? Columns - 1 : 0;
+ msg_col = 0;
} else if (msg_didout || (p_ch == 0 && !ui_has(kUIMessages))) { // start message on next line
msg_putchar('\n');
did_return = true;
@@ -1462,7 +1469,7 @@ void msg_putchar(int c)
void msg_putchar_attr(int c, int attr)
{
- char buf[MB_MAXBYTES + 1];
+ char buf[MB_MAXCHAR + 1];
if (IS_SPECIAL(c)) {
buf[0] = (char)K_SPECIAL;
@@ -1470,33 +1477,33 @@ void msg_putchar_attr(int c, int attr)
buf[2] = (char)K_THIRD(c);
buf[3] = NUL;
} else {
- buf[utf_char2bytes(c, (char *)buf)] = NUL;
+ buf[utf_char2bytes(c, buf)] = NUL;
}
- msg_puts_attr((const char *)buf, attr);
+ msg_puts_attr(buf, attr);
}
-void msg_outnum(long n)
+void msg_outnum(int n)
{
char buf[20];
- snprintf(buf, sizeof(buf), "%ld", n);
+ snprintf(buf, sizeof(buf), "%d", n);
msg_puts(buf);
}
-void msg_home_replace(char *fname)
+void msg_home_replace(const char *fname)
{
msg_home_replace_attr(fname, 0);
}
-void msg_home_replace_hl(char *fname)
+void msg_home_replace_hl(const char *fname)
{
msg_home_replace_attr(fname, HL_ATTR(HLF_D));
}
-static void msg_home_replace_attr(char *fname, int attr)
+static void msg_home_replace_attr(const char *fname, int attr)
{
char *name = home_replace_save(NULL, fname);
- msg_outtrans_attr(name, attr);
+ msg_outtrans(name, attr);
xfree(name);
}
@@ -1505,44 +1512,33 @@ static void msg_home_replace_attr(char *fname, int attr)
/// Use attributes 'attr'.
///
/// @return the number of characters it takes on the screen.
-int msg_outtrans(char *str)
-{
- return msg_outtrans_attr(str, 0);
-}
-
-int msg_outtrans_attr(const char *str, int attr)
-{
- return msg_outtrans_len_attr(str, (int)strlen(str), attr);
-}
-
-int msg_outtrans_len(const char *str, int len)
+int msg_outtrans(const char *str, int attr)
{
- return msg_outtrans_len_attr(str, len, 0);
+ return msg_outtrans_len(str, (int)strlen(str), attr);
}
/// Output one character at "p".
/// Handles multi-byte characters.
///
/// @return pointer to the next character.
-char *msg_outtrans_one(char *p, int attr)
+const char *msg_outtrans_one(const char *p, int attr)
{
int l;
if ((l = utfc_ptr2len(p)) > 1) {
- msg_outtrans_len_attr(p, l, attr);
+ msg_outtrans_len(p, l, attr);
return p + l;
}
- msg_puts_attr((const char *)transchar_byte((uint8_t)(*p)), attr);
+ msg_puts_attr(transchar_byte_buf(NULL, (uint8_t)(*p)), attr);
return p + 1;
}
-int msg_outtrans_len_attr(const char *msgstr, int len, int attr)
+int msg_outtrans_len(const char *msgstr, int len, int attr)
{
int retval = 0;
const char *str = msgstr;
const char *plain_start = msgstr;
char *s;
- int mb_l;
int c;
int save_got_int = got_int;
@@ -1555,17 +1551,18 @@ int msg_outtrans_len_attr(const char *msgstr, int len, int attr)
attr &= ~MSG_HIST;
}
- // If the string starts with a composing character first draw a space on
- // which the composing char can be drawn.
- if (utf_iscomposing(utf_ptr2char((char *)msgstr))) {
- msg_puts_attr(" ", attr);
+ // When drawing over the command line no need to clear it later or remove
+ // the mode message.
+ if (msg_row >= cmdline_row && msg_col == 0) {
+ clear_cmdline = false;
+ mode_displayed = false;
}
// Go over the string. Special characters are translated and printed.
// Normal characters are printed several at a time.
while (--len >= 0 && !got_int) {
// Don't include composing chars after the end.
- mb_l = utfc_ptr2len_len(str, len + 1);
+ int mb_l = utfc_ptr2len_len(str, len + 1);
if (mb_l > 1) {
c = utf_ptr2char(str);
if (vim_isprintc(c)) {
@@ -1575,25 +1572,24 @@ int msg_outtrans_len_attr(const char *msgstr, int len, int attr)
// Unprintable multi-byte char: print the printable chars so
// far and the translation of the unprintable char.
if (str > plain_start) {
- msg_puts_attr_len(plain_start, str - plain_start, attr);
+ msg_puts_len(plain_start, str - plain_start, attr);
}
plain_start = str + mb_l;
- msg_puts_attr((const char *)transchar(c),
- (attr == 0 ? HL_ATTR(HLF_8) : attr));
+ msg_puts_attr(transchar_buf(NULL, c), attr == 0 ? HL_ATTR(HLF_8) : attr);
retval += char2cells(c);
}
len -= mb_l - 1;
str += mb_l;
} else {
- s = (char *)transchar_byte((uint8_t)(*str));
+ s = transchar_byte_buf(NULL, (uint8_t)(*str));
if (s[1] != NUL) {
// Unprintable char: print the printable chars so far and the
// translation of the unprintable char.
if (str > plain_start) {
- msg_puts_attr_len(plain_start, str - plain_start, attr);
+ msg_puts_len(plain_start, str - plain_start, attr);
}
plain_start = str + 1;
- msg_puts_attr((const char *)s, attr == 0 ? HL_ATTR(HLF_8) : attr);
+ msg_puts_attr(s, attr == 0 ? HL_ATTR(HLF_8) : attr);
retval += (int)strlen(s);
} else {
retval++;
@@ -1604,7 +1600,7 @@ int msg_outtrans_len_attr(const char *msgstr, int len, int attr)
if (str > plain_start && !got_int) {
// Print the printable chars at the end.
- msg_puts_attr_len(plain_start, str - plain_start, attr);
+ msg_puts_len(plain_start, str - plain_start, attr);
}
got_int |= save_got_int;
@@ -1612,11 +1608,11 @@ int msg_outtrans_len_attr(const char *msgstr, int len, int attr)
return retval;
}
-void msg_make(char *arg)
+void msg_make(const char *arg)
{
int i;
- static char *str = "eeffoc";
- static char *rs = "Plon#dqg#vxjduB";
+ static const char *str = "eeffoc";
+ static const char *rs = "Plon#dqg#vxjduB";
arg = skipwhite(arg);
for (i = 5; *arg && i >= 0; i--) {
@@ -1667,9 +1663,9 @@ int msg_outtrans_special(const char *strstart, bool from, int maxlen)
}
if (text[0] != NUL && text[1] == NUL) {
// single-byte character or illegal byte
- text = (char *)transchar_byte((uint8_t)text[0]);
+ text = transchar_byte_buf(NULL, (uint8_t)text[0]);
}
- const int len = vim_strsize((char *)text);
+ const int len = vim_strsize(text);
if (maxlen > 0 && retval + len >= maxlen) {
break;
}
@@ -1773,7 +1769,7 @@ const char *str2special(const char **const sp, const bool replace_spaces, const
|| c < ' '
|| (replace_spaces && c == ' ')
|| (replace_lt && c == '<')) {
- return (const char *)get_special_key_name(c, modifiers);
+ return get_special_key_name(c, modifiers);
}
buf[0] = (char)c;
buf[1] = NUL;
@@ -1802,20 +1798,20 @@ void str2specialbuf(const char *sp, char *buf, size_t len)
}
/// print line for :print or :list command
-void msg_prt_line(char *s, int list)
+void msg_prt_line(const char *s, int list)
{
int c;
int col = 0;
int n_extra = 0;
int c_extra = 0;
int c_final = 0;
- char *p_extra = NULL; // init to make SASC shut up
+ const char *p_extra = NULL; // init to make SASC shut up
int n;
int attr = 0;
- char *lead = NULL;
+ const char *lead = NULL;
bool in_multispace = false;
int multispace_pos = 0;
- char *trail = NULL;
+ const char *trail = NULL;
int l;
if (curwin->w_p_list) {
@@ -1878,10 +1874,13 @@ void msg_prt_line(char *s, int list)
continue;
} else {
attr = 0;
- c = (unsigned char)(*s++);
- in_multispace = c == ' ' && ((col > 0 && s[-2] == ' ') || *s == ' ');
- if (!in_multispace) {
- multispace_pos = 0;
+ c = (uint8_t)(*s++);
+ if (list) {
+ in_multispace = c == ' ' && (*s == ' '
+ || (col > 0 && s[-2] == ' '));
+ if (!in_multispace) {
+ multispace_pos = 0;
+ }
}
if (c == TAB && (!list || curwin->w_p_lcs_chars.tab1)) {
// tab amount depends on current column
@@ -1913,7 +1912,7 @@ void msg_prt_line(char *s, int list)
s--;
} else if (c != NUL && (n = byte2cells(c)) > 1) {
n_extra = n - 1;
- p_extra = (char *)transchar_byte(c);
+ p_extra = transchar_byte_buf(NULL, c);
c_extra = NUL;
c_final = NUL;
c = (unsigned char)(*p_extra++);
@@ -1921,7 +1920,7 @@ void msg_prt_line(char *s, int list)
// the same in plain text.
attr = HL_ATTR(HLF_0);
} else if (c == ' ') {
- if (list && lead != NULL && s <= lead && in_multispace
+ if (lead != NULL && s <= lead && in_multispace
&& curwin->w_p_lcs_chars.leadmultispace != NULL) {
c = curwin->w_p_lcs_chars.leadmultispace[multispace_pos++];
if (curwin->w_p_lcs_chars.leadmultispace[multispace_pos] == NUL) {
@@ -1934,7 +1933,7 @@ void msg_prt_line(char *s, int list)
} else if (trail != NULL && s > trail) {
c = curwin->w_p_lcs_chars.trail;
attr = HL_ATTR(HLF_0);
- } else if (list && in_multispace
+ } else if (in_multispace
&& curwin->w_p_lcs_chars.multispace != NULL) {
c = curwin->w_p_lcs_chars.multispace[multispace_pos++];
if (curwin->w_p_lcs_chars.multispace[multispace_pos] == NUL) {
@@ -1958,40 +1957,6 @@ void msg_prt_line(char *s, int list)
msg_clr_eos();
}
-/// Use grid_puts() to output one multi-byte character.
-///
-/// @return the pointer "s" advanced to the next character.
-static char *screen_puts_mbyte(char *s, int l, int attr)
-{
- int cw;
- attr = hl_combine_attr(HL_ATTR(HLF_MSG), attr);
-
- msg_didout = true; // remember that line is not empty
- cw = utf_ptr2cells(s);
- if (cw > 1
- && (cmdmsg_rl ? msg_col <= 1 : msg_col == Columns - 1)) {
- // Doesn't fit, print a highlighted '>' to fill it up.
- msg_screen_putchar('>', HL_ATTR(HLF_AT));
- return s;
- }
-
- grid_puts_len(&msg_grid_adj, s, l, msg_row, msg_col, attr);
- if (cmdmsg_rl) {
- msg_col -= cw;
- if (msg_col == 0) {
- msg_col = Columns;
- msg_row++;
- }
- } else {
- msg_col += cw;
- if (msg_col >= Columns) {
- msg_col = 0;
- msg_row++;
- }
- }
- return s + l;
-}
-
/// Output a string to the screen at position msg_row, msg_col.
/// Update msg_row and msg_col for the next message.
void msg_puts(const char *s)
@@ -2007,29 +1972,23 @@ void msg_puts_title(const char *s)
/// Show a message in such a way that it always fits in the line. Cut out a
/// part in the middle and replace it with "..." when necessary.
/// Does not handle multi-byte characters!
-void msg_outtrans_long_attr(char *longstr, int attr)
-{
- msg_outtrans_long_len_attr(longstr, (int)strlen(longstr), attr);
-}
-
-void msg_outtrans_long_len_attr(char *longstr, int len, int attr)
+void msg_outtrans_long(const char *longstr, int attr)
{
+ int len = (int)strlen(longstr);
int slen = len;
- int room;
-
- room = Columns - msg_col;
+ int room = Columns - msg_col;
if (len > room && room >= 20) {
slen = (room - 3) / 2;
- msg_outtrans_len_attr(longstr, slen, attr);
+ msg_outtrans_len(longstr, slen, attr);
msg_puts_attr("...", HL_ATTR(HLF_8));
}
- msg_outtrans_len_attr(longstr + len - slen, slen, attr);
+ msg_outtrans_len(longstr + len - slen, slen, attr);
}
/// Basic function for writing a message with highlight attributes.
void msg_puts_attr(const char *const s, const int attr)
{
- msg_puts_attr_len(s, -1, attr);
+ msg_puts_len(s, -1, attr);
}
/// Write a message with highlight attributes
@@ -2037,7 +1996,7 @@ void msg_puts_attr(const char *const s, const int attr)
/// @param[in] str NUL-terminated message string.
/// @param[in] len Length of the string or -1.
/// @param[in] attr Highlight attribute.
-void msg_puts_attr_len(const char *const str, const ptrdiff_t len, int attr)
+void msg_puts_len(const char *const str, const ptrdiff_t len, int attr)
FUNC_ATTR_NONNULL_ALL
{
assert(len < 0 || memchr(str, 0, (size_t)len) == NULL);
@@ -2113,7 +2072,7 @@ void msg_printf_attr(const int attr, const char *const fmt, ...)
va_end(ap);
msg_scroll = true;
- msg_puts_attr_len(msgbuf, (ptrdiff_t)len, attr);
+ msg_puts_len(msgbuf, (ptrdiff_t)len, attr);
}
static void msg_ext_emit_chunk(void)
@@ -2130,19 +2089,13 @@ static void msg_ext_emit_chunk(void)
ADD(msg_ext_chunks, ARRAY_OBJ(chunk));
}
-/// The display part of msg_puts_attr_len().
+/// The display part of msg_puts_len().
/// May be called recursively to display scroll-back text.
static void msg_puts_display(const char *str, int maxlen, int attr, int recurse)
{
const char *s = str;
- const char *t_s = str; // String from "t_s" to "s" is still todo.
- int t_col = 0; // Screen cells todo, 0 when "t_s" not used.
- int l;
- int cw;
- const char *sb_str = (char *)str;
+ const char *sb_str = str;
int sb_col = msg_col;
- int wrap;
- int did_last_char;
did_wait_return = false;
@@ -2152,197 +2105,175 @@ static void msg_puts_display(const char *str, int maxlen, int attr, int recurse)
msg_ext_last_attr = attr;
}
// Concat pieces with the same highlight
- size_t len = strnlen(str, (size_t)maxlen); // -V781
- ga_concat_len(&msg_ext_last_chunk, (char *)str, len);
+ size_t len = strnlen(str, (size_t)maxlen);
+ ga_concat_len(&msg_ext_last_chunk, str, len);
msg_ext_cur_len += len;
return;
}
+ int print_attr = hl_combine_attr(HL_ATTR(HLF_MSG), attr);
msg_grid_validate();
cmdline_was_last_drawn = redrawing_cmdline;
- while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) {
- // We are at the end of the screen line when:
- // - When outputting a newline.
- // - When outputting a character in the last column.
- if (!recurse && msg_row >= Rows - 1
- && (*s == '\n' || (cmdmsg_rl
- ? (msg_col <= 1
- || (*s == TAB && msg_col <= 7)
- || (utf_ptr2cells(s) > 1
- && msg_col <= 2))
- : ((*s != '\r' && msg_col + t_col >= Columns - 1)
- || (*s == TAB
- && msg_col + t_col >= ((Columns - 1) & ~7))
- || (utf_ptr2cells(s) > 1
- && msg_col + t_col >= Columns - 2))))) {
- // The screen is scrolled up when at the last row (some terminals
- // scroll automatically, some don't. To avoid problems we scroll
- // ourselves).
- if (t_col > 0) {
- // output postponed text
- t_puts(&t_col, t_s, s, attr);
- }
+ int msg_row_pending = -1;
- // When no more prompt and no more room, truncate here
+ while (true) {
+ if (msg_col >= Columns) {
+ if (p_more && !recurse) {
+ // Store text for scrolling back.
+ store_sb_text(&sb_str, s, attr, &sb_col, true);
+ }
if (msg_no_more && lines_left == 0) {
break;
}
- // Scroll the screen up one line.
- bool has_last_char = ((uint8_t)(*s) >= ' ' && !cmdmsg_rl);
- msg_scroll_up(!has_last_char, false);
+ msg_col = 0;
+ msg_row++;
+ msg_didout = false;
+ }
- msg_row = Rows - 2;
- if (msg_col >= Columns) { // can happen after screen resize
- msg_col = Columns - 1;
- }
+ if (msg_row >= Rows) {
+ msg_row = Rows - 1;
- // Display char in last column before showing more-prompt.
- if (has_last_char) {
- if (maxlen >= 0) {
- // Avoid including composing chars after the end.
- l = utfc_ptr2len_len(s, (int)((str + maxlen) - s));
- } else {
- l = utfc_ptr2len(s);
- }
- s = screen_puts_mbyte((char *)s, l, attr);
- did_last_char = true;
- } else {
- did_last_char = false;
+ // When no more prompt and no more room, truncate here
+ if (msg_no_more && lines_left == 0) {
+ break;
}
- // Tricky: if last cell will be written, delay the throttle until
- // after the first scroll. Otherwise we would need to keep track of it.
- if (has_last_char && msg_do_throttle()) {
- if (!msg_grid.throttled) {
- msg_grid_scroll_discount++;
+ if (!recurse) {
+ if (msg_row_pending >= 0) {
+ msg_line_flush();
+ msg_row_pending = -1;
}
- msg_grid.throttled = true;
- }
-
- if (p_more) {
- // Store text for scrolling back.
- store_sb_text((char **)&sb_str, (char *)s, attr, &sb_col, true);
- }
- inc_msg_scrolled();
- need_wait_return = true; // may need wait_return() in main()
- redraw_cmdline = true;
- if (cmdline_row > 0 && !exmode_active) {
- cmdline_row--;
- }
+ // Scroll the screen up one line.
+ msg_scroll_up(true, false);
- // If screen is completely filled and 'more' is set then wait
- // for a character.
- if (lines_left > 0) {
- lines_left--;
- }
- if (p_more && lines_left == 0 && State != MODE_HITRETURN
- && !msg_no_more && !exmode_active) {
- if (do_more_prompt(NUL)) {
- s = confirm_msg_tail;
+ inc_msg_scrolled();
+ need_wait_return = true; // may need wait_return() in main()
+ redraw_cmdline = true;
+ if (cmdline_row > 0 && !exmode_active) {
+ cmdline_row--;
}
- if (quit_more) {
- return;
+
+ // If screen is completely filled and 'more' is set then wait
+ // for a character.
+ if (lines_left > 0) {
+ lines_left--;
}
- }
- // When we displayed a char in last column need to check if there
- // is still more.
- if (did_last_char) {
- continue;
+ if (p_more && lines_left == 0 && State != MODE_HITRETURN
+ && !msg_no_more && !exmode_active) {
+ if (do_more_prompt(NUL)) {
+ s = confirm_msg_tail;
+ }
+ if (quit_more) {
+ return;
+ }
+ }
}
}
- wrap = *s == '\n'
- || msg_col + t_col >= Columns
- || (utf_ptr2cells(s) > 1
- && msg_col + t_col >= Columns - 1)
- ;
- if (t_col > 0 && (wrap || *s == '\r' || *s == '\b'
- || *s == '\t' || *s == BELL)) {
- // Output any postponed text.
- t_puts(&t_col, t_s, s, attr);
+ if (!((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL)) {
+ break;
}
- if (wrap && p_more && !recurse) {
- // Store text for scrolling back.
- store_sb_text((char **)&sb_str, (char *)s, attr, &sb_col, true);
+ if (msg_row != msg_row_pending && ((uint8_t)(*s) >= 0x20 || *s == TAB)) {
+ // TODO(bfredl): this logic is messier that it has to be. What
+ // messages really want is its own private linebuf_char buffer.
+ if (msg_row_pending >= 0) {
+ msg_line_flush();
+ }
+ grid_line_start(&msg_grid_adj, msg_row);
+ msg_row_pending = msg_row;
}
- if (*s == '\n') { // go to next line
- msg_didout = false; // remember that line is empty
- if (cmdmsg_rl) {
- msg_col = Columns - 1;
- } else {
- msg_col = 0;
- }
- if (++msg_row >= Rows) { // safety check
- msg_row = Rows - 1;
- }
- } else if (*s == '\r') { // go to column 0
- msg_col = 0;
- } else if (*s == '\b') { // go to previous char
- if (msg_col) {
- msg_col--;
- }
- } else if (*s == TAB) { // translate Tab into spaces
- do {
- msg_screen_putchar(' ', attr);
- } while (msg_col & 7);
- } else if (*s == BELL) { // beep (from ":sh")
- vim_beep(BO_SH);
- } else if ((uint8_t)(*s) >= 0x20) { // printable char
- cw = utf_ptr2cells(s);
- if (maxlen >= 0) {
- // avoid including composing chars after the end
- l = utfc_ptr2len_len(s, (int)((str + maxlen) - s));
+ if ((uint8_t)(*s) >= 0x20) { // printable char
+ int cw = utf_ptr2cells(s);
+ // avoid including composing chars after the end
+ int l = (maxlen >= 0) ? utfc_ptr2len_len(s, (int)((str + maxlen) - s)) : utfc_ptr2len(s);
+
+ if (cw > 1 && (msg_col == Columns - 1)) {
+ // Doesn't fit, print a highlighted '>' to fill it up.
+ grid_line_puts(msg_col, ">", 1, HL_ATTR(HLF_AT));
+ cw = 1;
} else {
- l = utfc_ptr2len(s);
+ grid_line_puts(msg_col, s, l, print_attr);
+ s += l;
}
- // When drawing from right to left or when a double-wide character
- // doesn't fit, draw a single character here. Otherwise collect
- // characters and draw them all at once later.
- if (cmdmsg_rl || (cw > 1 && msg_col + t_col >= Columns - 1)) {
- if (l > 1) {
- s = screen_puts_mbyte((char *)s, l, attr) - 1;
- } else {
- msg_screen_putchar(*s, attr);
+ msg_didout = true; // remember that line is not empty
+ msg_col += cw;
+ } else {
+ char c = *s++;
+ if (c == '\n') { // go to next line
+ msg_didout = false; // remember that line is empty
+ msg_col = 0;
+ msg_row++;
+ if (p_more && !recurse) {
+ // Store text for scrolling back.
+ store_sb_text(&sb_str, s, attr, &sb_col, true);
}
- } else {
- // postpone this character until later
- if (t_col == 0) {
- t_s = s;
+ } else if (c == '\r') { // go to column 0
+ msg_col = 0;
+ } else if (c == '\b') { // go to previous char
+ if (msg_col) {
+ msg_col--;
}
- t_col += cw;
- s += l - 1;
+ } else if (c == TAB) { // translate Tab into spaces
+ do {
+ grid_line_puts(msg_col, " ", 1, print_attr);
+ msg_col += 1;
+
+ if (msg_col == Columns) {
+ break;
+ }
+ } while (msg_col & 7);
+ } else if (c == BELL) { // beep (from ":sh")
+ vim_beep(BO_SH);
}
}
- s++;
}
- // Output any postponed text.
- if (t_col > 0) {
- t_puts(&t_col, t_s, s, attr);
+ if (msg_row_pending >= 0) {
+ msg_line_flush();
}
+ msg_cursor_goto(msg_row, msg_col);
+
if (p_more && !recurse && !(s == sb_str + 1 && *sb_str == '\n')) {
- store_sb_text((char **)&sb_str, (char *)s, attr, &sb_col, false);
+ store_sb_text(&sb_str, s, attr, &sb_col, false);
}
msg_check();
}
+void msg_line_flush(void)
+{
+ if (cmdmsg_rl) {
+ grid_line_mirror();
+ }
+ grid_line_flush_if_valid_row();
+}
+
+void msg_cursor_goto(int row, int col)
+{
+ ScreenGrid *grid = &msg_grid_adj;
+ if (cmdmsg_rl) {
+ col = Columns - 1 - col;
+ }
+ grid_adjust(&grid, &row, &col);
+ ui_grid_cursor_goto(grid->handle, row, col);
+}
+
/// @return true when ":filter pattern" was used and "msg" does not match
/// "pattern".
-bool message_filtered(char *msg)
+bool message_filtered(const char *msg)
{
if (cmdmod.cmod_filter_regmatch.regprog == NULL) {
return false;
}
- bool match = vim_regexec(&cmdmod.cmod_filter_regmatch, msg, (colnr_T)0);
+ bool match = vim_regexec(&cmdmod.cmod_filter_regmatch, msg, 0);
return cmdmod.cmod_filter_force ? match : !match;
}
@@ -2502,7 +2433,7 @@ static sb_clear_T do_clear_sb_text = SB_CLEAR_NONE;
/// @param sb_str start of string
/// @param s just after string
/// @param finish line ends
-static void store_sb_text(char **sb_str, char *s, int attr, int *sb_col, int finish)
+static void store_sb_text(const char **sb_str, const char *s, int attr, int *sb_col, int finish)
{
msgchunk_T *mp;
@@ -2510,11 +2441,14 @@ static void store_sb_text(char **sb_str, char *s, int attr, int *sb_col, int fin
|| do_clear_sb_text == SB_CLEAR_CMDLINE_DONE) {
clear_sb_text(do_clear_sb_text == SB_CLEAR_ALL);
msg_sb_eol(); // prevent messages from overlapping
+ if (do_clear_sb_text == SB_CLEAR_CMDLINE_DONE && s > *sb_str && **sb_str == '\n') {
+ (*sb_str)++;
+ }
do_clear_sb_text = SB_CLEAR_NONE;
}
if (s > *sb_str) {
- mp = xmalloc((sizeof(msgchunk_T) + (size_t)(s - *sb_str)));
+ mp = xmalloc(offsetof(msgchunk_T, sb_text) + (size_t)(s - *sb_str) + 1);
mp->sb_eol = (char)finish;
mp->sb_msg_col = *sb_col;
mp->sb_attr = attr;
@@ -2652,15 +2586,11 @@ void msg_sb_eol(void)
static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp)
{
msgchunk_T *mp = smp;
- char *p;
- for (;;) {
+ while (true) {
msg_row = row;
msg_col = mp->sb_msg_col;
- p = mp->sb_text;
- if (*p == '\n') { // don't display the line break
- p++;
- }
+ char *p = mp->sb_text;
msg_puts_display(p, -1, mp->sb_attr, true);
if (mp->sb_eol || mp->sb_next == NULL) {
break;
@@ -2671,26 +2601,6 @@ static msgchunk_T *disp_sb_line(int row, msgchunk_T *smp)
return mp->sb_next;
}
-/// Output any postponed text for msg_puts_attr_len().
-static void t_puts(int *t_col, const char *t_s, const char *s, int attr)
-{
- attr = hl_combine_attr(HL_ATTR(HLF_MSG), attr);
- // Output postponed text.
- msg_didout = true; // Remember that line is not empty.
- grid_puts_len(&msg_grid_adj, (char *)t_s, (int)(s - t_s), msg_row, msg_col, attr);
- msg_col += *t_col;
- *t_col = 0;
- // If the string starts with a composing character don't increment the
- // column position for it.
- if (utf_iscomposing(utf_ptr2char(t_s))) {
- msg_col--;
- }
- if (msg_col >= Columns) {
- msg_col = 0;
- msg_row++;
- }
-}
-
/// @return true when messages should be printed to stdout/stderr:
/// - "batch mode" ("silent mode", -es/-Es)
/// - no UI and not embedded
@@ -2736,18 +2646,10 @@ static void msg_puts_printf(const char *str, const ptrdiff_t maxlen)
int cw = utf_char2cells(utf_ptr2char(s));
// primitive way to compute the current column
- if (cmdmsg_rl) {
- if (*s == '\r' || *s == '\n') {
- msg_col = Columns - 1;
- } else {
- msg_col -= cw;
- }
+ if (*s == '\r' || *s == '\n') {
+ msg_col = 0;
} else {
- if (*s == '\r' || *s == '\n') {
- msg_col = 0;
- } else {
- msg_col += cw;
- }
+ msg_col += cw;
}
s += len;
}
@@ -2767,11 +2669,9 @@ static int do_more_prompt(int typed_char)
int oldState = State;
int c;
int retval = false;
- int toscroll;
bool to_redraw = false;
msgchunk_T *mp_last = NULL;
msgchunk_T *mp;
- int i;
// If headless mode is enabled and no input is required, this variable
// will be true. However If server mode is enabled, the message "--more--"
@@ -2789,7 +2689,7 @@ static int do_more_prompt(int typed_char)
if (typed_char == 'G') {
// "g<": Find first line on the last page.
mp_last = msg_sb_start(last_msgchunk);
- for (i = 0; i < Rows - 2 && mp_last != NULL
+ for (int i = 0; i < Rows - 2 && mp_last != NULL
&& mp_last->sb_prev != NULL; i++) {
mp_last = msg_sb_start(mp_last->sb_prev);
}
@@ -2800,7 +2700,7 @@ static int do_more_prompt(int typed_char)
if (typed_char == NUL) {
msg_moremsg(false);
}
- for (;;) {
+ while (true) {
// Get a typed character directly from the user.
if (used_typed_char != NUL) {
c = used_typed_char; // was typed at hit-enter prompt
@@ -2809,7 +2709,7 @@ static int do_more_prompt(int typed_char)
c = get_keystroke(resize_events);
}
- toscroll = 0;
+ int toscroll = 0;
switch (c) {
case BS: // scroll one line back
case K_BS:
@@ -2907,13 +2807,13 @@ static int do_more_prompt(int typed_char)
}
// go to start of line at top of the screen
- for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL; i++) {
+ for (int i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL; i++) {
mp = msg_sb_start(mp->sb_prev);
}
if (mp != NULL && (mp->sb_prev != NULL || to_redraw)) {
// Find line to be displayed at top
- for (i = 0; i > toscroll; i--) {
+ for (int i = 0; i > toscroll; i--) {
if (mp == NULL || mp->sb_prev == NULL) {
break;
}
@@ -2937,7 +2837,7 @@ static int do_more_prompt(int typed_char)
// event fragmentization, not unnecessary scroll events).
grid_fill(&msg_grid_adj, 0, Rows, 0, Columns, ' ', ' ',
HL_ATTR(HLF_MSG));
- for (i = 0; mp != NULL && i < Rows - 1; i++) {
+ for (int i = 0; mp != NULL && i < Rows - 1; i++) {
mp = disp_sb_line(i, mp);
msg_scrolled++;
}
@@ -2996,8 +2896,6 @@ static int do_more_prompt(int typed_char)
if (quit_more) {
msg_row = Rows - 1;
msg_col = 0;
- } else if (cmdmsg_rl) {
- msg_col = Columns - 1;
}
entered = false;
@@ -3038,37 +2936,17 @@ void os_msg(const char *str)
}
#endif // MSWIN
-/// Put a character on the screen at the current message position and advance
-/// to the next position. Only for printable ASCII!
-static void msg_screen_putchar(int c, int attr)
-{
- attr = hl_combine_attr(HL_ATTR(HLF_MSG), attr);
- msg_didout = true; // remember that line is not empty
- grid_putchar(&msg_grid_adj, c, msg_row, msg_col, attr);
- if (cmdmsg_rl) {
- if (--msg_col == 0) {
- msg_col = Columns;
- msg_row++;
- }
- } else {
- if (++msg_col >= Columns) {
- msg_col = 0;
- msg_row++;
- }
- }
-}
-
void msg_moremsg(int full)
{
- int attr;
- char *s = _("-- More --");
-
- attr = hl_combine_attr(HL_ATTR(HLF_MSG), HL_ATTR(HLF_M));
- grid_puts(&msg_grid_adj, s, Rows - 1, 0, attr);
+ int attr = hl_combine_attr(HL_ATTR(HLF_MSG), HL_ATTR(HLF_M));
+ grid_line_start(&msg_grid_adj, Rows - 1);
+ int len = grid_line_puts(0, _("-- More --"), -1, attr);
if (full) {
- grid_puts(&msg_grid_adj, _(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "),
- Rows - 1, vim_strsize(s), attr);
+ len += grid_line_puts(len, _(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "),
+ -1, attr);
}
+ grid_line_cursor_goto(len);
+ grid_line_flush();
}
/// Repeat the message for the current mode: MODE_ASKMORE, MODE_EXTERNCMD,
@@ -3115,12 +2993,15 @@ void msg_clr_eos_force(void)
return;
}
int msg_startcol = (cmdmsg_rl) ? 0 : msg_col;
- int msg_endcol = (cmdmsg_rl) ? msg_col + 1 : Columns;
+ int msg_endcol = (cmdmsg_rl) ? Columns - msg_col : Columns;
+ // TODO(bfredl): ugly, this state should already been validated at this
+ // point. But msg_clr_eos() is called in a lot of places.
if (msg_grid.chars && msg_row < msg_grid_pos) {
- // TODO(bfredl): ugly, this state should already been validated at this
- // point. But msg_clr_eos() is called in a lot of places.
- msg_row = msg_grid_pos;
+ msg_grid_validate();
+ if (msg_row < msg_grid_pos) {
+ msg_row = msg_grid_pos;
+ }
}
grid_fill(&msg_grid_adj, msg_row, msg_row + 1, msg_startcol, msg_endcol,
@@ -3129,7 +3010,7 @@ void msg_clr_eos_force(void)
' ', ' ', HL_ATTR(HLF_MSG));
redraw_cmdline = true; // overwritten the command line
- if (msg_row < Rows - 1 || msg_col == (cmdmsg_rl ? Columns : 0)) {
+ if (msg_row < Rows - 1 || msg_col == 0) {
clear_cmdline = false; // command line has been cleared
mode_displayed = false; // mode cleared or overwritten
}
@@ -3305,7 +3186,7 @@ static void redir_write(const char *const str, const ptrdiff_t maxlen)
write_reg_contents(redir_reg, s, (ssize_t)len, true);
}
if (redir_vname) {
- var_redir_str((char *)s, (int)maxlen);
+ var_redir_str(s, (int)maxlen);
}
// Write and adjust the current column.
@@ -3414,7 +3295,7 @@ int verbose_open(void)
/// Give a warning message (for searching).
/// Use 'w' highlighting and may repeat the message after redrawing
-void give_warning(char *message, bool hl)
+void give_warning(const char *message, bool hl)
FUNC_ATTR_NONNULL_ARG(1)
{
// Don't do this for ":silent".
@@ -3437,7 +3318,7 @@ void give_warning(char *message, bool hl)
msg_ext_set_kind("wmsg");
}
- if (msg_attr((const char *)message, keep_msg_attr) && msg_scrolled == 0) {
+ if (msg(message, keep_msg_attr) && msg_scrolled == 0) {
set_keep_msg(message, keep_msg_attr);
}
msg_didout = false; // Overwrite this message.
@@ -3447,9 +3328,22 @@ void give_warning(char *message, bool hl)
no_wait_return--;
}
-void give_warning2(char *const message, char *const a1, bool hl)
+/// Shows a warning, with optional highlighting.
+///
+/// @param hl enable highlighting
+/// @param fmt printf-style format message
+///
+/// @see smsg
+/// @see semsg
+void swmsg(bool hl, const char *const fmt, ...)
+ FUNC_ATTR_PRINTF(2, 3)
{
- vim_snprintf(IObuff, IOSIZE, message, a1);
+ va_list args;
+
+ va_start(args, fmt);
+ vim_vsnprintf(IObuff, IOSIZE, fmt, args);
+ va_end(args);
+
give_warning(IObuff, hl);
}
@@ -3471,14 +3365,8 @@ void msg_advance(int col)
if (col >= Columns) { // not enough room
col = Columns - 1;
}
- if (cmdmsg_rl) {
- while (msg_col > Columns - col) {
- msg_putchar(' ');
- }
- } else {
- while (msg_col < col) {
- msg_putchar(' ');
- }
+ while (msg_col < col) {
+ msg_putchar(' ');
}
}
@@ -3502,12 +3390,11 @@ void msg_advance(int col)
/// @param textfiel IObuff for inputdialog(), NULL otherwise
/// @param ex_cmd when true pressing : accepts default and starts Ex command
/// @returns 0 if cancelled, otherwise the nth button (1-indexed).
-int do_dialog(int type, char *title, char *message, char *buttons, int dfltbutton, char *textfield,
- int ex_cmd)
+int do_dialog(int type, const char *title, const char *message, const char *buttons, int dfltbutton,
+ const char *textfield, int ex_cmd)
{
int retval = 0;
char *hotkeys;
- int c;
int i;
if (silent_mode // No dialogs in silent mode ("ex -s")
@@ -3528,9 +3415,9 @@ int do_dialog(int type, char *title, char *message, char *buttons, int dfltbutto
no_wait_return++;
hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
- for (;;) {
+ while (true) {
// Get a typed character directly from the user.
- c = get_keystroke(NULL);
+ int c = get_keystroke(NULL);
switch (c) {
case CAR: // User accepts default option
case NL:
@@ -3611,7 +3498,7 @@ static int copy_char(const char *from, char *to, bool lowercase)
/// corresponding button has a hotkey
///
/// @return Pointer to memory allocated for storing hotkeys
-static char *console_dialog_alloc(const char *message, char *buttons, bool has_hotkey[])
+static char *console_dialog_alloc(const char *message, const char *buttons, bool has_hotkey[])
{
int lenhotkey = HOTK_LEN; // count first button
has_hotkey[0] = false;
@@ -3619,7 +3506,7 @@ static char *console_dialog_alloc(const char *message, char *buttons, bool has_h
// Compute the size of memory to allocate.
int len = 0;
int idx = 0;
- char *r = buttons;
+ const char *r = buttons;
while (*r) {
if (*r == DLG_BUTTON_SEP) {
len += 3; // '\n' -> ', '; 'x' -> '(x)'
@@ -3665,7 +3552,7 @@ static char *console_dialog_alloc(const char *message, char *buttons, bool has_h
/// The hotkeys can be multi-byte characters, but without combining chars.
///
/// @return an allocated string with hotkeys.
-static char *msg_show_console_dialog(char *message, char *buttons, int dfltbutton)
+static char *msg_show_console_dialog(const char *message, const char *buttons, int dfltbutton)
FUNC_ATTR_NONNULL_RET
{
bool has_hotkey[HAS_HOTKEY_LEN] = { false };
@@ -3685,7 +3572,7 @@ static char *msg_show_console_dialog(char *message, char *buttons, int dfltbutto
/// @param has_hotkey An element in this array is true if corresponding button
/// has a hotkey
/// @param[out] hotkeys_ptr Pointer to the memory location where hotkeys will be copied
-static void copy_hotkeys_and_msg(const char *message, char *buttons, int default_button_idx,
+static void copy_hotkeys_and_msg(const char *message, const char *buttons, int default_button_idx,
const bool has_hotkey[], char *hotkeys_ptr)
{
*confirm_msg = '\n';
@@ -3708,7 +3595,7 @@ static void copy_hotkeys_and_msg(const char *message, char *buttons, int default
}
int idx = 0;
- char *r = buttons;
+ const char *r = buttons;
while (*r) {
if (*r == DLG_BUTTON_SEP) {
*msgp++ = ',';
@@ -3812,3 +3699,21 @@ int vim_dialog_yesnoallcancel(int type, char *title, char *message, int dflt)
}
return VIM_CANCEL;
}
+
+/// Check if there should be a delay to allow the user to see a message.
+///
+/// Used before clearing or redrawing the screen or the command line.
+void msg_check_for_delay(bool check_msg_scroll)
+{
+ if ((emsg_on_display || (check_msg_scroll && msg_scroll))
+ && !did_wait_return
+ && emsg_silent == 0
+ && !in_assert_fails) {
+ ui_flush();
+ os_delay(1006, true);
+ emsg_on_display = false;
+ if (check_msg_scroll) {
+ msg_scroll = false;
+ }
+ }
+}