xref: /vim-8.2.3635/src/message.c (revision ed20346f)
1 /* vi:set ts=8 sts=4 sw=4:
2  *
3  * VIM - Vi IMproved	by Bram Moolenaar
4  *
5  * Do ":help uganda"  in Vim to read copying and usage conditions.
6  * Do ":help credits" in Vim to see a list of people who contributed.
7  * See README.txt for an overview of the Vim source code.
8  */
9 
10 /*
11  * message.c: functions for displaying messages on the command line
12  */
13 
14 #define MESSAGE_FILE		/* don't include prototype for smsg() */
15 
16 #include "vim.h"
17 
18 #ifdef HAVE_STDARG_H
19 # include <stdarg.h>
20 #endif
21 
22 static void reset_last_sourcing __ARGS((void));
23 static char_u *get_emsg_source __ARGS((int other));
24 static char_u *get_emsg_lnum __ARGS((int other));
25 static void add_msg_hist __ARGS((char_u *s, int len, int attr));
26 static void hit_return_msg __ARGS((void));
27 static void msg_home_replace_attr __ARGS((char_u *fname, int attr));
28 #ifdef FEAT_MBYTE
29 static char_u *screen_puts_mbyte __ARGS((char_u *s, int l, int attr));
30 #endif
31 static void msg_puts_attr_len __ARGS((char_u *str, int maxlen, int attr));
32 static void t_puts __ARGS((int t_col, char_u *t_s, char_u *s, int attr));
33 static void msg_screen_putchar __ARGS((int c, int attr));
34 static int  msg_check_screen __ARGS((void));
35 static void redir_write __ARGS((char_u *s, int maxlen));
36 #ifdef FEAT_CON_DIALOG
37 static char_u *msg_show_console_dialog __ARGS((char_u *message, char_u *buttons, int dfltbutton));
38 static int	confirm_msg_used = FALSE;	/* displaying confirm_msg */
39 static char_u	*confirm_msg = NULL;		/* ":confirm" message */
40 static char_u	*confirm_msg_tail;		/* tail of confirm_msg */
41 #endif
42 
43 struct msg_hist
44 {
45     struct msg_hist	*next;
46     char_u		*msg;
47     int			attr;
48 };
49 
50 static struct msg_hist *first_msg_hist = NULL;
51 static struct msg_hist *last_msg_hist = NULL;
52 static int msg_hist_len = 0;
53 static int msg_hist_off = FALSE;	/* don't add messages to history */
54 
55 /*
56  * When writing messages to the screen, there are many different situations.
57  * A number of variables is used to remember the current state:
58  * msg_didany	    TRUE when messages were written since the last time the
59  *		    user reacted to a prompt.
60  *		    Reset: After hitting a key for the hit-return prompt,
61  *		    hitting <CR> for the command line or input().
62  *		    Set: When any message is written to the screen.
63  * msg_didout	    TRUE when something was written to the current line.
64  *		    Reset: When advancing to the next line, when the current
65  *		    text can be overwritten.
66  *		    Set: When any message is written to the screen.
67  * msg_nowait	    No extra delay for the last drawn message.
68  *		    Used in normal_cmd() before the mode message is drawn.
69  * emsg_on_display  There was an error message recently.  Indicates that there
70  *		    should be a delay before redrawing.
71  * msg_scroll	    The next message should not overwrite the current one.
72  * msg_scrolled	    How many lines the screen has been scrolled (because of
73  *		    messages).  Used in update_screen() to scroll the screen
74  *		    back.  Incremented each time the screen scrolls a line.
75  * msg_scrolled_ign  TRUE when msg_scrolled is non-zero and msg_puts_attr()
76  *		    writes something without scrolling should not make
77  *		    need_wait_return to be set.  This is a hack to make ":ts"
78  *		    work without an extra prompt.
79  * lines_left	    Number of lines available for messages before the
80  *		    more-prompt is to be given.
81  * need_wait_return TRUE when the hit-return prompt is needed.
82  *		    Reset: After giving the hit-return prompt, when the user
83  *		    has answered some other prompt.
84  *		    Set: When the ruler or typeahead display is overwritten,
85  *		    scrolling the screen for some message.
86  * keep_msg	    Message to be displayed after redrawing the screen, in
87  *		    main_loop().
88  *		    This is an allocated string or NULL when not used.
89  */
90 
91 /*
92  * msg(s) - displays the string 's' on the status line
93  * When terminal not initialized (yet) mch_errmsg(..) is used.
94  * return TRUE if wait_return not called
95  */
96     int
97 msg(s)
98     char_u	*s;
99 {
100     return msg_attr_keep(s, 0, FALSE);
101 }
102 
103     int
104 msg_attr(s, attr)
105     char_u	*s;
106     int		attr;
107 {
108     return msg_attr_keep(s, attr, FALSE);
109 }
110 
111     int
112 msg_attr_keep(s, attr, keep)
113     char_u	*s;
114     int		attr;
115     int		keep;	    /* TRUE: set keep_msg if it doesn't scroll */
116 {
117     static int	entered = 0;
118     int		retval;
119     char_u	*buf = NULL;
120 
121 #ifdef FEAT_EVAL
122     if (attr == 0)
123 	set_vim_var_string(VV_STATUSMSG, s, -1);
124 #endif
125 
126     /*
127      * It is possible that displaying a messages causes a problem (e.g.,
128      * when redrawing the window), which causes another message, etc..	To
129      * break this loop, limit the recursiveness to 3 levels.
130      */
131     if (entered >= 3)
132 	return TRUE;
133     ++entered;
134 
135     /* Add message to history (unless it's a repeated kept message or a
136      * truncated message) */
137     if (s != keep_msg
138 	    || (*s != '<'
139 		&& last_msg_hist != NULL
140 		&& last_msg_hist->msg != NULL
141 		&& STRCMP(s, last_msg_hist->msg)))
142 	add_msg_hist(s, -1, attr);
143 
144     /* When displaying keep_msg, don't let msg_start() free it, caller must do
145      * that. */
146     if (s == keep_msg)
147 	keep_msg = NULL;
148 
149     /* Truncate the message if needed. */
150     buf = msg_strtrunc(s);
151     if (buf != NULL)
152 	s = buf;
153 
154     msg_start();
155     msg_outtrans_attr(s, attr);
156     msg_clr_eos();
157     retval = msg_end();
158 
159     if (keep && retval && vim_strsize(s) < (int)(Rows - cmdline_row - 1)
160 							   * Columns + sc_col)
161     {
162 	set_keep_msg(s);
163 	keep_msg_attr = 0;
164     }
165 
166     vim_free(buf);
167     --entered;
168     return retval;
169 }
170 
171 /*
172  * Truncate a string such that it can be printed without causing a scroll.
173  * Returns an allocated string or NULL when no truncating is done.
174  */
175     char_u *
176 msg_strtrunc(s)
177     char_u	*s;
178 {
179     char_u	*buf = NULL;
180     int		len;
181     int		room;
182 
183     /* May truncate message to avoid a hit-return prompt */
184     if (!msg_scroll && !need_wait_return && shortmess(SHM_TRUNCALL)
185 							    && !exmode_active)
186     {
187 	len = vim_strsize(s);
188 	room = (int)(Rows - cmdline_row - 1) * Columns + sc_col - 1;
189 	if (len > room && room > 0)
190 	{
191 #ifdef FEAT_MBYTE
192 	    if (enc_utf8)
193 		/* may have up to 18 bytes per cell (6 per char, up to two
194 		 * composing chars) */
195 		buf = alloc((room + 2) * 18);
196 	    else if (enc_dbcs == DBCS_JPNU)
197 		/* may have up to 2 bytes per cell for euc-jp */
198 		buf = alloc((room + 2) * 2);
199 	    else
200 #endif
201 		buf = alloc(room + 2);
202 	    if (buf != NULL)
203 		trunc_string(s, buf, room);
204 	}
205     }
206     return buf;
207 }
208 
209 /*
210  * Truncate a string "s" to "buf" with cell width "room".
211  * "s" and "buf" may be equal.
212  */
213     void
214 trunc_string(s, buf, room)
215     char_u	*s;
216     char_u	*buf;
217     int		room;
218 {
219     int		half;
220     int		len;
221     int		e;
222     int		i;
223     int		n;
224 
225     room -= 3;
226     half = room / 2;
227     len = 0;
228 
229     /* First part: Start of the string. */
230     for (e = 0; len < half; ++e)
231     {
232 	if (s[e] == NUL)
233 	{
234 	    /* text fits without truncating! */
235 	    buf[e] = NUL;
236 	    return;
237 	}
238 	n = ptr2cells(s + e);
239 	if (len + n >= half)
240 	    break;
241 	len += n;
242 	buf[e] = s[e];
243 #ifdef FEAT_MBYTE
244 	if (has_mbyte)
245 	    for (n = (*mb_ptr2len_check)(s + e); --n > 0; )
246 	    {
247 		++e;
248 		buf[e] = s[e];
249 	    }
250 #endif
251     }
252 
253     /* Last part: End of the string. */
254     i = e;
255 #ifdef FEAT_MBYTE
256     if (enc_dbcs != 0)
257     {
258 	/* For DBCS going backwards in a string is slow, but
259 	 * computing the cell width isn't too slow: go forward
260 	 * until the rest fits. */
261 	n = vim_strsize(s + i);
262 	while (len + n > room)
263 	{
264 	    n -= ptr2cells(s + i);
265 	    i += (*mb_ptr2len_check)(s + i);
266 	}
267     }
268     else if (enc_utf8)
269     {
270 	/* For UTF-8 we can go backwards easily. */
271 	i = (int)STRLEN(s);
272 	for (;;)
273 	{
274 	    half = i - (*mb_head_off)(s, s + i - 1) - 1;
275 	    n = ptr2cells(s + half);
276 	    if (len + n > room)
277 		break;
278 	    len += n;
279 	    i = half;
280 	}
281     }
282     else
283 #endif
284     {
285 	for (i = (int)STRLEN(s); len + (n = ptr2cells(s + i - 1)) <= room; --i)
286 	    len += n;
287     }
288 
289     /* Set the middle and copy the last part. */
290     mch_memmove(buf + e, "...", (size_t)3);
291     mch_memmove(buf + e + 3, s + i, STRLEN(s + i) + 1);
292 }
293 
294 /*
295  * Automatic prototype generation does not understand this function.
296  * Note: Caller of smgs() and smsg_attr() must check the resulting string is
297  * shorter than IOSIZE!!!
298  */
299 #ifndef PROTO
300 # ifndef HAVE_STDARG_H
301 
302 int
303 #ifdef __BORLANDC__
304 _RTLENTRYF
305 #endif
306 smsg __ARGS((char_u *, long, long, long,
307 			long, long, long, long, long, long, long));
308 int
309 #ifdef __BORLANDC__
310 _RTLENTRYF
311 #endif
312 smsg_attr __ARGS((int, char_u *, long, long, long,
313 			long, long, long, long, long, long, long));
314 
315 /* VARARGS */
316     int
317 #ifdef __BORLANDC__
318 _RTLENTRYF
319 #endif
320 smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
321     char_u	*s;
322     long	a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
323 {
324     return smsg_attr(0, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
325 }
326 
327 /* VARARGS */
328     int
329 #ifdef __BORLANDC__
330 _RTLENTRYF
331 #endif
332 smsg_attr(attr, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
333     int		attr;
334     char_u	*s;
335     long	a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
336 {
337     sprintf((char *)IObuff, (char *)s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
338     return msg_attr(IObuff, attr);
339 }
340 
341 # else /* HAVE_STDARG_H */
342 
343     int
344 #ifdef __BORLANDC__
345 _RTLENTRYF
346 #endif
347 smsg(char_u *s, ...)
348 {
349     va_list arglist;
350 
351     va_start(arglist, s);
352 # ifdef HAVE_VSNPRINTF
353     vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist);
354 # else
355     vsprintf((char *)IObuff, (char *)s, arglist);
356 # endif
357     va_end(arglist);
358     return msg(IObuff);
359 }
360 
361     int
362 #ifdef __BORLANDC__
363 _RTLENTRYF
364 #endif
365 smsg_attr(int attr, char_u *s, ...)
366 {
367     va_list arglist;
368 
369     va_start(arglist, s);
370 # ifdef HAVE_VSNPRINTF
371     vsnprintf((char *)IObuff, IOSIZE, (char *)s, arglist);
372 # else
373     vsprintf((char *)IObuff, (char *)s, arglist);
374 # endif
375     va_end(arglist);
376     return msg_attr(IObuff, attr);
377 }
378 
379 # endif /* HAVE_STDARG_H */
380 #endif
381 
382 /*
383  * Remember the last sourcing name/lnum used in an error message, so that it
384  * isn't printed each time when it didn't change.
385  */
386 static int	last_sourcing_lnum = 0;
387 static char_u   *last_sourcing_name = NULL;
388 
389 /*
390  * Reset the last used sourcing name/lnum.  Makes sure it is displayed again
391  * for the next error message;
392  */
393     static void
394 reset_last_sourcing()
395 {
396     vim_free(last_sourcing_name);
397     last_sourcing_name = NULL;
398     last_sourcing_lnum = 0;
399 }
400 
401 /*
402  * Get the message about the source, as used for an error message.
403  * Returns an allocated string with room for one more character.
404  * Returns NULL when no message is to be given.
405  */
406     static char_u *
407 get_emsg_source(other)
408     int		other;	/* TRUE when "sourcing_name" differs from last time */
409 {
410     char_u	*Buf, *p;
411 
412     if (sourcing_name != NULL && other)
413     {
414 	p = (char_u *)_("Error detected while processing %s:");
415 	Buf = alloc((unsigned)(STRLEN(sourcing_name) + STRLEN(p)));
416 	if (Buf != NULL)
417 	    sprintf((char *)Buf, (char *)p, sourcing_name);
418 	return Buf;
419     }
420     return NULL;
421 }
422 
423 /*
424  * Get the message about the source lnum, as used for an error message.
425  * Returns an allocated string with room for one more character.
426  * Returns NULL when no message is to be given.
427  */
428     static char_u *
429 get_emsg_lnum(other)
430     int		other;	/* TRUE when "sourcing_name" differs from last time */
431 {
432     char_u	*Buf, *p;
433 
434     /* lnum is 0 when executing a command from the command line
435      * argument, we don't want a line number then */
436     if (sourcing_name != NULL
437 	    && (other || sourcing_lnum != last_sourcing_lnum)
438 	    && sourcing_lnum != 0)
439     {
440 	p = (char_u *)_("line %4ld:");
441 	Buf = alloc((unsigned)(STRLEN(p) + 20));
442 	if (Buf != NULL)
443 	    sprintf((char *)Buf, (char *)p, (long)sourcing_lnum);
444 	return Buf;
445     }
446     return NULL;
447 }
448 
449 /*
450  * emsg() - display an error message
451  *
452  * Rings the bell, if appropriate, and calls message() to do the real work
453  * When terminal not initialized (yet) mch_errmsg(..) is used.
454  *
455  * return TRUE if wait_return not called
456  */
457     int
458 emsg(s)
459     char_u	*s;
460 {
461     int		attr;
462     int		other_sourcing_name;
463     char_u	*p;
464 #ifdef FEAT_EVAL
465     int		ignore = FALSE;
466     int		severe;
467 #endif
468 
469     called_emsg = TRUE;
470 
471     /*
472      * If "emsg_severe" is TRUE: When an error exception is to be thrown, prefer
473      * this message over previous messages for the same command.
474      */
475 #ifdef FEAT_EVAL
476     severe = emsg_severe;
477     emsg_severe = FALSE;
478 #endif
479 
480     /*
481      * If "emsg_off" is set: no error messages at the moment.
482      * If 'debug' is set: do error message anyway, but without side effects.
483      * If "emsg_skip" is set: never do error messages.
484      */
485     if ((emsg_off > 0 && *p_debug == NUL)
486 #ifdef FEAT_EVAL
487 	    || emsg_skip > 0
488 #endif
489 	    )
490 	return TRUE;
491 
492     if (sourcing_name != NULL)
493     {
494 	if (last_sourcing_name != NULL)
495 	    other_sourcing_name = STRCMP(sourcing_name, last_sourcing_name);
496 	else
497 	    other_sourcing_name = TRUE;
498     }
499     else
500 	other_sourcing_name = FALSE;
501 
502     if (!emsg_off)
503     {
504 #ifdef FEAT_EVAL
505 	/*
506 	 * Cause a throw of an error exception if appropriate.  Don't display
507 	 * the error message in this case.  (If no matching catch clause will
508 	 * be found, the message will be displayed later on.)  "ignore" is set
509 	 * when the message should be ignored completely (used for the
510 	 * interrupt message).
511 	 */
512 	if (cause_errthrow(s, severe, &ignore) == TRUE)
513 	{
514 	    if (!ignore)
515 		did_emsg = TRUE;
516 	    return TRUE;
517 	}
518 
519 	/* set "v:errmsg", also when using ":silent! cmd" */
520 	set_vim_var_string(VV_ERRMSG, s, -1);
521 #endif
522 
523 	/*
524 	 * When using ":silent! cmd" ignore error messsages.
525 	 * But do write it to the redirection file.
526 	 */
527 	if (emsg_silent != 0)
528 	{
529 	    msg_start();
530 	    p = get_emsg_source(other_sourcing_name);
531 	    if (p != NULL)
532 	    {
533 		STRCAT(p, "\n");
534 		redir_write(p, -1);
535 		vim_free(p);
536 	    }
537 	    p = get_emsg_lnum(other_sourcing_name);
538 	    if (p != NULL)
539 	    {
540 		STRCAT(p, "\n");
541 		redir_write(p, -1);
542 		vim_free(p);
543 	    }
544 	    redir_write(s, -1);
545 	    return TRUE;
546 	}
547 
548 	/* Reset msg_silent, an error causes messages to be switched back on. */
549 	msg_silent = 0;
550 	cmd_silent = FALSE;
551 
552 	if (global_busy)		/* break :global command */
553 	    ++global_busy;
554 
555 	if (p_eb)
556 	    beep_flush();		/* also includes flush_buffers() */
557 	else
558 	    flush_buffers(FALSE);	/* flush internal buffers */
559 	did_emsg = TRUE;		/* flag for DoOneCmd() */
560     }
561 
562     emsg_on_display = TRUE;	/* remember there is an error message */
563     ++msg_scroll;		/* don't overwrite a previous message */
564     attr = hl_attr(HLF_E);	/* set highlight mode for error messages */
565     if (msg_scrolled)
566 	need_wait_return = TRUE;    /* needed in case emsg() is called after
567 				     * wait_return has reset need_wait_return
568 				     * and a redraw is expected because
569 				     * msg_scrolled is non-zero */
570 
571     /*
572      * Display name and line number for the source of the error.
573      */
574     ++no_wait_return;
575     p = get_emsg_source(other_sourcing_name);
576     if (p != NULL)
577     {
578 	msg_attr(p, attr);
579 	vim_free(p);
580     }
581     p = get_emsg_lnum(other_sourcing_name);
582     if (p != NULL)
583     {
584 	msg_attr(p, hl_attr(HLF_N));
585 	vim_free(p);
586 	last_sourcing_lnum = sourcing_lnum;  /* only once for each line */
587     }
588     --no_wait_return;
589 
590     /* remember the last sourcing name printed, also when it's empty */
591     if (sourcing_name == NULL || other_sourcing_name)
592     {
593 	vim_free(last_sourcing_name);
594 	if (sourcing_name == NULL)
595 	    last_sourcing_name = NULL;
596 	else
597 	    last_sourcing_name = vim_strsave(sourcing_name);
598     }
599     msg_nowait = FALSE;			/* wait for this msg */
600 
601     /*
602      * Display the error message itself.
603      */
604     return msg_attr(s, attr);
605 }
606 
607 /*
608  * Print an error message with one "%s" and one string argument.
609  */
610     int
611 emsg2(s, a1)
612     char_u *s, *a1;
613 {
614     return emsg3(s, a1, NULL);
615 }
616 
617 /*
618  * Print an error message with one or two "%s" and one or two string arguments.
619  */
620     int
621 emsg3(s, a1, a2)
622     char_u *s, *a1, *a2;
623 {
624     if ((emsg_off > 0 && *p_debug == NUL)
625 #ifdef FEAT_EVAL
626 	    || emsg_skip > 0
627 #endif
628 	    )
629 	return TRUE;		/* no error messages at the moment */
630 
631     /* Check for NULL strings (just in case) */
632     if (a1 == NULL)
633 	a1 = (char_u *)"[NULL]";
634     if (a2 == NULL)
635 	a2 = (char_u *)"[NULL]";
636 
637     /* Check for very long strings (can happen with ":help ^A<CR>"). */
638     if (STRLEN(s) + STRLEN(a1) + STRLEN(a2) >= (size_t)IOSIZE)
639 	a1 = a2 = (char_u *)_("[string too long]");
640 
641     sprintf((char *)IObuff, (char *)s, (char *)a1, (char *)a2);
642     return emsg(IObuff);
643 }
644 
645 /*
646  * Print an error message with one "%ld" and one long int argument.
647  */
648     int
649 emsgn(s, n)
650     char_u	*s;
651     long	n;
652 {
653     if ((emsg_off > 0 && *p_debug == NUL)
654 #ifdef FEAT_EVAL
655 	    || emsg_skip > 0
656 #endif
657 	    )
658 	return TRUE;		/* no error messages at the moment */
659     sprintf((char *)IObuff, (char *)s, n);
660     return emsg(IObuff);
661 }
662 
663 /*
664  * Like msg(), but truncate to a single line if p_shm contains 't', or when
665  * "force" is TRUE.  This truncates in another way as for normal messages.
666  * Careful: The string may be changed by msg_may_trunc()!
667  * Returns a pointer to the printed message, if wait_return() not called.
668  */
669     char_u *
670 msg_trunc_attr(s, force, attr)
671     char_u	*s;
672     int		force;
673     int		attr;
674 {
675     int		n;
676 
677     /* Add message to history before truncating */
678     add_msg_hist(s, -1, attr);
679 
680     s = msg_may_trunc(force, s);
681 
682     msg_hist_off = TRUE;
683     n = msg_attr(s, attr);
684     msg_hist_off = FALSE;
685 
686     if (n)
687 	return s;
688     return NULL;
689 }
690 
691 /*
692  * Check if message "s" should be truncated at the start (for filenames).
693  * Return a pointer to where the truncated message starts.
694  * Note: May change the message by replacing a character with '<'.
695  */
696     char_u *
697 msg_may_trunc(force, s)
698     int		force;
699     char_u	*s;
700 {
701     int		n;
702     int		room;
703 
704     room = (int)(Rows - cmdline_row - 1) * Columns + sc_col - 1;
705     if ((force || (shortmess(SHM_TRUNC) && !exmode_active))
706 	    && (n = (int)STRLEN(s) - room) > 0)
707     {
708 #ifdef FEAT_MBYTE
709 	if (has_mbyte)
710 	{
711 	    int	size = vim_strsize(s);
712 
713 	    for (n = 0; size >= room; )
714 	    {
715 		size -= (*mb_ptr2cells)(s + n);
716 		n += (*mb_ptr2len_check)(s + n);
717 	    }
718 	    --n;
719 	}
720 #endif
721 	s += n;
722 	*s = '<';
723     }
724     return s;
725 }
726 
727     static void
728 add_msg_hist(s, len, attr)
729     char_u	*s;
730     int		len;		/* -1 for undetermined length */
731     int		attr;
732 {
733     struct msg_hist *p;
734 
735     if (msg_hist_off || msg_silent != 0)
736 	return;
737 
738     /* Don't let the message history get too big */
739     while (msg_hist_len > 20)
740     {
741 	p = first_msg_hist;
742 	first_msg_hist = p->next;
743 	vim_free(p->msg);
744 	vim_free(p);
745 	--msg_hist_len;
746     }
747     /* allocate an entry and add the message at the end of the history */
748     p = (struct msg_hist *)alloc((int)sizeof(struct msg_hist));
749     if (p != NULL)
750     {
751 	if (len < 0)
752 	    len = (int)STRLEN(s);
753 	/* remove leading and trailing newlines */
754 	while (len > 0 && *s == '\n')
755 	{
756 	    ++s;
757 	    --len;
758 	}
759 	while (len > 0 && s[len - 1] == '\n')
760 	    --len;
761 	p->msg = vim_strnsave(s, len);
762 	p->next = NULL;
763 	p->attr = attr;
764 	if (last_msg_hist != NULL)
765 	    last_msg_hist->next = p;
766 	last_msg_hist = p;
767 	if (first_msg_hist == NULL)
768 	    first_msg_hist = last_msg_hist;
769 	++msg_hist_len;
770     }
771 }
772 
773 /*
774  * ":messages" command.
775  */
776 /*ARGSUSED*/
777     void
778 ex_messages(eap)
779     exarg_T	*eap;
780 {
781     struct msg_hist *p;
782     char_u	    *s;
783 
784     msg_hist_off = TRUE;
785 
786     s = mch_getenv((char_u *)"LANG");
787     if (s != NULL && *s != NUL)
788 	msg_attr((char_u *)
789 		_("Messages maintainer: Bram Moolenaar <[email protected]>"),
790 		hl_attr(HLF_T));
791 
792     for (p = first_msg_hist; p != NULL; p = p->next)
793 	if (p->msg != NULL)
794 	    msg_attr(p->msg, p->attr);
795 
796     msg_hist_off = FALSE;
797 }
798 
799 #if defined(FEAT_CON_DIALOG) || defined(PROTO)
800 static void msg_end_prompt __ARGS((void));
801 
802 /*
803  * Call this after prompting the user.  This will avoid a hit-return message
804  * and a delay.
805  */
806     static void
807 msg_end_prompt()
808 {
809     need_wait_return = FALSE;
810     emsg_on_display = FALSE;
811     cmdline_row = msg_row;
812     msg_col = 0;
813     msg_clr_eos();
814 }
815 #endif
816 
817 /*
818  * wait for the user to hit a key (normally a return)
819  * if 'redraw' is TRUE, clear and redraw the screen
820  * if 'redraw' is FALSE, just redraw the screen
821  * if 'redraw' is -1, don't redraw at all
822  */
823     void
824 wait_return(redraw)
825     int		redraw;
826 {
827     int		c;
828     int		oldState;
829     int		tmpState;
830 #ifndef ORG_HITRETURN
831     int		had_got_int;
832 #endif
833 
834     if (redraw == TRUE)
835 	must_redraw = CLEAR;
836 
837     /* If using ":silent cmd", don't wait for a return.  Also don't set
838      * need_wait_return to do it later. */
839     if (msg_silent != 0)
840 	return;
841 
842 /*
843  * With the global command (and some others) we only need one return at the
844  * end. Adjust cmdline_row to avoid the next message overwriting the last one.
845  * When inside vgetc(), we can't wait for a typed character at all.
846  */
847     if (vgetc_busy)
848 	return;
849     if (no_wait_return)
850     {
851 	need_wait_return = TRUE;
852 	if (!exmode_active)
853 	    cmdline_row = msg_row;
854 	return;
855     }
856 
857     redir_off = TRUE;		/* don't redirect this message */
858     oldState = State;
859     if (quit_more)
860     {
861 	c = CAR;		/* just pretend CR was hit */
862 	quit_more = FALSE;
863 	got_int = FALSE;
864     }
865     else if (exmode_active)
866     {
867 	MSG_PUTS(" ");		/* make sure the cursor is on the right line */
868 	c = CAR;		/* no need for a return in ex mode */
869 	got_int = FALSE;
870     }
871     else
872     {
873 	/* Make sure the hit-return prompt is on screen when 'guioptions' was
874 	 * just changed. */
875 	screenalloc(FALSE);
876 
877 	State = HITRETURN;
878 #ifdef FEAT_MOUSE
879 	setmouse();
880 #endif
881 #ifdef USE_ON_FLY_SCROLL
882 	dont_scroll = TRUE;		/* disallow scrolling here */
883 #endif
884 	hit_return_msg();
885 
886 #ifdef ORG_HITRETURN
887 	do
888 	{
889 	    c = safe_vgetc();
890 	} while (vim_strchr((char_u *)"\r\n: ", c) == NULL);
891 	if (c == ':')			/* this can vi too (but not always!) */
892 	    stuffcharReadbuff(c);
893 #else
894 	do
895 	{
896 	    /* Remember "got_int", if it is set vgetc() probably returns a
897 	     * CTRL-C, but we need to loop then. */
898 	    had_got_int = got_int;
899 	    c = safe_vgetc();
900 	    if (!global_busy)
901 		got_int = FALSE;
902 #ifdef FEAT_CLIPBOARD
903 	    /* Strange way to allow copying (yanking) a modeless selection at
904 	     * the hit-enter prompt.  Use CTRL-Y, because the same is used in
905 	     * Cmdline-mode and it's harmless when there is no selection. */
906 	    if (c == Ctrl_Y && clip_star.state == SELECT_DONE)
907 	    {
908 		clip_copy_modeless_selection(TRUE);
909 		c = K_IGNORE;
910 	    }
911 #endif
912 	} while ((had_got_int && c == Ctrl_C)
913 				|| c == K_IGNORE
914 #ifdef FEAT_GUI
915 				|| c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR
916 #endif
917 #ifdef FEAT_MOUSE
918 				|| c == K_LEFTDRAG   || c == K_LEFTRELEASE
919 				|| c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
920 				|| c == K_RIGHTDRAG  || c == K_RIGHTRELEASE
921 				|| c == K_MOUSEDOWN  || c == K_MOUSEUP
922 				|| (!mouse_has(MOUSE_RETURN)
923 				    && mouse_row < msg_row
924 				    && (c == K_LEFTMOUSE
925 					|| c == K_MIDDLEMOUSE
926 					|| c == K_RIGHTMOUSE
927 					|| c == K_X1MOUSE
928 					|| c == K_X2MOUSE))
929 #endif
930 				);
931 	ui_breakcheck();
932 #ifdef FEAT_MOUSE
933 	/*
934 	 * Avoid that the mouse-up event causes visual mode to start.
935 	 */
936 	if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE
937 					  || c == K_X1MOUSE || c == K_X2MOUSE)
938 	    (void)jump_to_mouse(MOUSE_SETPOS, NULL, 0);
939 	else
940 #endif
941 	    if (vim_strchr((char_u *)"\r\n ", c) == NULL && c != Ctrl_C)
942 	{
943 	    stuffcharReadbuff(c);
944 	    do_redraw = TRUE;	    /* need a redraw even though there is
945 				       something in the stuff buffer */
946 	}
947 #endif
948     }
949     redir_off = FALSE;
950 
951     /*
952      * If the user hits ':', '?' or '/' we get a command line from the next
953      * line.
954      */
955     if (c == ':' || c == '?' || c == '/')
956     {
957 	if (!exmode_active)
958 	    cmdline_row = msg_row;
959 	skip_redraw = TRUE;	    /* skip redraw once */
960 	do_redraw = FALSE;
961     }
962 
963     /*
964      * If the window size changed set_shellsize() will redraw the screen.
965      * Otherwise the screen is only redrawn if 'redraw' is set and no ':'
966      * typed.
967      */
968     tmpState = State;
969     State = oldState;		    /* restore State before set_shellsize */
970 #ifdef FEAT_MOUSE
971     setmouse();
972 #endif
973     msg_check();
974 
975 #if defined(UNIX) || defined(VMS)
976     /*
977      * When switching screens, we need to output an extra newline on exit.
978      */
979     if (swapping_screen() && !termcap_active)
980 	newline_on_exit = TRUE;
981 #endif
982 
983     need_wait_return = FALSE;
984     did_wait_return = TRUE;
985     emsg_on_display = FALSE;	/* can delete error message now */
986     lines_left = -1;		/* reset lines_left at next msg_start() */
987     reset_last_sourcing();
988     if (keep_msg != NULL && vim_strsize(keep_msg) >=
989 				  (Rows - cmdline_row - 1) * Columns + sc_col)
990     {
991 	vim_free(keep_msg);
992 	keep_msg = NULL;	    /* don't redisplay message, it's too long */
993     }
994 
995     if (tmpState == SETWSIZE)	    /* got resize event while in vgetc() */
996     {
997 	starttermcap();		    /* start termcap before redrawing */
998 	shell_resized();
999     }
1000     else if (!skip_redraw
1001 	    && (redraw == TRUE || (msg_scrolled != 0 && redraw != -1)))
1002     {
1003 	starttermcap();		    /* start termcap before redrawing */
1004 	redraw_later(VALID);
1005     }
1006 }
1007 
1008 /*
1009  * Write the hit-return prompt.
1010  */
1011     static void
1012 hit_return_msg()
1013 {
1014     if (msg_didout)		    /* start on a new line */
1015 	msg_putchar('\n');
1016     if (got_int)
1017 	MSG_PUTS(_("Interrupt: "));
1018 
1019 #ifdef ORG_HITRETURN
1020     MSG_PUTS_ATTR(_("Hit ENTER to continue"), hl_attr(HLF_R));
1021 #else
1022     MSG_PUTS_ATTR(_("Hit ENTER or type command to continue"), hl_attr(HLF_R));
1023 #endif
1024     if (!msg_use_printf())
1025 	msg_clr_eos();
1026 }
1027 
1028 /*
1029  * Set "keep_msg" to "s".  Free the old value and check for NULL pointer.
1030  */
1031     void
1032 set_keep_msg(s)
1033     char_u	*s;
1034 {
1035     vim_free(keep_msg);
1036     if (s != NULL && msg_silent == 0)
1037 	keep_msg = vim_strsave(s);
1038     else
1039 	keep_msg = NULL;
1040 }
1041 
1042 /*
1043  * Prepare for outputting characters in the command line.
1044  */
1045     void
1046 msg_start()
1047 {
1048     int		did_return = FALSE;
1049 
1050     vim_free(keep_msg);
1051     keep_msg = NULL;			/* don't display old message now */
1052     if (!msg_scroll && full_screen)	/* overwrite last message */
1053     {
1054 	msg_row = cmdline_row;
1055 	msg_col =
1056 #ifdef FEAT_RIGHTLEFT
1057 	    cmdmsg_rl ? Columns - 1 :
1058 #endif
1059 	    0;
1060     }
1061     else if (msg_didout)		    /* start message on next line */
1062     {
1063 	msg_putchar('\n');
1064 	did_return = TRUE;
1065 	if (exmode_active != EXMODE_NORMAL)
1066 	    cmdline_row = msg_row;
1067     }
1068     if (!msg_didany || lines_left < 0)
1069 	msg_starthere();
1070     if (msg_silent == 0)
1071     {
1072 	msg_didout = FALSE;		    /* no output on current line yet */
1073 	cursor_off();
1074     }
1075 
1076     /* when redirecting, may need to start a new line. */
1077     if (!did_return)
1078 	redir_write((char_u *)"\n", -1);
1079 }
1080 
1081 /*
1082  * Note that the current msg position is where messages start.
1083  */
1084     void
1085 msg_starthere()
1086 {
1087     lines_left = cmdline_row;
1088     msg_didany = FALSE;
1089 }
1090 
1091     void
1092 msg_putchar(c)
1093     int		c;
1094 {
1095     msg_putchar_attr(c, 0);
1096 }
1097 
1098     void
1099 msg_putchar_attr(c, attr)
1100     int		c;
1101     int		attr;
1102 {
1103 #ifdef FEAT_MBYTE
1104     char_u	buf[MB_MAXBYTES + 1];
1105 #else
1106     char_u	buf[4];
1107 #endif
1108 
1109     if (IS_SPECIAL(c))
1110     {
1111 	buf[0] = K_SPECIAL;
1112 	buf[1] = K_SECOND(c);
1113 	buf[2] = K_THIRD(c);
1114 	buf[3] = NUL;
1115     }
1116     else
1117     {
1118 #ifdef FEAT_MBYTE
1119 	buf[(*mb_char2bytes)(c, buf)] = NUL;
1120 #else
1121 	buf[0] = c;
1122 	buf[1] = NUL;
1123 #endif
1124     }
1125     msg_puts_attr(buf, attr);
1126 }
1127 
1128     void
1129 msg_outnum(n)
1130     long	n;
1131 {
1132     char_u	buf[20];
1133 
1134     sprintf((char *)buf, "%ld", n);
1135     msg_puts(buf);
1136 }
1137 
1138     void
1139 msg_home_replace(fname)
1140     char_u	*fname;
1141 {
1142     msg_home_replace_attr(fname, 0);
1143 }
1144 
1145 #if defined(FEAT_FIND_ID) || defined(PROTO)
1146     void
1147 msg_home_replace_hl(fname)
1148     char_u	*fname;
1149 {
1150     msg_home_replace_attr(fname, hl_attr(HLF_D));
1151 }
1152 #endif
1153 
1154     static void
1155 msg_home_replace_attr(fname, attr)
1156     char_u  *fname;
1157     int	    attr;
1158 {
1159     char_u	*name;
1160 
1161     name = home_replace_save(NULL, fname);
1162     if (name != NULL)
1163 	msg_outtrans_attr(name, attr);
1164     vim_free(name);
1165 }
1166 
1167 /*
1168  * Output 'len' characters in 'str' (including NULs) with translation
1169  * if 'len' is -1, output upto a NUL character.
1170  * Use attributes 'attr'.
1171  * Return the number of characters it takes on the screen.
1172  */
1173     int
1174 msg_outtrans(str)
1175     char_u	    *str;
1176 {
1177     return msg_outtrans_attr(str, 0);
1178 }
1179 
1180     int
1181 msg_outtrans_attr(str, attr)
1182     char_u	*str;
1183     int		attr;
1184 {
1185     return msg_outtrans_len_attr(str, (int)STRLEN(str), attr);
1186 }
1187 
1188     int
1189 msg_outtrans_len(str, len)
1190     char_u	*str;
1191     int		len;
1192 {
1193     return msg_outtrans_len_attr(str, len, 0);
1194 }
1195 
1196 /*
1197  * Output one character at "p".  Return pointer to the next character.
1198  * Handles multi-byte characters.
1199  */
1200     char_u *
1201 msg_outtrans_one(p, attr)
1202     char_u	*p;
1203     int		attr;
1204 {
1205 #ifdef FEAT_MBYTE
1206     int		l;
1207 
1208     if (has_mbyte && (l = (*mb_ptr2len_check)(p)) > 1)
1209     {
1210 	msg_outtrans_len_attr(p, l, attr);
1211 	return p + l;
1212     }
1213 #endif
1214     msg_puts_attr(transchar_byte(*p), attr);
1215     return p + 1;
1216 }
1217 
1218     int
1219 msg_outtrans_len_attr(msgstr, len, attr)
1220     char_u	*msgstr;
1221     int		len;
1222     int		attr;
1223 {
1224     int		retval = 0;
1225     char_u	*str = msgstr;
1226     char_u	*plain_start = msgstr;
1227     char_u	*s;
1228 #ifdef FEAT_MBYTE
1229     int		mb_l;
1230     int		c;
1231 #endif
1232 
1233     /* if MSG_HIST flag set, add message to history */
1234     if (attr & MSG_HIST)
1235     {
1236 	add_msg_hist(str, len, attr);
1237 	attr &= ~MSG_HIST;
1238     }
1239 
1240 #ifdef FEAT_MBYTE
1241     /* If the string starts with a composing character first draw a space on
1242      * which the composing char can be drawn. */
1243     if (enc_utf8 && utf_iscomposing(utf_ptr2char(msgstr)))
1244 	msg_puts_attr((char_u *)" ", attr);
1245 #endif
1246 
1247     /*
1248      * Go over the string.  Special characters are translated and printed.
1249      * Normal characters are printed several at a time.
1250      */
1251     while (--len >= 0)
1252     {
1253 #ifdef FEAT_MBYTE
1254 	if (enc_utf8)
1255 	    /* Don't include composing chars after the end. */
1256 	    mb_l = utfc_ptr2len_check_len(str, len + 1);
1257 	else if (has_mbyte)
1258 	    mb_l = (*mb_ptr2len_check)(str);
1259 	else
1260 	    mb_l = 1;
1261 	if (has_mbyte && mb_l > 1)
1262 	{
1263 	    c = (*mb_ptr2char)(str);
1264 	    if (vim_isprintc(c))
1265 		/* printable multi-byte char: count the cells. */
1266 		retval += (*mb_ptr2cells)(str);
1267 	    else
1268 	    {
1269 		/* unprintable multi-byte char: print the printable chars so
1270 		 * far and the translation of the unprintable char. */
1271 		if (str > plain_start)
1272 		    msg_puts_attr_len(plain_start, (int)(str - plain_start),
1273 									attr);
1274 		plain_start = str + mb_l;
1275 		msg_puts_attr(transchar(c), attr == 0 ? hl_attr(HLF_8) : attr);
1276 		retval += char2cells(c);
1277 	    }
1278 	    len -= mb_l - 1;
1279 	    str += mb_l;
1280 	}
1281 	else
1282 #endif
1283 	{
1284 	    s = transchar_byte(*str);
1285 	    if (s[1] != NUL)
1286 	    {
1287 		/* unprintable char: print the printable chars so far and the
1288 		 * translation of the unprintable char. */
1289 		if (str > plain_start)
1290 		    msg_puts_attr_len(plain_start, (int)(str - plain_start),
1291 									attr);
1292 		plain_start = str + 1;
1293 		msg_puts_attr(s, attr == 0 ? hl_attr(HLF_8) : attr);
1294 	    }
1295 	    retval += ptr2cells(str);
1296 	    ++str;
1297 	}
1298     }
1299 
1300     if (str > plain_start)
1301 	/* print the printable chars at the end */
1302 	msg_puts_attr_len(plain_start, (int)(str - plain_start), attr);
1303 
1304     return retval;
1305 }
1306 
1307 #if defined(FEAT_QUICKFIX) || defined(PROTO)
1308     void
1309 msg_make(arg)
1310     char_u  *arg;
1311 {
1312     int	    i;
1313     static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB";
1314 
1315     arg = skipwhite(arg);
1316     for (i = 5; *arg && i >= 0; --i)
1317 	if (*arg++ != str[i])
1318 	    break;
1319     if (i < 0)
1320     {
1321 	msg_putchar('\n');
1322 	for (i = 0; rs[i]; ++i)
1323 	    msg_putchar(rs[i] - 3);
1324     }
1325 }
1326 #endif
1327 
1328 /*
1329  * Output the string 'str' upto a NUL character.
1330  * Return the number of characters it takes on the screen.
1331  *
1332  * If K_SPECIAL is encountered, then it is taken in conjunction with the
1333  * following character and shown as <F1>, <S-Up> etc.  Any other character
1334  * which is not printable shown in <> form.
1335  * If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>.
1336  * If a character is displayed in one of these special ways, is also
1337  * highlighted (its highlight name is '8' in the p_hl variable).
1338  * Otherwise characters are not highlighted.
1339  * This function is used to show mappings, where we want to see how to type
1340  * the character/string -- webb
1341  */
1342     int
1343 msg_outtrans_special(strstart, from)
1344     char_u	*strstart;
1345     int		from;	/* TRUE for lhs of a mapping */
1346 {
1347     char_u	*str = strstart;
1348     int		retval = 0;
1349     char_u	*string;
1350     int		attr;
1351     int		len;
1352 
1353     attr = hl_attr(HLF_8);
1354     while (*str != NUL)
1355     {
1356 	/* Leading and trailing spaces need to be displayed in <> form. */
1357 	if ((str == strstart || str[1] == NUL) && *str == ' ')
1358 	{
1359 	    string = (char_u *)"<Space>";
1360 	    ++str;
1361 	}
1362 	else
1363 	    string = str2special(&str, from);
1364 	len = vim_strsize(string);
1365 	/* Highlight special keys */
1366 	msg_puts_attr(string, len > 1
1367 #ifdef FEAT_MBYTE
1368 		&& (*mb_ptr2len_check)(string) <= 1
1369 #endif
1370 		? attr : 0);
1371 	retval += len;
1372     }
1373     return retval;
1374 }
1375 
1376 /*
1377  * Return the printable string for the key codes at "*sp".
1378  * Used for translating the lhs or rhs of a mapping to printable chars.
1379  * Advances "sp" to the next code.
1380  */
1381     char_u *
1382 str2special(sp, from)
1383     char_u	**sp;
1384     int		from;	/* TRUE for lhs of mapping */
1385 {
1386     int			c;
1387     static char_u	buf[7];
1388     char_u		*str = *sp;
1389     int			modifiers = 0;
1390     int			special = FALSE;
1391 
1392 #ifdef FEAT_MBYTE
1393     if (has_mbyte)
1394     {
1395 	char_u	*p;
1396 
1397 	/* Try to un-escape a multi-byte character.  Return the un-escaped
1398 	 * string if it is a multi-byte character. */
1399 	p = mb_unescape(sp);
1400 	if (p != NULL)
1401 	    return p;
1402     }
1403 #endif
1404 
1405     c = *str;
1406     if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
1407     {
1408 	if (str[1] == KS_MODIFIER)
1409 	{
1410 	    modifiers = str[2];
1411 	    str += 3;
1412 	    c = *str;
1413 	}
1414 	if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
1415 	{
1416 	    c = TO_SPECIAL(str[1], str[2]);
1417 	    str += 2;
1418 	    if (c == K_ZERO)	/* display <Nul> as ^@ */
1419 		c = NUL;
1420 	}
1421 	if (IS_SPECIAL(c) || modifiers)	/* special key */
1422 	    special = TRUE;
1423     }
1424     *sp = str + 1;
1425 
1426 #ifdef FEAT_MBYTE
1427     /* For multi-byte characters check for an illegal byte. */
1428     if (has_mbyte && MB_BYTE2LEN(*str) > (*mb_ptr2len_check)(str))
1429     {
1430 	transchar_nonprint(buf, c);
1431 	return buf;
1432     }
1433 #endif
1434 
1435     /* Make unprintable characters in <> form, also <M-Space> and <Tab>.
1436      * Use <Space> only for lhs of a mapping. */
1437     if (special || char2cells(c) > 1 || (from && c == ' '))
1438 	return get_special_key_name(c, modifiers);
1439     buf[0] = c;
1440     buf[1] = NUL;
1441     return buf;
1442 }
1443 
1444 /*
1445  * Translate a key sequence into special key names.
1446  */
1447     void
1448 str2specialbuf(sp, buf, len)
1449     char_u	*sp;
1450     char_u	*buf;
1451     int		len;
1452 {
1453     char_u	*s;
1454 
1455     *buf = NUL;
1456     while (*sp)
1457     {
1458 	s = str2special(&sp, FALSE);
1459 	if ((int)(STRLEN(s) + STRLEN(buf)) < len)
1460 	    STRCAT(buf, s);
1461     }
1462 }
1463 
1464 /*
1465  * print line for :print or :list command
1466  */
1467     void
1468 msg_prt_line(s)
1469     char_u	*s;
1470 {
1471     int		c;
1472     int		col = 0;
1473     int		n_extra = 0;
1474     int		c_extra = 0;
1475     char_u	*p_extra = NULL;	    /* init to make SASC shut up */
1476     int		n;
1477     int		attr= 0;
1478     char_u	*trail = NULL;
1479 #ifdef FEAT_MBYTE
1480     int		l;
1481     char_u	buf[MB_MAXBYTES + 1];
1482 #endif
1483 
1484     /* find start of trailing whitespace */
1485     if (curwin->w_p_list && lcs_trail)
1486     {
1487 	trail = s + STRLEN(s);
1488 	while (trail > s && vim_iswhite(trail[-1]))
1489 	    --trail;
1490     }
1491 
1492     /* output a space for an empty line, otherwise the line will be
1493      * overwritten */
1494     if (*s == NUL && !(curwin->w_p_list && lcs_eol != NUL))
1495 	msg_putchar(' ');
1496 
1497     for (;;)
1498     {
1499 	if (n_extra)
1500 	{
1501 	    --n_extra;
1502 	    if (c_extra)
1503 		c = c_extra;
1504 	    else
1505 		c = *p_extra++;
1506 	}
1507 #ifdef FEAT_MBYTE
1508 	else if (has_mbyte && (l = (*mb_ptr2len_check)(s)) > 1)
1509 	{
1510 	    col += (*mb_ptr2cells)(s);
1511 	    mch_memmove(buf, s, (size_t)l);
1512 	    buf[l] = NUL;
1513 	    msg_puts_attr(buf, attr);
1514 	    s += l;
1515 	    continue;
1516 	}
1517 #endif
1518 	else
1519 	{
1520 	    attr = 0;
1521 	    c = *s++;
1522 	    if (c == TAB && (!curwin->w_p_list || lcs_tab1))
1523 	    {
1524 		/* tab amount depends on current column */
1525 		n_extra = curbuf->b_p_ts - col % curbuf->b_p_ts - 1;
1526 		if (!curwin->w_p_list)
1527 		{
1528 		    c = ' ';
1529 		    c_extra = ' ';
1530 		}
1531 		else
1532 		{
1533 		    c = lcs_tab1;
1534 		    c_extra = lcs_tab2;
1535 		    attr = hl_attr(HLF_8);
1536 		}
1537 	    }
1538 	    else if (c == NUL && curwin->w_p_list && lcs_eol != NUL)
1539 	    {
1540 		p_extra = (char_u *)"";
1541 		c_extra = NUL;
1542 		n_extra = 1;
1543 		c = lcs_eol;
1544 		attr = hl_attr(HLF_AT);
1545 		--s;
1546 	    }
1547 	    else if (c != NUL && (n = byte2cells(c)) > 1)
1548 	    {
1549 		n_extra = n - 1;
1550 		p_extra = transchar_byte(c);
1551 		c_extra = NUL;
1552 		c = *p_extra++;
1553 	    }
1554 	    else if (c == ' ' && trail != NULL && s > trail)
1555 	    {
1556 		c = lcs_trail;
1557 		attr = hl_attr(HLF_8);
1558 	    }
1559 	}
1560 
1561 	if (c == NUL)
1562 	    break;
1563 
1564 	msg_putchar_attr(c, attr);
1565 	col++;
1566     }
1567     msg_clr_eos();
1568 }
1569 
1570 #ifdef FEAT_MBYTE
1571 /*
1572  * Use screen_puts() to output one multi-byte character.
1573  * Return the pointer "s" advanced to the next character.
1574  */
1575     static char_u *
1576 screen_puts_mbyte(s, l, attr)
1577     char_u	*s;
1578     int		l;
1579     int		attr;
1580 {
1581     int		cw;
1582 
1583     msg_didout = TRUE;		/* remember that line is not empty */
1584     cw = (*mb_ptr2cells)(s);
1585     if (cw > 1 && (
1586 #ifdef FEAT_RIGHTLEFT
1587 		cmdmsg_rl ? msg_col <= 1 :
1588 #endif
1589 		msg_col == Columns - 1))
1590     {
1591 	/* Doesn't fit, print a highlighted '>' to fill it up. */
1592 	msg_screen_putchar('>', hl_attr(HLF_AT));
1593 	return s;
1594     }
1595 
1596     screen_puts_len(s, l, msg_row, msg_col, attr);
1597 #ifdef FEAT_RIGHTLEFT
1598     if (cmdmsg_rl)
1599     {
1600 	msg_col -= cw;
1601 	if (msg_col == 0)
1602 	{
1603 	    msg_col = Columns;
1604 	    ++msg_row;
1605 	}
1606     }
1607     else
1608 #endif
1609     {
1610 	msg_col += cw;
1611 	if (msg_col >= Columns)
1612 	{
1613 	    msg_col = 0;
1614 	    ++msg_row;
1615 	}
1616     }
1617     return s + l;
1618 }
1619 #endif
1620 
1621 /*
1622  * Output a string to the screen at position msg_row, msg_col.
1623  * Update msg_row and msg_col for the next message.
1624  */
1625     void
1626 msg_puts(s)
1627     char_u	*s;
1628 {
1629     msg_puts_attr(s, 0);
1630 }
1631 
1632     void
1633 msg_puts_title(s)
1634     char_u	*s;
1635 {
1636     msg_puts_attr(s, hl_attr(HLF_T));
1637 }
1638 
1639 #if defined(FEAT_CSCOPE) || defined(PROTO)
1640 /*
1641  * if printing a string will exceed the screen width, print "..." in the
1642  * middle.
1643  */
1644     void
1645 msg_puts_long(longstr)
1646     char_u	*longstr;
1647 {
1648     msg_puts_long_len_attr(longstr, (int)strlen((char *)longstr), 0);
1649 }
1650 #endif
1651 
1652 /*
1653  * Show a message in such a way that it always fits in the line.  Cut out a
1654  * part in the middle and replace it with "..." when necessary.
1655  * Does not handle multi-byte characters!
1656  */
1657     void
1658 msg_puts_long_attr(longstr, attr)
1659     char_u	*longstr;
1660     int		attr;
1661 {
1662     msg_puts_long_len_attr(longstr, (int)strlen((char *)longstr), attr);
1663 }
1664 
1665     void
1666 msg_puts_long_len_attr(longstr, len, attr)
1667     char_u	*longstr;
1668     int		len;
1669     int		attr;
1670 {
1671     int		slen = len;
1672     int		room;
1673 
1674     room = Columns - msg_col;
1675     if (len > room && room >= 20)
1676     {
1677 	slen = (room - 3) / 2;
1678 	msg_outtrans_len_attr(longstr, slen, attr);
1679 	msg_puts_attr((char_u *)"...", hl_attr(HLF_8));
1680     }
1681     msg_outtrans_len_attr(longstr + len - slen, slen, attr);
1682 }
1683 
1684 /*
1685  * Basic function for writing a message with highlight attributes.
1686  */
1687     void
1688 msg_puts_attr(s, attr)
1689     char_u	*s;
1690     int		attr;
1691 {
1692     msg_puts_attr_len(s, -1, attr);
1693 }
1694 
1695 /*
1696  * Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes).
1697  * When "maxlen" is -1 there is no maximum length.
1698  * When "maxlen" is >= 0 the message is not put in the history.
1699  */
1700     static void
1701 msg_puts_attr_len(str, maxlen, attr)
1702     char_u	*str;
1703     int		maxlen;
1704     int		attr;
1705 {
1706     int		oldState;
1707     char_u	*s = str;
1708     char_u	*p;
1709     char_u	buf[4];
1710     char_u	*t_s = str;	/* string from "t_s" to "s" is still todo */
1711     int		t_col = 0;	/* screen cells todo, 0 when "t_s" not used */
1712 #ifdef FEAT_MBYTE
1713     int		l;
1714     int		cw;
1715 #endif
1716     int		c;
1717 
1718     /*
1719      * If redirection is on, also write to the redirection file.
1720      */
1721     redir_write(s, maxlen);
1722 
1723     /*
1724      * Don't print anything when using ":silent cmd".
1725      */
1726     if (msg_silent != 0)
1727 	return;
1728 
1729     /* if MSG_HIST flag set, add message to history */
1730     if ((attr & MSG_HIST) && maxlen < 0)
1731     {
1732 	add_msg_hist(s, -1, attr);
1733 	attr &= ~MSG_HIST;
1734     }
1735 
1736     /*
1737      * When writing something to the screen after it has scrolled, requires a
1738      * wait-return prompt later.  Needed when scrolling, resetting
1739      * need_wait_return after some prompt, and then outputting something
1740      * without scrolling
1741      */
1742     if (msg_scrolled && !msg_scrolled_ign)
1743 	need_wait_return = TRUE;
1744     msg_didany = TRUE;		/* remember that something was outputted */
1745 
1746     /*
1747      * If there is no valid screen, use fprintf so we can see error messages.
1748      * If termcap is not active, we may be writing in an alternate console
1749      * window, cursor positioning may not work correctly (window size may be
1750      * different, e.g. for Win32 console) or we just don't know where the
1751      * cursor is.
1752      */
1753     if (msg_use_printf())
1754     {
1755 #ifdef WIN3264
1756 	if (!(silent_mode && p_verbose == 0))
1757 	    mch_settmode(TMODE_COOK);	/* handle '\r' and '\n' correctly */
1758 #endif
1759 	while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
1760 	{
1761 	    if (!(silent_mode && p_verbose == 0))
1762 	    {
1763 		p = &buf[0];
1764 		/* NL --> CR NL translation (for Unix, not for "--version") */
1765 		/* NL --> CR translation (for Mac) */
1766 		if (*s == '\n' && !info_message)
1767 		    *p++ = '\r';
1768 #if defined(USE_CR) && !defined(MACOS_X_UNIX)
1769 		else
1770 #endif
1771 		    *p++ = *s;
1772 		*p = '\0';
1773 		if (info_message)	/* informative message, not an error */
1774 		    mch_msg((char *)buf);
1775 		else
1776 		    mch_errmsg((char *)buf);
1777 	    }
1778 
1779 	    /* primitive way to compute the current column */
1780 #ifdef FEAT_RIGHTLEFT
1781 	    if (cmdmsg_rl)
1782 	    {
1783 		if (*s == '\r' || *s == '\n')
1784 		    msg_col = Columns - 1;
1785 		else
1786 		    --msg_col;
1787 	    }
1788 	    else
1789 #endif
1790 	    {
1791 		if (*s == '\r' || *s == '\n')
1792 		    msg_col = 0;
1793 		else
1794 		    ++msg_col;
1795 	    }
1796 	    ++s;
1797 	}
1798 	msg_didout = TRUE;	    /* assume that line is not empty */
1799 
1800 #ifdef WIN3264
1801 	if (!(silent_mode && p_verbose == 0))
1802 	    mch_settmode(TMODE_RAW);
1803 #endif
1804 	return;
1805     }
1806 
1807     did_wait_return = FALSE;
1808     while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
1809     {
1810 	/*
1811 	 * The screen is scrolled up when:
1812 	 * - When outputting a newline in the last row
1813 	 * - when outputting a character in the last column of the last row
1814 	 *   (some terminals scroll automatically, some don't. To avoid
1815 	 *   problems we scroll ourselves)
1816 	 */
1817 	if (msg_row >= Rows - 1
1818 		&& (*s == '\n'
1819 		    || (
1820 #ifdef FEAT_RIGHTLEFT
1821 		    cmdmsg_rl
1822 		    ? (
1823 			msg_col <= 1
1824 			|| (*s == TAB && msg_col <= 7)
1825 # ifdef FEAT_MBYTE
1826 			|| (has_mbyte && (*mb_ptr2cells)(s) > 1 && msg_col <= 2)
1827 # endif
1828 		      )
1829 		    :
1830 #endif
1831 		      (msg_col + t_col >= Columns - 1
1832 		       || (*s == TAB && msg_col + t_col >= ((Columns - 1) & ~7))
1833 # ifdef FEAT_MBYTE
1834 		       || (has_mbyte && (*mb_ptr2cells)(s) > 1
1835 					    && msg_col + t_col >= Columns - 2)
1836 # endif
1837 		      ))))
1838 	{
1839 	    if (t_col > 0)
1840 	    {
1841 		/* output postponed text */
1842 		t_puts(t_col, t_s, s, attr);
1843 		t_col = 0;
1844 	    }
1845 
1846 	    /* When no more prompt an no more room, truncate here */
1847 	    if (msg_no_more && lines_left == 0)
1848 		break;
1849 #ifdef FEAT_GUI
1850 	    /* Remove the cursor before scrolling, ScreenLines[] is going to
1851 	     * become invalid. */
1852 	    if (gui.in_use)
1853 		gui_undraw_cursor();
1854 #endif
1855 	    /* scrolling up always works */
1856 	    screen_del_lines(0, 0, 1, (int)Rows, TRUE, NULL);
1857 
1858 	    if (!can_clear((char_u *)" "))
1859 	    {
1860 		/* Scrolling up doesn't result in the right background.  Set
1861 		 * the background here.  It's not efficient, but avoids that
1862 		 * we have to do it all over the code. */
1863 		screen_fill((int)Rows - 1, (int)Rows, 0,
1864 						   (int)Columns, ' ', ' ', 0);
1865 
1866 		/* Also clear the last char of the last but one line if it was
1867 		 * not cleared before to avoid a scroll-up. */
1868 		if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1]
1869 							       == (sattr_T)-1)
1870 		    screen_fill((int)Rows - 2, (int)Rows - 1,
1871 				 (int)Columns - 1, (int)Columns, ' ', ' ', 0);
1872 	    }
1873 
1874 	    msg_row = Rows - 2;
1875 	    if (msg_col >= Columns)	/* can happen after screen resize */
1876 		msg_col = Columns - 1;
1877 
1878 	    ++msg_scrolled;
1879 	    need_wait_return = TRUE;	/* may need wait_return in main() */
1880 	    if (must_redraw < VALID)
1881 		must_redraw = VALID;
1882 	    redraw_cmdline = TRUE;
1883 	    if (cmdline_row > 0 && !exmode_active)
1884 		--cmdline_row;
1885 
1886 	    /*
1887 	     * if screen is completely filled wait for a character
1888 	     */
1889 	    if (p_more && --lines_left == 0 && State != HITRETURN
1890 					    && !msg_no_more && !exmode_active)
1891 	    {
1892 		oldState = State;
1893 		State = ASKMORE;
1894 #ifdef FEAT_MOUSE
1895 		setmouse();
1896 #endif
1897 		msg_moremsg(FALSE);
1898 		for (;;)
1899 		{
1900 		    /*
1901 		     * Get a typed character directly from the user.
1902 		     */
1903 		    c = get_keystroke();
1904 
1905 #if defined(FEAT_MENU) && defined(FEAT_GUI)
1906 		    if (c == K_MENU)
1907 		    {
1908 			int idx = get_menu_index(current_menu, ASKMORE);
1909 
1910 			/* Used a menu.  If it starts with CTRL-Y, it must
1911 			 * be a "Copy" for the clipboard.  Otherwise
1912 			 * assume that we end */
1913 			if (idx == MENU_INDEX_INVALID)
1914 			    continue;
1915 			c = *current_menu->strings[idx];
1916 			if (c != NUL && current_menu->strings[idx][1] != NUL)
1917 			    ins_typebuf(current_menu->strings[idx] + 1,
1918 				    current_menu->noremap[idx], 0, TRUE,
1919 				    current_menu->silent[idx]);
1920 		    }
1921 #endif
1922 
1923 		    switch (c)
1924 		    {
1925 		    case BS:
1926 		    case 'k':
1927 		    case K_UP:
1928 			if (!more_back_used)
1929 			{
1930 			    msg_moremsg(TRUE);
1931 			    continue;
1932 			}
1933 			more_back = 1;
1934 			lines_left = 1;
1935 			break;
1936 		    case CAR:		/* one extra line */
1937 		    case NL:
1938 		    case 'j':
1939 		    case K_DOWN:
1940 			lines_left = 1;
1941 			break;
1942 		    case ':':		/* start new command line */
1943 #ifdef FEAT_CON_DIALOG
1944 			if (!confirm_msg_used)
1945 #endif
1946 			{
1947 			    /* Since got_int is set all typeahead will be
1948 			     * flushed, but we want to keep this ':', remember
1949 			     * that in a special way. */
1950 			    typeahead_noflush(':');
1951 			    cmdline_row = Rows - 1;   /* put ':' on this line */
1952 			    skip_redraw = TRUE;	      /* skip redraw once */
1953 			    need_wait_return = FALSE; /* don't wait in main() */
1954 			}
1955 			/*FALLTHROUGH*/
1956 		    case 'q':		/* quit */
1957 		    case Ctrl_C:
1958 		    case ESC:
1959 #ifdef FEAT_CON_DIALOG
1960 			if (confirm_msg_used)
1961 			{
1962 			    /* Jump to the choices of the dialog. */
1963 			    s = confirm_msg_tail;
1964 			    lines_left = Rows - 1;
1965 			}
1966 			else
1967 #endif
1968 			{
1969 			    got_int = TRUE;
1970 			    quit_more = TRUE;
1971 			}
1972 			break;
1973 		    case 'u':		/* Up half a page */
1974 		    case K_PAGEUP:
1975 			if (!more_back_used)
1976 			{
1977 			    msg_moremsg(TRUE);
1978 			    continue;
1979 			}
1980 			more_back = Rows / 2;
1981 			/*FALLTHROUGH*/
1982 		    case 'd':		/* Down half a page */
1983 			lines_left = Rows / 2;
1984 			break;
1985 		    case 'b':		/* one page back */
1986 			if (!more_back_used)
1987 			{
1988 			    msg_moremsg(TRUE);
1989 			    continue;
1990 			}
1991 			more_back = Rows - 1;
1992 			/*FALLTHROUGH*/
1993 		    case ' ':		/* one extra page */
1994 		    case K_PAGEDOWN:
1995 		    case K_LEFTMOUSE:
1996 			lines_left = Rows - 1;
1997 			break;
1998 
1999 #ifdef FEAT_CLIPBOARD
2000 		    case Ctrl_Y:
2001 			/* Strange way to allow copying (yanking) a modeless
2002 			 * selection at the more prompt.  Use CTRL-Y,
2003 			 * because the same is used in Cmdline-mode and at the
2004 			 * hit-enter prompt.  However, scrolling one line up
2005 			 * might be expected... */
2006 			if (clip_star.state == SELECT_DONE)
2007 			    clip_copy_modeless_selection(TRUE);
2008 			continue;
2009 #endif
2010 		    default:		/* no valid response */
2011 			msg_moremsg(TRUE);
2012 			continue;
2013 		    }
2014 		    break;
2015 		}
2016 
2017 		/* clear the --more-- message */
2018 		screen_fill((int)Rows - 1, (int)Rows,
2019 						0, (int)Columns, ' ', ' ', 0);
2020 		State = oldState;
2021 #ifdef FEAT_MOUSE
2022 		setmouse();
2023 #endif
2024 		if (quit_more)
2025 		{
2026 		    msg_row = Rows - 1;
2027 		    msg_col = 0;
2028 		    return;	    /* the string is not displayed! */
2029 		}
2030 #ifdef FEAT_RIGHTLEFT
2031 		if (cmdmsg_rl)
2032 		    msg_col = Columns - 1;
2033 #endif
2034 	    }
2035 	}
2036 
2037 	if (t_col > 0
2038 		&& (vim_strchr((char_u *)"\n\r\b\t", *s) != NULL
2039 		    || *s == BELL
2040 		    || msg_col + t_col >= Columns
2041 #ifdef FEAT_MBYTE
2042 		    || (has_mbyte && (*mb_ptr2cells)(s) > 1
2043 					    && msg_col + t_col >= Columns - 1)
2044 #endif
2045 		    ))
2046 	{
2047 	    /* output any postponed text */
2048 	    t_puts(t_col, t_s, s, attr);
2049 	    t_col = 0;
2050 	}
2051 
2052 	if (*s == '\n')		    /* go to next line */
2053 	{
2054 	    msg_didout = FALSE;	    /* remember that line is empty */
2055 	    msg_col = 0;
2056 	    if (++msg_row >= Rows)  /* safety check */
2057 		msg_row = Rows - 1;
2058 	}
2059 	else if (*s == '\r')	    /* go to column 0 */
2060 	{
2061 	    msg_col = 0;
2062 	}
2063 	else if (*s == '\b')	    /* go to previous char */
2064 	{
2065 	    if (msg_col)
2066 		--msg_col;
2067 	}
2068 	else if (*s == TAB)	    /* translate into spaces */
2069 	{
2070 	    do
2071 		msg_screen_putchar(' ', attr);
2072 	    while (msg_col & 7);
2073 	}
2074 	else if (*s == BELL)	    /* beep (from ":sh") */
2075 	    vim_beep();
2076 	else
2077 	{
2078 #ifdef FEAT_MBYTE
2079 	    if (has_mbyte)
2080 	    {
2081 		cw = (*mb_ptr2cells)(s);
2082 		if (enc_utf8 && maxlen >= 0)
2083 		    /* avoid including composing chars after the end */
2084 		    l = utfc_ptr2len_check_len(s, (int)((str + maxlen) - s));
2085 		else
2086 		    l = (*mb_ptr2len_check)(s);
2087 	    }
2088 	    else
2089 	    {
2090 		cw = 1;
2091 		l = 1;
2092 	    }
2093 #endif
2094 	    /* When drawing from right to left or when a double-wide character
2095 	     * doesn't fit, draw a single character here.  Otherwise collect
2096 	     * characters and draw them all at once later. */
2097 #if defined(FEAT_RIGHTLEFT) || defined(FEAT_MBYTE)
2098 	    if (
2099 # ifdef FEAT_RIGHTLEFT
2100 		    cmdmsg_rl
2101 #  ifdef FEAT_MBYTE
2102 		    ||
2103 #  endif
2104 # endif
2105 # ifdef FEAT_MBYTE
2106 		    (cw > 1 && msg_col + t_col >= Columns - 1)
2107 # endif
2108 		    )
2109 	    {
2110 # ifdef FEAT_MBYTE
2111 		if (l > 1)
2112 		    s = screen_puts_mbyte(s, l, attr) - 1;
2113 		else
2114 # endif
2115 		    msg_screen_putchar(*s, attr);
2116 	    }
2117 	    else
2118 #endif
2119 	    {
2120 		/* postpone this character until later */
2121 		if (t_col == 0)
2122 		    t_s = s;
2123 #ifdef FEAT_MBYTE
2124 		t_col += cw;
2125 		s += l - 1;
2126 #else
2127 		++t_col;
2128 #endif
2129 	    }
2130 	}
2131 	++s;
2132     }
2133 
2134     /* output any postponed text */
2135     if (t_col > 0)
2136 	t_puts(t_col, t_s, s, attr);
2137 
2138     msg_check();
2139 }
2140 
2141 /*
2142  * Output any postponed text for msg_puts_attr_len().
2143  */
2144     static void
2145 t_puts(t_col, t_s, s, attr)
2146     int		t_col;
2147     char_u	*t_s;
2148     char_u	*s;
2149     int		attr;
2150 {
2151     /* output postponed text */
2152     msg_didout = TRUE;		/* remember that line is not empty */
2153     screen_puts_len(t_s, (int)(s - t_s), msg_row, msg_col, attr);
2154     msg_col += t_col;
2155 #ifdef FEAT_MBYTE
2156     /* If the string starts with a composing character don't increment the
2157      * column position for it. */
2158     if (enc_utf8 && utf_iscomposing(utf_ptr2char(t_s)))
2159 	--msg_col;
2160 #endif
2161     if (msg_col >= Columns)
2162     {
2163 	msg_col = 0;
2164 	++msg_row;
2165     }
2166 }
2167 
2168 
2169 /*
2170  * Returns TRUE when messages should be printed with mch_errmsg().
2171  * This is used when there is no valid screen, so we can see error messages.
2172  * If termcap is not active, we may be writing in an alternate console
2173  * window, cursor positioning may not work correctly (window size may be
2174  * different, e.g. for Win32 console) or we just don't know where the
2175  * cursor is.
2176  */
2177     int
2178 msg_use_printf()
2179 {
2180     return (!msg_check_screen()
2181 #if defined(WIN3264) && !defined(FEAT_GUI_MSWIN)
2182 	    || !termcap_active
2183 #endif
2184 	    || (swapping_screen() && !termcap_active)
2185 	       );
2186 }
2187 
2188 #if defined(USE_MCH_ERRMSG) || defined(PROTO)
2189 
2190 #ifdef mch_errmsg
2191 # undef mch_errmsg
2192 #endif
2193 #ifdef mch_msg
2194 # undef mch_msg
2195 #endif
2196 
2197 /*
2198  * Give an error message.  To be used when the screen hasn't been initialized
2199  * yet.  When stderr can't be used, collect error messages until the GUI has
2200  * started and they can be displayed in a message box.
2201  */
2202     void
2203 mch_errmsg(str)
2204     char	*str;
2205 {
2206     int		len;
2207 
2208 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI)
2209     /* On Unix use stderr if it's a tty.
2210      * When not going to start the GUI also use stderr.
2211      * On Mac, when started from Finder, stderr is the console. */
2212     if (
2213 # ifdef UNIX
2214 #  ifdef MACOS_X_UNIX
2215 	    (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0)
2216 #  else
2217 	    isatty(2)
2218 #  endif
2219 #  ifdef FEAT_GUI
2220 	    ||
2221 #  endif
2222 # endif
2223 # ifdef FEAT_GUI
2224 	    !(gui.in_use || gui.starting)
2225 # endif
2226 	    )
2227     {
2228 	fprintf(stderr, "%s", str);
2229 	return;
2230     }
2231 #endif
2232 
2233     /* avoid a delay for a message that isn't there */
2234     emsg_on_display = FALSE;
2235 
2236     len = (int)STRLEN(str) + 1;
2237     if (error_ga.ga_growsize == 0)
2238     {
2239 	error_ga.ga_growsize = 80;
2240 	error_ga.ga_itemsize = 1;
2241     }
2242     if (ga_grow(&error_ga, len) == OK)
2243     {
2244 	mch_memmove((char_u *)error_ga.ga_data + error_ga.ga_len,
2245 							  (char_u *)str, len);
2246 #ifdef UNIX
2247 	/* remove CR characters, they are displayed */
2248 	{
2249 	    char_u	*p;
2250 
2251 	    p = (char_u *)error_ga.ga_data + error_ga.ga_len;
2252 	    for (;;)
2253 	    {
2254 		p = vim_strchr(p, '\r');
2255 		if (p == NULL)
2256 		    break;
2257 		*p = ' ';
2258 	    }
2259 	}
2260 #endif
2261 	--len;		/* don't count the NUL at the end */
2262 	error_ga.ga_len += len;
2263 	error_ga.ga_room -= len;
2264     }
2265 }
2266 
2267 /*
2268  * Give a message.  To be used when the screen hasn't been initialized yet.
2269  * When there is no tty, collect messages until the GUI has started and they
2270  * can be displayed in a message box.
2271  */
2272     void
2273 mch_msg(str)
2274     char	*str;
2275 {
2276 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI)
2277     /* On Unix use stdout if we have a tty.  This allows "vim -h | more" and
2278      * uses mch_errmsg() when started from the desktop.
2279      * When not going to start the GUI also use stdout.
2280      * On Mac, when started from Finder, stderr is the console. */
2281     if (
2282 #  ifdef UNIX
2283 #   ifdef MACOS_X_UNIX
2284 	    (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0)
2285 #   else
2286 	    isatty(2)
2287 #    endif
2288 #   ifdef FEAT_GUI
2289 	    ||
2290 #   endif
2291 #  endif
2292 #  ifdef FEAT_GUI
2293 	    !(gui.in_use || gui.starting)
2294 #  endif
2295 	    )
2296     {
2297 	printf("%s", str);
2298 	return;
2299     }
2300 # endif
2301     mch_errmsg(str);
2302 }
2303 #endif /* USE_MCH_ERRMSG */
2304 
2305 /*
2306  * Put a character on the screen at the current message position and advance
2307  * to the next position.  Only for printable ASCII!
2308  */
2309     static void
2310 msg_screen_putchar(c, attr)
2311     int		c;
2312     int		attr;
2313 {
2314     msg_didout = TRUE;		/* remember that line is not empty */
2315     screen_putchar(c, msg_row, msg_col, attr);
2316 #ifdef FEAT_RIGHTLEFT
2317     if (cmdmsg_rl)
2318     {
2319 	if (--msg_col == 0)
2320 	{
2321 	    msg_col = Columns;
2322 	    ++msg_row;
2323 	}
2324     }
2325     else
2326 #endif
2327     {
2328 	if (++msg_col >= Columns)
2329 	{
2330 	    msg_col = 0;
2331 	    ++msg_row;
2332 	}
2333     }
2334 }
2335 
2336     void
2337 msg_moremsg(full)
2338     int	    full;
2339 {
2340     int	    attr;
2341 
2342     attr = hl_attr(HLF_M);
2343     screen_puts((char_u *)_("-- More --"), (int)Rows - 1, 0, attr);
2344     if (full)
2345 	screen_puts(more_back_used
2346 	    ? (char_u *)_(" (RET/BS: line, SPACE/b: page, d/u: half page, q: quit)")
2347 	    : (char_u *)_(" (RET: line, SPACE: page, d: half page, q: quit)"),
2348 	    (int)Rows - 1, 10, attr);
2349 }
2350 
2351 /*
2352  * Repeat the message for the current mode: ASKMORE, EXTERNCMD, CONFIRM or
2353  * exmode_active.
2354  */
2355     void
2356 repeat_message()
2357 {
2358     if (State == ASKMORE)
2359     {
2360 	msg_moremsg(TRUE);	/* display --more-- message again */
2361 	msg_row = Rows - 1;
2362     }
2363 #ifdef FEAT_CON_DIALOG
2364     else if (State == CONFIRM)
2365     {
2366 	display_confirm_msg();	/* display ":confirm" message again */
2367 	msg_row = Rows - 1;
2368     }
2369 #endif
2370     else if (State == EXTERNCMD)
2371     {
2372 	windgoto(msg_row, msg_col); /* put cursor back */
2373     }
2374     else if (State == HITRETURN || State == SETWSIZE)
2375     {
2376 	hit_return_msg();
2377 	msg_row = Rows - 1;
2378     }
2379 }
2380 
2381 /*
2382  * msg_check_screen - check if the screen is initialized.
2383  * Also check msg_row and msg_col, if they are too big it may cause a crash.
2384  * While starting the GUI the terminal codes will be set for the GUI, but the
2385  * output goes to the terminal.  Don't use the terminal codes then.
2386  */
2387     static int
2388 msg_check_screen()
2389 {
2390     if (!full_screen || !screen_valid(FALSE))
2391 	return FALSE;
2392 
2393     if (msg_row >= Rows)
2394 	msg_row = Rows - 1;
2395     if (msg_col >= Columns)
2396 	msg_col = Columns - 1;
2397     return TRUE;
2398 }
2399 
2400 /*
2401  * Clear from current message position to end of screen.
2402  * Skip this when ":silent" was used, no need to clear for redirection.
2403  */
2404     void
2405 msg_clr_eos()
2406 {
2407     if (msg_silent == 0)
2408 	msg_clr_eos_force();
2409 }
2410 
2411 /*
2412  * Clear from current message position to end of screen.
2413  * Note: msg_col is not updated, so we remember the end of the message
2414  * for msg_check().
2415  */
2416     void
2417 msg_clr_eos_force()
2418 {
2419     if (msg_use_printf())
2420     {
2421 	if (full_screen)	/* only when termcap codes are valid */
2422 	{
2423 	    if (*T_CD)
2424 		out_str(T_CD);	/* clear to end of display */
2425 	    else if (*T_CE)
2426 		out_str(T_CE);	/* clear to end of line */
2427 	}
2428     }
2429     else
2430     {
2431 #ifdef FEAT_RIGHTLEFT
2432 	if (cmdmsg_rl)
2433 	{
2434 	    screen_fill(msg_row, msg_row + 1, 0, msg_col + 1, ' ', ' ', 0);
2435 	    screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
2436 	}
2437 	else
2438 #endif
2439 	{
2440 	    screen_fill(msg_row, msg_row + 1, msg_col, (int)Columns,
2441 								 ' ', ' ', 0);
2442 	    screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
2443 	}
2444     }
2445 }
2446 
2447 /*
2448  * Clear the command line.
2449  */
2450     void
2451 msg_clr_cmdline()
2452 {
2453     msg_row = cmdline_row;
2454     msg_col = 0;
2455     msg_clr_eos_force();
2456 }
2457 
2458 /*
2459  * end putting a message on the screen
2460  * call wait_return if the message does not fit in the available space
2461  * return TRUE if wait_return not called.
2462  */
2463     int
2464 msg_end()
2465 {
2466     /*
2467      * if the string is larger than the window,
2468      * or the ruler option is set and we run into it,
2469      * we have to redraw the window.
2470      * Do not do this if we are abandoning the file or editing the command line.
2471      */
2472     if (!exiting && need_wait_return && !(State & CMDLINE))
2473     {
2474 	wait_return(FALSE);
2475 	return FALSE;
2476     }
2477     out_flush();
2478     return TRUE;
2479 }
2480 
2481 /*
2482  * If the written message runs into the shown command or ruler, we have to
2483  * wait for hit-return and redraw the window later.
2484  */
2485     void
2486 msg_check()
2487 {
2488     if (msg_row == Rows - 1 && msg_col >= sc_col)
2489     {
2490 	need_wait_return = TRUE;
2491 	redraw_cmdline = TRUE;
2492     }
2493 }
2494 
2495 /*
2496  * May write a string to the redirection file.
2497  * When "maxlen" is -1 write the whole string, otherwise up to "maxlen" bytes.
2498  */
2499     static void
2500 redir_write(str, maxlen)
2501     char_u	*str;
2502     int		maxlen;
2503 {
2504     char_u	*s = str;
2505     static int	cur_col = 0;
2506 
2507     if ((redir_fd != NULL
2508 #ifdef FEAT_EVAL
2509 			  || redir_reg
2510 #endif
2511 				       ) && !redir_off)
2512     {
2513 	/* If the string doesn't start with CR or NL, go to msg_col */
2514 	if (*s != '\n' && *s != '\r')
2515 	{
2516 	    while (cur_col < msg_col)
2517 	    {
2518 #ifdef FEAT_EVAL
2519 		if (redir_reg)
2520 		    write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE);
2521 		else if (redir_fd)
2522 #endif
2523 		    fputs(" ", redir_fd);
2524 		++cur_col;
2525 	    }
2526 	}
2527 
2528 #ifdef FEAT_EVAL
2529 	if (redir_reg)
2530 	    write_reg_contents(redir_reg, s, maxlen, TRUE);
2531 #endif
2532 
2533 	/* Adjust the current column */
2534 	while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen))
2535 	{
2536 #ifdef FEAT_EVAL
2537 	    if (!redir_reg && redir_fd != NULL)
2538 #endif
2539 		putc(*s, redir_fd);
2540 	    if (*s == '\r' || *s == '\n')
2541 		cur_col = 0;
2542 	    else if (*s == '\t')
2543 		cur_col += (8 - cur_col % 8);
2544 	    else
2545 		++cur_col;
2546 	    ++s;
2547 	}
2548 
2549 	if (msg_silent != 0)	/* should update msg_col */
2550 	    msg_col = cur_col;
2551     }
2552 }
2553 
2554 /*
2555  * Give a warning message (for searching).
2556  * Use 'w' highlighting and may repeat the message after redrawing
2557  */
2558     void
2559 give_warning(message, hl)
2560     char_u  *message;
2561     int	    hl;
2562 {
2563     /* Don't do this for ":silent". */
2564     if (msg_silent != 0)
2565 	return;
2566 
2567     /* Don't want a hit-enter prompt here. */
2568     ++no_wait_return;
2569 
2570 #ifdef FEAT_EVAL
2571     set_vim_var_string(VV_WARNINGMSG, message, -1);
2572 #endif
2573     vim_free(keep_msg);
2574     keep_msg = NULL;
2575     if (hl)
2576 	keep_msg_attr = hl_attr(HLF_W);
2577     else
2578 	keep_msg_attr = 0;
2579     if (msg_attr(message, keep_msg_attr) && msg_scrolled == 0)
2580 	set_keep_msg(message);
2581     msg_didout = FALSE;	    /* overwrite this message */
2582     msg_nowait = TRUE;	    /* don't wait for this message */
2583     msg_col = 0;
2584 
2585     --no_wait_return;
2586 }
2587 
2588 /*
2589  * Advance msg cursor to column "col".
2590  */
2591     void
2592 msg_advance(col)
2593     int	    col;
2594 {
2595     if (msg_silent != 0)	/* nothing to advance to */
2596     {
2597 	msg_col = col;		/* for redirection, may fill it up later */
2598 	return;
2599     }
2600     if (col >= Columns)		/* not enough room */
2601 	col = Columns - 1;
2602     while (msg_col < col)
2603 	msg_putchar(' ');
2604 }
2605 
2606 #if defined(FEAT_CON_DIALOG) || defined(PROTO)
2607 /*
2608  * Used for "confirm()" function, and the :confirm command prefix.
2609  * Versions which haven't got flexible dialogs yet, and console
2610  * versions, get this generic handler which uses the command line.
2611  *
2612  * type  = one of:
2613  *	   VIM_QUESTION, VIM_INFO, VIM_WARNING, VIM_ERROR or VIM_GENERIC
2614  * title = title string (can be NULL for default)
2615  * (neither used in console dialogs at the moment)
2616  *
2617  * Format of the "buttons" string:
2618  * "Button1Name\nButton2Name\nButton3Name"
2619  * The first button should normally be the default/accept
2620  * The second button should be the 'Cancel' button
2621  * Other buttons- use your imagination!
2622  * A '&' in a button name becomes a shortcut, so each '&' should be before a
2623  * different letter.
2624  */
2625 /* ARGSUSED */
2626     int
2627 do_dialog(type, title, message, buttons, dfltbutton, textfield)
2628     int		type;
2629     char_u	*title;
2630     char_u	*message;
2631     char_u	*buttons;
2632     int		dfltbutton;
2633     char_u	*textfield;	/* IObuff for inputdialog(), NULL otherwise */
2634 {
2635     int		oldState;
2636     int		retval = 0;
2637     char_u	*hotkeys;
2638     int		c;
2639     int		i;
2640 
2641 #ifndef NO_CONSOLE
2642     /* Don't output anything in silent mode ("ex -s") */
2643     if (silent_mode)
2644 	return dfltbutton;   /* return default option */
2645 #endif
2646 
2647 #ifdef FEAT_GUI_DIALOG
2648     /* When GUI is running and 'c' not in 'guioptions', use the GUI dialog */
2649     if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL)
2650     {
2651 	c = gui_mch_dialog(type, title, message, buttons, dfltbutton,
2652 								   textfield);
2653 	msg_end_prompt();
2654 
2655 	/* Flush output to avoid that further messages and redrawing is done
2656 	 * in the wrong order. */
2657 	out_flush();
2658 	gui_mch_update();
2659 
2660 	return c;
2661     }
2662 #endif
2663 
2664     oldState = State;
2665     State = CONFIRM;
2666 #ifdef FEAT_MOUSE
2667     setmouse();
2668 #endif
2669 
2670     /*
2671      * Since we wait for a keypress, don't make the
2672      * user press RETURN as well afterwards.
2673      */
2674     ++no_wait_return;
2675     hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
2676 
2677     if (hotkeys != NULL)
2678     {
2679 	for (;;)
2680 	{
2681 	    /* Get a typed character directly from the user. */
2682 	    c = get_keystroke();
2683 	    switch (c)
2684 	    {
2685 	    case CAR:		/* User accepts default option */
2686 	    case NL:
2687 		retval = dfltbutton;
2688 		break;
2689 	    case Ctrl_C:	/* User aborts/cancels */
2690 	    case ESC:
2691 		retval = 0;
2692 		break;
2693 	    default:		/* Could be a hotkey? */
2694 		if (c < 0)	/* special keys are ignored here */
2695 		    continue;
2696 		/* Make the character lowercase, as chars in "hotkeys" are. */
2697 		c = MB_TOLOWER(c);
2698 		retval = 1;
2699 		for (i = 0; hotkeys[i]; ++i)
2700 		{
2701 #ifdef FEAT_MBYTE
2702 		    if (has_mbyte)
2703 		    {
2704 			if ((*mb_ptr2char)(hotkeys + i) == c)
2705 			    break;
2706 			i += (*mb_ptr2len_check)(hotkeys + i) - 1;
2707 		    }
2708 		    else
2709 #endif
2710 			if (hotkeys[i] == c)
2711 			    break;
2712 		    ++retval;
2713 		}
2714 		if (hotkeys[i])
2715 		    break;
2716 		/* No hotkey match, so keep waiting */
2717 		continue;
2718 	    }
2719 	    break;
2720 	}
2721 
2722 	vim_free(hotkeys);
2723     }
2724 
2725     State = oldState;
2726 #ifdef FEAT_MOUSE
2727     setmouse();
2728 #endif
2729     --no_wait_return;
2730     msg_end_prompt();
2731 
2732     return retval;
2733 }
2734 
2735 static int copy_char __ARGS((char_u *from, char_u *to, int lowercase));
2736 
2737 /*
2738  * Copy one character from "*from" to "*to", taking care of multi-byte
2739  * characters.  Return the length of the character in bytes.
2740  */
2741     static int
2742 copy_char(from, to, lowercase)
2743     char_u	*from;
2744     char_u	*to;
2745     int		lowercase;	/* make character lower case */
2746 {
2747 #ifdef FEAT_MBYTE
2748     int		len;
2749     int		c;
2750 
2751     if (has_mbyte)
2752     {
2753 	if (lowercase)
2754 	{
2755 	    c = MB_TOLOWER((*mb_ptr2char)(from));
2756 	    return (*mb_char2bytes)(c, to);
2757 	}
2758 	else
2759 	{
2760 	    len = (*mb_ptr2len_check)(from);
2761 	    mch_memmove(to, from, (size_t)len);
2762 	    return len;
2763 	}
2764     }
2765     else
2766 #endif
2767     {
2768 	if (lowercase)
2769 	    *to = (char_u)TOLOWER_LOC(*from);
2770 	else
2771 	    *to = *from;
2772 	return 1;
2773     }
2774 }
2775 
2776 /*
2777  * Format the dialog string, and display it at the bottom of
2778  * the screen. Return a string of hotkey chars (if defined) for
2779  * each 'button'. If a button has no hotkey defined, the first character of
2780  * the button is used.
2781  * The hotkeys can be multi-byte characters, but without combining chars.
2782  *
2783  * Returns an allocated string with hotkeys, or NULL for error.
2784  */
2785     static char_u *
2786 msg_show_console_dialog(message, buttons, dfltbutton)
2787     char_u	*message;
2788     char_u	*buttons;
2789     int		dfltbutton;
2790 {
2791     int		len = 0;
2792 #ifdef FEAT_MBYTE
2793 # define HOTK_LEN (has_mbyte ? MB_MAXBYTES : 1)
2794 #else
2795 # define HOTK_LEN 1
2796 #endif
2797     int		lenhotkey = HOTK_LEN;	/* count first button */
2798     char_u	*hotk = NULL;
2799     char_u	*msgp = NULL;
2800     char_u	*hotkp = NULL;
2801     char_u	*r;
2802     int		copy;
2803 #define HAS_HOTKEY_LEN 30
2804     char_u	has_hotkey[HAS_HOTKEY_LEN];
2805     int		first_hotkey = FALSE;	/* first char of button is hotkey */
2806     int		idx;
2807 
2808     has_hotkey[0] = FALSE;
2809 
2810     /*
2811      * First loop: compute the size of memory to allocate.
2812      * Second loop: copy to the allocated memory.
2813      */
2814     for (copy = 0; copy <= 1; ++copy)
2815     {
2816 	r = buttons;
2817 	idx = 0;
2818 	while (*r)
2819 	{
2820 	    if (*r == DLG_BUTTON_SEP)
2821 	    {
2822 		if (copy)
2823 		{
2824 		    *msgp++ = ',';
2825 		    *msgp++ = ' ';	    /* '\n' -> ', ' */
2826 
2827 		    /* advance to next hotkey and set default hotkey */
2828 #ifdef FEAT_MBYTE
2829 		    if (has_mbyte)
2830 			hotkp += (*mb_ptr2len_check)(hotkp);
2831 		    else
2832 #endif
2833 			++hotkp;
2834 		    (void)copy_char(r + 1, hotkp, TRUE);
2835 		    if (dfltbutton)
2836 			--dfltbutton;
2837 
2838 		    /* If no hotkey is specified first char is used. */
2839 		    if (idx < HAS_HOTKEY_LEN - 1 && !has_hotkey[++idx])
2840 			first_hotkey = TRUE;
2841 		}
2842 		else
2843 		{
2844 		    len += 3;		    /* '\n' -> ', '; 'x' -> '(x)' */
2845 		    lenhotkey += HOTK_LEN;  /* each button needs a hotkey */
2846 		    if (idx < HAS_HOTKEY_LEN - 1)
2847 			has_hotkey[++idx] = FALSE;
2848 		}
2849 	    }
2850 	    else if (*r == DLG_HOTKEY_CHAR || first_hotkey)
2851 	    {
2852 		if (*r == DLG_HOTKEY_CHAR)
2853 		    ++r;
2854 		first_hotkey = FALSE;
2855 		if (copy)
2856 		{
2857 		    if (*r == DLG_HOTKEY_CHAR)		/* '&&a' -> '&a' */
2858 			*msgp++ = *r;
2859 		    else
2860 		    {
2861 			/* '&a' -> '[a]' */
2862 			*msgp++ = (dfltbutton == 1) ? '[' : '(';
2863 			msgp += copy_char(r, msgp, FALSE);
2864 			*msgp++ = (dfltbutton == 1) ? ']' : ')';
2865 
2866 			/* redefine hotkey */
2867 			(void)copy_char(r, hotkp, TRUE);
2868 		    }
2869 		}
2870 		else
2871 		{
2872 		    ++len;	    /* '&a' -> '[a]' */
2873 		    if (idx < HAS_HOTKEY_LEN - 1)
2874 			has_hotkey[idx] = TRUE;
2875 		}
2876 	    }
2877 	    else
2878 	    {
2879 		/* everything else copy literally */
2880 		if (copy)
2881 		    msgp += copy_char(r, msgp, FALSE);
2882 	    }
2883 
2884 	    /* advance to the next character */
2885 #ifdef FEAT_MBYTE
2886 	    if (has_mbyte)
2887 		r += (*mb_ptr2len_check)(r);
2888 	    else
2889 #endif
2890 		++r;
2891 	}
2892 
2893 	if (copy)
2894 	{
2895 	    *msgp++ = ':';
2896 	    *msgp++ = ' ';
2897 	    *msgp = NUL;
2898 #ifdef FEAT_MBYTE
2899 	    if (has_mbyte)
2900 		hotkp += (*mb_ptr2len_check)(hotkp);
2901 	    else
2902 #endif
2903 		++hotkp;
2904 	    *hotkp = NUL;
2905 	}
2906 	else
2907 	{
2908 	    len += STRLEN(message)
2909 		    + 2			/* for the NL's */
2910 		    + STRLEN(buttons)
2911 		    + 3;		/* for the ": " and NUL */
2912 	    lenhotkey++;		/* for the NUL */
2913 
2914 	    /* If no hotkey is specified first char is used. */
2915 	    if (!has_hotkey[0])
2916 	    {
2917 		first_hotkey = TRUE;
2918 		len += 2;		/* "x" -> "[x]" */
2919 	    }
2920 
2921 	    /*
2922 	     * Now allocate and load the strings
2923 	     */
2924 	    vim_free(confirm_msg);
2925 	    confirm_msg = alloc(len);
2926 	    if (confirm_msg == NULL)
2927 		return NULL;
2928 	    *confirm_msg = NUL;
2929 	    hotk = alloc(lenhotkey);
2930 	    if (hotk == NULL)
2931 		return NULL;
2932 
2933 	    *confirm_msg = '\n';
2934 	    STRCPY(confirm_msg + 1, message);
2935 
2936 	    msgp = confirm_msg + 1 + STRLEN(message);
2937 	    hotkp = hotk;
2938 
2939 	    /* define first default hotkey */
2940 	    (void)copy_char(buttons, hotkp, TRUE);
2941 
2942 	    /* Remember where the choices start, displaying starts here when
2943 	     * "hotkp" typed at the more prompt. */
2944 	    confirm_msg_tail = msgp;
2945 	    *msgp++ = '\n';
2946 	}
2947     }
2948 
2949     display_confirm_msg();
2950     return hotk;
2951 }
2952 
2953 /*
2954  * Display the ":confirm" message.  Also called when screen resized.
2955  */
2956     void
2957 display_confirm_msg()
2958 {
2959     /* avoid that 'q' at the more prompt truncates the message here */
2960     ++confirm_msg_used;
2961     if (confirm_msg != NULL)
2962 	msg_puts_attr(confirm_msg, hl_attr(HLF_M));
2963     --confirm_msg_used;
2964 }
2965 
2966 #endif /* FEAT_CON_DIALOG */
2967 
2968 #if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG)
2969 
2970     int
2971 vim_dialog_yesno(type, title, message, dflt)
2972     int		type;
2973     char_u	*title;
2974     char_u	*message;
2975     int		dflt;
2976 {
2977     if (do_dialog(type,
2978 		title == NULL ? (char_u *)_("Question") : title,
2979 		message,
2980 		(char_u *)_("&Yes\n&No"), dflt, NULL) == 1)
2981 	return VIM_YES;
2982     return VIM_NO;
2983 }
2984 
2985     int
2986 vim_dialog_yesnocancel(type, title, message, dflt)
2987     int		type;
2988     char_u	*title;
2989     char_u	*message;
2990     int		dflt;
2991 {
2992     switch (do_dialog(type,
2993 		title == NULL ? (char_u *)_("Question") : title,
2994 		message,
2995 		(char_u *)_("&Yes\n&No\n&Cancel"), dflt, NULL))
2996     {
2997 	case 1: return VIM_YES;
2998 	case 2: return VIM_NO;
2999     }
3000     return VIM_CANCEL;
3001 }
3002 
3003     int
3004 vim_dialog_yesnoallcancel(type, title, message, dflt)
3005     int		type;
3006     char_u	*title;
3007     char_u	*message;
3008     int		dflt;
3009 {
3010     switch (do_dialog(type,
3011 		title == NULL ? (char_u *)"Question" : title,
3012 		message,
3013 		(char_u *)_("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"),
3014 								  dflt, NULL))
3015     {
3016 	case 1: return VIM_YES;
3017 	case 2: return VIM_NO;
3018 	case 3: return VIM_ALL;
3019 	case 4: return VIM_DISCARDALL;
3020     }
3021     return VIM_CANCEL;
3022 }
3023 
3024 #endif /* FEAT_GUI_DIALOG || FEAT_CON_DIALOG */
3025 
3026 #if defined(FEAT_BROWSE) || defined(PROTO)
3027 /*
3028  * Generic browse function.  Calls gui_mch_browse() when possible.
3029  * Later this may pop-up a non-GUI file selector (external command?).
3030  */
3031     char_u *
3032 do_browse(saving, title, dflt, ext, initdir, filter, buf)
3033     int		saving;		/* write action */
3034     char_u	*title;		/* title for the window */
3035     char_u	*dflt;		/* default file name (may include directory) */
3036     char_u	*ext;		/* extension added */
3037     char_u	*initdir;	/* initial directory, NULL for current dir or
3038 				   when using path from "dflt" */
3039     char_u	*filter;	/* file name filter */
3040     buf_T	*buf;		/* buffer to read/write for */
3041 {
3042     char_u		*fname;
3043     static char_u	*last_dir = NULL;    /* last used directory */
3044     char_u		*tofree = NULL;
3045     int			save_browse = cmdmod.browse;
3046 
3047     /* Must turn off browse to avoid that autocommands will get the
3048      * flag too!  */
3049     cmdmod.browse = FALSE;
3050 
3051     if (title == NULL)
3052     {
3053 	if (saving)
3054 	    title = (char_u *)_("Save File dialog");
3055 	else
3056 	    title = (char_u *)_("Open File dialog");
3057     }
3058 
3059     /* When no directory specified, use default file name, default dir, buffer
3060      * dir, last dir or current dir */
3061     if ((initdir == NULL || *initdir == NUL) && dflt != NULL && *dflt != NUL)
3062     {
3063 	if (mch_isdir(dflt))		/* default file name is a directory */
3064 	{
3065 	    initdir = dflt;
3066 	    dflt = NULL;
3067 	}
3068 	else if (gettail(dflt) != dflt)	/* default file name includes a path */
3069 	{
3070 	    tofree = vim_strsave(dflt);
3071 	    if (tofree != NULL)
3072 	    {
3073 		initdir = tofree;
3074 		*gettail(initdir) = NUL;
3075 		dflt = gettail(dflt);
3076 	    }
3077 	}
3078     }
3079 
3080     if (initdir == NULL || *initdir == NUL)
3081     {
3082 	/* When 'browsedir' is a directory, use it */
3083 	if (mch_isdir(p_bsdir))
3084 	    initdir = p_bsdir;
3085 	/* When saving or 'browsedir' is "buffer", use buffer fname */
3086 	else if ((saving || *p_bsdir == 'b')
3087 		&& buf != NULL && buf->b_ffname != NULL)
3088 	{
3089 	    if (dflt == NULL || *dflt == NUL)
3090 		dflt = gettail(curbuf->b_ffname);
3091 	    tofree = vim_strsave(curbuf->b_ffname);
3092 	    if (tofree != NULL)
3093 	    {
3094 		initdir = tofree;
3095 		*gettail(initdir) = NUL;
3096 	    }
3097 	}
3098 	/* When 'browsedir' is "last", use dir from last browse */
3099 	else if (*p_bsdir == 'l')
3100 	    initdir = last_dir;
3101 	/* When 'browsedir is "current", use current directory.  This is the
3102 	 * default already, leave initdir empty. */
3103     }
3104 
3105 # ifdef FEAT_GUI
3106     if (gui.in_use)		/* when this changes, also adjust f_has()! */
3107     {
3108 	if (filter == NULL
3109 #  ifdef FEAT_EVAL
3110 		&& (filter = get_var_value((char_u *)"b:browsefilter")) == NULL
3111 		&& (filter = get_var_value((char_u *)"g:browsefilter")) == NULL
3112 #  endif
3113 	)
3114 	    filter = BROWSE_FILTER_DEFAULT;
3115 	fname = gui_mch_browse(saving, title, dflt, ext, initdir, filter);
3116 
3117 	/* We hang around in the dialog for a while, the user might do some
3118 	 * things to our files.  The Win32 dialog allows deleting or renaming
3119 	 * a file, check timestamps. */
3120 	need_check_timestamps = TRUE;
3121 	did_check_timestamps = FALSE;
3122     }
3123     else
3124 # endif
3125     {
3126 	/* TODO: non-GUI file selector here */
3127 	EMSG(_("E338: Sorry, no file browser in console mode"));
3128 	fname = NULL;
3129     }
3130 
3131     /* keep the directory for next time */
3132     if (fname != NULL)
3133     {
3134 	vim_free(last_dir);
3135 	last_dir = vim_strsave(fname);
3136 	if (last_dir != NULL)
3137 	{
3138 	    *gettail(last_dir) = NUL;
3139 	    if (*last_dir == NUL)
3140 	    {
3141 		/* filename only returned, must be in current dir */
3142 		vim_free(last_dir);
3143 		last_dir = alloc(MAXPATHL);
3144 		if (last_dir != NULL)
3145 		    mch_dirname(last_dir, MAXPATHL);
3146 	    }
3147 	}
3148     }
3149 
3150     vim_free(tofree);
3151     cmdmod.browse = save_browse;
3152 
3153     return fname;
3154 }
3155 #endif
3156