📄 message.c
字号:
/* vi:set ts=8 sts=4 sw=4:
*
* VIM - Vi IMproved by Bram Moolenaar
*
* Do ":help uganda" in Vim to read copying and usage conditions.
* Do ":help credits" in Vim to see a list of people who contributed.
*/
/*
* message.c: functions for displaying messages on the command line
*/
#define MESSAGE_FILE /* don't include prototype for smsg() */
#include "vim.h"
#ifdef __QNX__
# include <stdarg.h>
#endif
static void msg_home_replace_attr __ARGS((char_u *fname, int attr));
static int msg_use_printf __ARGS((void));
static void msg_screen_putchar __ARGS((int c, int attr));
static int msg_check_screen __ARGS((void));
static void redir_write __ARGS((char_u *s));
#ifdef CON_DIALOG
static char_u *msg_show_console_dialog __ARGS((char_u *message, char_u *buttons, int dfltbutton));
#endif
/*
* msg(s) - displays the string 's' on the status line
* When terminal not initialized (yet) mch_errmsg(..) is used.
* return TRUE if wait_return not called
*/
int
msg(s)
char_u *s;
{
return msg_attr(s, 0);
}
int
msg_attr(s, attr)
char_u *s;
int attr;
{
static int entered = 0;
int retval;
/*
* 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;
msg_start();
msg_outtrans_attr(s, attr);
msg_clr_eos();
retval = msg_end();
--entered;
return retval;
}
/*
* automatic prototype generation does not understand this function
*/
#ifndef PROTO
# ifndef __QNX__
int
#ifdef __BORLANDC__
_RTLENTRYF
#endif
smsg __ARGS((char_u *, long, long, long,
long, long, long, long, long, long, long));
int
#ifdef __BORLANDC__
_RTLENTRYF
#endif
smsg_attr __ARGS((int, char_u *, long, long, long,
long, long, long, long, long, long, long));
/* VARARGS */
int
#ifdef __BORLANDC__
_RTLENTRYF
#endif
smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
char_u *s;
long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
{
return smsg_attr(0, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
}
/* VARARGS */
int
#ifdef __BORLANDC__
_RTLENTRYF
#endif
smsg_attr(attr, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
int attr;
char_u *s;
long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
{
sprintf((char *)IObuff, (char *)s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
return msg_attr(IObuff, attr);
}
# else /* __QNX__ */
int smsg(char_u *s, ...)
{
va_list arglist;
va_start(arglist, s);
vsprintf((char *)IObuff, (char *)s, arglist);
va_end(arglist);
return msg(IObuff);
}
int smsg_attr(int attr, char_u *s, ...)
{
va_list arglist;
va_start(arglist, s);
vsprintf((char *)IObuff, (char *)s, arglist);
va_end(arglist);
return msg_attr(IObuff, attr);
}
# endif /* __QNX__ */
#endif
/*
* 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(s)
char_u *s;
{
char_u *Buf;
static int last_lnum = 0;
static char_u *last_sourcing_name = NULL;
int attr;
int other_sourcing_name;
if (emsg_off) /* no error messages at the moment */
return TRUE;
if (global_busy) /* break :global command */
++global_busy;
if (p_eb)
beep_flush(); /* also includes flush_buffers() */
else
flush_buffers(FALSE); /* flush internal buffers */
did_emsg = TRUE; /* flag for DoOneCmd() */
emsg_on_display = TRUE; /* remember there is an error message */
++msg_scroll; /* don't overwrite a previous message */
attr = hl_attr(HLF_E); /* set highlight mode for error messages */
if (msg_scrolled)
need_wait_return = TRUE; /* needed in case emsg() is called after
* wait_return has reset need_wait_return
* and a redraw is expected because
* msg_scrolled is non-zero */
/*
* First output name and line number of source of error message
*/
if (sourcing_name != NULL)
{
if (last_sourcing_name != NULL)
other_sourcing_name = STRCMP(sourcing_name, last_sourcing_name);
else
other_sourcing_name = TRUE;
}
else
other_sourcing_name = FALSE;
if (sourcing_name != NULL
&& (other_sourcing_name || sourcing_lnum != last_lnum)
&& (Buf = alloc(MAXPATHL + 30)) != NULL)
{
++no_wait_return;
if (other_sourcing_name)
{
sprintf((char *)Buf, "Error detected while processing %s:",
sourcing_name);
msg_attr(Buf, attr);
}
/* lnum is 0 when executing a command from the command line
* argument, we don't want a line number then */
if (sourcing_lnum != 0)
{
sprintf((char *)Buf, "line %4ld:", sourcing_lnum);
msg_attr(Buf, hl_attr(HLF_N));
}
--no_wait_return;
last_lnum = sourcing_lnum; /* only once for each line */
vim_free(Buf);
}
/* remember the last sourcing name printed, also when it's empty */
if (sourcing_name == NULL || other_sourcing_name)
{
vim_free(last_sourcing_name);
if (sourcing_name == NULL)
last_sourcing_name = NULL;
else
last_sourcing_name = vim_strsave(sourcing_name);
}
msg_nowait = FALSE; /* wait for this msg */
#ifdef WANT_EVAL
set_internal_string_var((char_u *)"errmsg", s);
#endif
return msg_attr(s, attr);
}
int
emsg2(s, a1)
char_u *s, *a1;
{
if (emsg_off) /* no error messages at the moment */
return TRUE;
/* Check for NULL strings (just in case) */
if (a1 == NULL)
a1 = (char_u *)"[NULL]";
/* Check for very long strings (can happen with ":help ^A<CR>") */
if (STRLEN(s) + STRLEN(a1) >= (size_t)IOSIZE)
a1 = (char_u *)"[string too long]";
sprintf((char *)IObuff, (char *)s, (char *)a1);
return emsg(IObuff);
}
int
emsgn(s, n)
char_u *s;
long n;
{
if (emsg_off) /* no error messages at the moment */
return TRUE;
sprintf((char *)IObuff, (char *)s, n);
return emsg(IObuff);
}
/*
* Like msg(), but truncate to a single line if p_shm contains 't', or when
* "force" is TRUE.
* Careful: The string may be changed!
* Returns a pointer to the printed message, if wait_return() not called.
*/
char_u *
msg_trunc_attr(s, force, attr)
char_u *s;
int force;
int attr;
{
int n;
if ((force || shortmess(SHM_TRUNC)) && (n = (int)STRLEN(s) -
(int)(Rows - cmdline_row - 1) * Columns - sc_col + 1) > 0)
{
s += n;
*s = '<';
}
if (msg_attr(s, attr))
return s;
return NULL;
}
/*
* wait for the user to hit a key (normally a return)
* if 'redraw' is TRUE, clear and redraw the screen
* if 'redraw' is FALSE, just redraw the screen
* if 'redraw' is -1, don't redraw at all
*/
void
wait_return(redraw)
int redraw;
{
int c;
int oldState;
int tmpState;
if (redraw == TRUE)
must_redraw = CLEAR;
/*
* With the global command (and some others) we only need one return at the
* end. Adjust cmdline_row to avoid the next message overwriting the last one.
* When inside vgetc(), we can't wait for a typed character at all.
*/
if (vgetc_busy)
return;
if (no_wait_return)
{
need_wait_return = TRUE;
if (!exmode_active)
cmdline_row = msg_row;
return;
}
redir_off = TRUE; /* don't redirect this message */
oldState = State;
if (quit_more)
{
c = CR; /* just pretend CR was hit */
quit_more = FALSE;
got_int = FALSE;
}
else if (exmode_active)
{
MSG_PUTS(" "); /* make sure the cursor is on the right line */
c = CR; /* no need for a return in ex mode */
got_int = FALSE;
}
else
{
State = HITRETURN;
#ifdef USE_MOUSE
setmouse();
#endif
if (msg_didout) /* start on a new line */
msg_putchar('\n');
if (got_int)
MSG_PUTS("Interrupt: ");
#ifdef ORG_HITRETURN
MSG_PUTS_ATTR("Press RETURN to continue", hl_attr(HLF_R));
do {
c = vgetc();
} while (vim_strchr((char_u *)"\r\n: ", c) == NULL);
if (c == ':') /* this can vi too (but not always!) */
stuffcharReadbuff(c);
#else
MSG_PUTS_ATTR("Press RETURN or enter command to continue",
hl_attr(HLF_R));
if (!msg_use_printf())
msg_clr_eos();
do
{
c = vgetc();
if (!global_busy)
got_int = FALSE;
} while (c == Ctrl('C')
#ifdef USE_GUI
|| c == K_SCROLLBAR || c == K_HORIZ_SCROLLBAR
#endif
#ifdef USE_MOUSE
|| c == K_LEFTDRAG || c == K_LEFTRELEASE
|| c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
|| c == K_RIGHTDRAG || c == K_RIGHTRELEASE
|| c == K_IGNORE ||
(!mouse_has(MOUSE_RETURN) &&
(c == K_LEFTMOUSE ||
c == K_MIDDLEMOUSE ||
c == K_RIGHTMOUSE))
#endif
);
ui_breakcheck();
#ifdef USE_MOUSE
/*
* Avoid that the mouse-up event causes visual mode to start.
*/
if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE)
jump_to_mouse(MOUSE_SETPOS, NULL);
else
#endif
if (vim_strchr((char_u *)"\r\n ", c) == NULL)
{
stuffcharReadbuff(c);
do_redraw = TRUE; /* need a redraw even though there is
something in the stuff buffer */
}
#endif
}
redir_off = FALSE;
/*
* If the user hits ':', '?' or '/' we get a command line from the next
* line.
*/
if (c == ':' || c == '?' || c == '/')
{
if (!exmode_active)
cmdline_row = msg_row;
skip_redraw = TRUE; /* skip redraw once */
do_redraw = FALSE;
}
/*
* If the window size changed set_winsize() will redraw the screen.
* Otherwise the screen is only redrawn if 'redraw' is set and no ':' typed.
*/
tmpState = State;
State = oldState; /* restore State before set_winsize */
#ifdef USE_MOUSE
setmouse();
#endif
msg_check();
/*
* When switching screens, we need to output an extra newline on exit.
*/
#ifdef UNIX
if (swapping_screen() && !termcap_active)
newline_on_exit = TRUE;
#endif
need_wait_return = FALSE;
emsg_on_display = FALSE; /* can delete error message now */
msg_didany = FALSE; /* reset lines_left at next msg_start() */
lines_left = -1;
if (keep_msg != NULL && linetabsize(keep_msg) >=
(Rows - cmdline_row - 1) * Columns + sc_col)
keep_msg = NULL; /* don't redisplay message, it's too long */
if (tmpState == SETWSIZE) /* got resize event while in vgetc() */
{
starttermcap(); /* start termcap before redrawing */
set_winsize(0, 0, FALSE);
}
else if (!skip_redraw && (redraw == TRUE || (msg_scrolled && redraw != -1)))
{
starttermcap(); /* start termcap before redrawing */
update_screen(VALID);
}
dont_wait_return = TRUE; /* don't wait again in main() */
}
/*
* Prepare for outputting characters in the command line.
*/
void
msg_start()
{
int did_return = FALSE;
keep_msg = NULL; /* don't display old message now */
if (!msg_scroll && full_screen) /* overwrite last message */
{
msg_row = cmdline_row;
msg_col = 0;
}
else if (msg_didout) /* start message on next line */
{
msg_putchar('\n');
did_return = TRUE;
if (!exmode_active)
cmdline_row = msg_row;
}
if (!msg_didany)
lines_left = cmdline_row;
msg_didout = FALSE; /* no output on current line yet */
cursor_off();
/* when redirecting, may need to start a new line. */
if (!did_return)
redir_write((char_u *)"\n");
}
void
msg_putchar(c)
int c;
{
msg_putchar_attr(c, 0);
}
void
msg_putchar_attr(c, attr)
int c;
int attr;
{
char_u buf[4];
if (IS_SPECIAL(c))
{
buf[0] = K_SPECIAL;
buf[1] = K_SECOND(c);
buf[2] = K_THIRD(c);
buf[3] = NUL;
}
else
{
buf[0] = c;
buf[1] = NUL;
}
msg_puts_attr(buf, attr);
}
void
msg_outnum(n)
long n;
{
char_u buf[20];
sprintf((char *)buf, "%ld", n);
msg_puts(buf);
}
void
msg_home_replace(fname)
char_u *fname;
{
msg_home_replace_attr(fname, 0);
}
void
msg_home_replace_hl(fname)
char_u *fname;
{
msg_home_replace_attr(fname, hl_attr(HLF_D));
}
static void
msg_home_replace_attr(fname, attr)
char_u *fname;
int attr;
{
char_u *name;
name = home_replace_save(NULL, fname);
if (name != NULL)
msg_outtrans_attr(name, attr);
vim_free(name);
}
/*
* Output 'len' characters in 'str' (including NULs) with translation
* if 'len' is -1, output upto a NUL character.
* Use attributes 'attr'.
* Return the number of characters it takes on the screen.
*/
int
msg_outtrans(str)
char_u *str;
{
return msg_outtrans_attr(str, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -