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