4595 lines · 103.7 KB · C
RawDownload
/* 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. * See README.txt for an overview of the Vim source code. */ /* * message.c: functions for displaying messages on the command line */ #define MESSAGE_FILE		/* don't include prototype for smsg() */ #include "vim.h" static int other_sourcing_name __ARGS((void));static char_u *get_emsg_source __ARGS((void));static char_u *get_emsg_lnum __ARGS((void));static void add_msg_hist __ARGS((char_u *s, int len, int attr));static void hit_return_msg __ARGS((void));static void msg_home_replace_attr __ARGS((char_u *fname, int attr));#ifdef FEAT_MBYTEstatic char_u *screen_puts_mbyte __ARGS((char_u *s, int l, int attr));#endifstatic void msg_puts_attr_len __ARGS((char_u *str, int maxlen, int attr));static void msg_puts_display __ARGS((char_u *str, int maxlen, int attr, int recurse));static void msg_scroll_up __ARGS((void));static void inc_msg_scrolled __ARGS((void));static void store_sb_text __ARGS((char_u **sb_str, char_u *s, int attr, int *sb_col, int finish));static void t_puts __ARGS((int *t_col, char_u *t_s, char_u *s, int attr));static void msg_puts_printf __ARGS((char_u *str, int maxlen));static int do_more_prompt __ARGS((int typed_char));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, int maxlen));static void verbose_write __ARGS((char_u *s, int maxlen));#ifdef FEAT_CON_DIALOGstatic char_u *msg_show_console_dialog __ARGS((char_u *message, char_u *buttons, int dfltbutton));static int	confirm_msg_used = FALSE;	/* displaying confirm_msg */static char_u	*confirm_msg = NULL;		/* ":confirm" message */static char_u	*confirm_msg_tail;		/* tail of confirm_msg */#endif struct msg_hist{    struct msg_hist	*next;    char_u		*msg;    int			attr;}; static struct msg_hist *first_msg_hist = NULL;static struct msg_hist *last_msg_hist = NULL;static int msg_hist_len = 0; /* * When writing messages to the screen, there are many different situations. * A number of variables is used to remember the current state: * msg_didany	    TRUE when messages were written since the last time the *		    user reacted to a prompt. *		    Reset: After hitting a key for the hit-return prompt, *		    hitting <CR> for the command line or input(). *		    Set: When any message is written to the screen. * msg_didout	    TRUE when something was written to the current line. *		    Reset: When advancing to the next line, when the current *		    text can be overwritten. *		    Set: When any message is written to the screen. * msg_nowait	    No extra delay for the last drawn message. *		    Used in normal_cmd() before the mode message is drawn. * emsg_on_display  There was an error message recently.  Indicates that there *		    should be a delay before redrawing. * msg_scroll	    The next message should not overwrite the current one. * msg_scrolled	    How many lines the screen has been scrolled (because of *		    messages).  Used in update_screen() to scroll the screen *		    back.  Incremented each time the screen scrolls a line. * msg_scrolled_ign  TRUE when msg_scrolled is non-zero and msg_puts_attr() *		    writes something without scrolling should not make *		    need_wait_return to be set.  This is a hack to make ":ts" *		    work without an extra prompt. * lines_left	    Number of lines available for messages before the *		    more-prompt is to be given. * need_wait_return TRUE when the hit-return prompt is needed. *		    Reset: After giving the hit-return prompt, when the user *		    has answered some other prompt. *		    Set: When the ruler or typeahead display is overwritten, *		    scrolling the screen for some message. * keep_msg	    Message to be displayed after redrawing the screen, in *		    main_loop(). *		    This is an allocated string or NULL when not used. */ /* * 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 */    intmsg(s)    char_u	*s;{    return msg_attr_keep(s, 0, FALSE);} #if defined(FEAT_EVAL) || defined(FEAT_X11) || defined(USE_XSMP) \    || defined(PROTO)/* * Like msg() but keep it silent when 'verbosefile' is set. */    intverb_msg(s)    char_u	*s;{    int		n;     verbose_enter();    n = msg_attr_keep(s, 0, FALSE);    verbose_leave();     return n;}#endif     intmsg_attr(s, attr)    char_u	*s;    int		attr;{    return msg_attr_keep(s, attr, FALSE);}     intmsg_attr_keep(s, attr, keep)    char_u	*s;    int		attr;    int		keep;	    /* TRUE: set keep_msg if it doesn't scroll */{    static int	entered = 0;    int		retval;    char_u	*buf = NULL; #ifdef FEAT_EVAL    if (attr == 0)	set_vim_var_string(VV_STATUSMSG, s, -1);#endif     /*     * 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) */    if (s != keep_msg	    || (*s != '<'		&& last_msg_hist != NULL		&& last_msg_hist->msg != NULL		&& STRCMP(s, last_msg_hist->msg)))	add_msg_hist(s, -1, attr);     /* When displaying keep_msg, don't let msg_start() free it, caller must do     * that. */    if (s == keep_msg)	keep_msg = NULL;     /* Truncate the message if needed. */    msg_start();    buf = msg_strtrunc(s, FALSE);    if (buf != NULL)	s = buf;     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)	set_keep_msg(s, 0);     vim_free(buf);    --entered;    return retval;} /* * Truncate a string such that it can be printed without causing a scroll. * Returns an allocated string or NULL when no truncating is done. */    char_u *msg_strtrunc(s, force)    char_u	*s;    int		force;	    /* always truncate */{    char_u	*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) || force)    {	len = vim_strsize(s);	if (msg_scrolled != 0)	    /* Use all the columns. */	    room = (int)(Rows - msg_row) * Columns - 1;	else	    /* Use up to 'showcmd' column. */	    room = (int)(Rows - msg_row - 1) * Columns + sc_col - 1;	if (len > room && room > 0)	{#ifdef FEAT_MBYTE	    if (enc_utf8)		/* may have up to 18 bytes per cell (6 per char, up to two		 * composing chars) */		buf = alloc((room + 2) * 18);	    else if (enc_dbcs == DBCS_JPNU)		/* may have up to 2 bytes per cell for euc-jp */		buf = alloc((room + 2) * 2);	    else#endif		buf = alloc(room + 2);	    if (buf != NULL)		trunc_string(s, buf, room);	}    }    return buf;} /* * Truncate a string "s" to "buf" with cell width "room". * "s" and "buf" may be equal. */    voidtrunc_string(s, buf, room)    char_u	*s;    char_u	*buf;    int		room;{    int		half;    int		len;    int		e;    int		i;    int		n;     room -= 3;    half = room / 2;    len = 0;     /* First part: Start of the string. */    for (e = 0; len < half; ++e)    {	if (s[e] == NUL)	{	    /* text fits without truncating! */	    buf[e] = NUL;	    return;	}	n = ptr2cells(s + e);	if (len + n >= half)	    break;	len += n;	buf[e] = s[e];#ifdef FEAT_MBYTE	if (has_mbyte)	    for (n = (*mb_ptr2len)(s + e); --n > 0; )	    {		++e;		buf[e] = s[e];	    }#endif    }     /* Last part: End of the string. */    i = e;#ifdef FEAT_MBYTE    if (enc_dbcs != 0)    {	/* For DBCS going backwards in a string is slow, but	 * computing the cell width isn't too slow: go forward	 * until the rest fits. */	n = vim_strsize(s + i);	while (len + n > room)	{	    n -= ptr2cells(s + i);	    i += (*mb_ptr2len)(s + i);	}    }    else if (enc_utf8)    {	/* For UTF-8 we can go backwards easily. */	half = i = (int)STRLEN(s);	for (;;)	{	    do		half = half - (*mb_head_off)(s, s + half - 1) - 1;	    while (utf_iscomposing(utf_ptr2char(s + half)) && half > 0);	    n = ptr2cells(s + half);	    if (len + n > room)		break;	    len += n;	    i = half;	}    }    else#endif    {	for (i = (int)STRLEN(s); len + (n = ptr2cells(s + i - 1)) <= room; --i)	    len += n;    }     /* Set the middle and copy the last part. */    mch_memmove(buf + e, "...", (size_t)3);    mch_memmove(buf + e + 3, s + i, STRLEN(s + i) + 1);} /* * Automatic prototype generation does not understand this function. * Note: Caller of smgs() and smsg_attr() must check the resulting string is * shorter than IOSIZE!!! */#ifndef PROTO# ifndef HAVE_STDARG_H int#ifdef __BORLANDC___RTLENTRYF#endifsmsg __ARGS((char_u *, long, long, long,			long, long, long, long, long, long, long));int#ifdef __BORLANDC___RTLENTRYF#endifsmsg_attr __ARGS((int, char_u *, long, long, long,			long, long, long, long, long, long, long)); int vim_snprintf __ARGS((char *, size_t, char *, long, long, long,				   long, long, long, long, long, long, long)); /* * smsg(str, arg, ...) is like using sprintf(buf, str, arg, ...) and then * calling msg(buf). * The buffer used is IObuff, the message is truncated at IOSIZE. */ /* VARARGS */    int#ifdef __BORLANDC___RTLENTRYF#endifsmsg(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#endifsmsg_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;{    vim_snprintf((char *)IObuff, IOSIZE, (char *)s,				     a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);    return msg_attr(IObuff, attr);} # else /* HAVE_STDARG_H */ int vim_snprintf(char *str, size_t str_m, char *fmt, ...);     int#ifdef __BORLANDC___RTLENTRYF#endifsmsg(char_u *s, ...){    va_list arglist;     va_start(arglist, s);    vim_vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist, NULL);    va_end(arglist);    return msg(IObuff);}     int#ifdef __BORLANDC___RTLENTRYF#endifsmsg_attr(int attr, char_u *s, ...){    va_list arglist;     va_start(arglist, s);    vim_vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist, NULL);    va_end(arglist);    return msg_attr(IObuff, attr);} # endif /* HAVE_STDARG_H */#endif /* * Remember the last sourcing name/lnum used in an error message, so that it * isn't printed each time when it didn't change. */static int	last_sourcing_lnum = 0;static char_u   *last_sourcing_name = NULL; /* * Reset the last used sourcing name/lnum.  Makes sure it is displayed again * for the next error message; */    voidreset_last_sourcing(){    vim_free(last_sourcing_name);    last_sourcing_name = NULL;    last_sourcing_lnum = 0;} /* * Return TRUE if "sourcing_name" differs from "last_sourcing_name". */    static intother_sourcing_name(){    if (sourcing_name != NULL)    {	if (last_sourcing_name != NULL)	    return STRCMP(sourcing_name, last_sourcing_name) != 0;	return TRUE;    }    return FALSE;} /* * Get the message about the source, as used for an error message. * Returns an allocated string with room for one more character. * Returns NULL when no message is to be given. */    static char_u *get_emsg_source(){    char_u	*Buf, *p;     if (sourcing_name != NULL && other_sourcing_name())    {	p = (char_u *)_("Error detected while processing %s:");	Buf = alloc((unsigned)(STRLEN(sourcing_name) + STRLEN(p)));	if (Buf != NULL)	    sprintf((char *)Buf, (char *)p, sourcing_name);	return Buf;    }    return NULL;} /* * Get the message about the source lnum, as used for an error message. * Returns an allocated string with room for one more character. * Returns NULL when no message is to be given. */    static char_u *get_emsg_lnum(){    char_u	*Buf, *p;     /* lnum is 0 when executing a command from the command line     * argument, we don't want a line number then */    if (sourcing_name != NULL	    && (other_sourcing_name() || sourcing_lnum != last_sourcing_lnum)	    && sourcing_lnum != 0)    {	p = (char_u *)_("line %4ld:");	Buf = alloc((unsigned)(STRLEN(p) + 20));	if (Buf != NULL)	    sprintf((char *)Buf, (char *)p, (long)sourcing_lnum);	return Buf;    }    return NULL;} /* * Display name and line number for the source of an error. * Remember the file name and line number, so that for the next error the info * is only displayed if it changed. */    voidmsg_source(attr)    int		attr;{

Lines 1–500 of 4595.