1 /* vi:set ts=8 sts=4 sw=4 noet: 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 static void add_msg_hist(char_u *s, int len, int attr); 19 static void hit_return_msg(void); 20 static void msg_home_replace_attr(char_u *fname, int attr); 21 static void msg_puts_attr_len(char *str, int maxlen, int attr); 22 static void msg_puts_display(char_u *str, int maxlen, int attr, int recurse); 23 static void msg_scroll_up(void); 24 static void inc_msg_scrolled(void); 25 static void store_sb_text(char_u **sb_str, char_u *s, int attr, int *sb_col, int finish); 26 static void t_puts(int *t_col, char_u *t_s, char_u *s, int attr); 27 static void msg_puts_printf(char_u *str, int maxlen); 28 static int do_more_prompt(int typed_char); 29 static void msg_screen_putchar(int c, int attr); 30 static void msg_moremsg(int full); 31 static int msg_check_screen(void); 32 static void redir_write(char_u *s, int maxlen); 33 #ifdef FEAT_CON_DIALOG 34 static char_u *msg_show_console_dialog(char_u *message, char_u *buttons, int dfltbutton); 35 static int confirm_msg_used = FALSE; // displaying confirm_msg 36 static char_u *confirm_msg = NULL; // ":confirm" message 37 static char_u *confirm_msg_tail; // tail of confirm_msg 38 static void display_confirm_msg(void); 39 #endif 40 #ifdef FEAT_JOB_CHANNEL 41 static int emsg_to_channel_log = FALSE; 42 #endif 43 44 struct msg_hist 45 { 46 struct msg_hist *next; 47 char_u *msg; 48 int attr; 49 }; 50 51 static struct msg_hist *first_msg_hist = NULL; 52 static struct msg_hist *last_msg_hist = NULL; 53 static int msg_hist_len = 0; 54 55 static FILE *verbose_fd = NULL; 56 static int verbose_did_open = FALSE; 57 58 /* 59 * When writing messages to the screen, there are many different situations. 60 * A number of variables is used to remember the current state: 61 * msg_didany TRUE when messages were written since the last time the 62 * user reacted to a prompt. 63 * Reset: After hitting a key for the hit-return prompt, 64 * hitting <CR> for the command line or input(). 65 * Set: When any message is written to the screen. 66 * msg_didout TRUE when something was written to the current line. 67 * Reset: When advancing to the next line, when the current 68 * text can be overwritten. 69 * Set: When any message is written to the screen. 70 * msg_nowait No extra delay for the last drawn message. 71 * Used in normal_cmd() before the mode message is drawn. 72 * emsg_on_display There was an error message recently. Indicates that there 73 * should be a delay before redrawing. 74 * msg_scroll The next message should not overwrite the current one. 75 * msg_scrolled How many lines the screen has been scrolled (because of 76 * messages). Used in update_screen() to scroll the screen 77 * back. Incremented each time the screen scrolls a line. 78 * msg_scrolled_ign TRUE when msg_scrolled is non-zero and msg_puts_attr() 79 * writes something without scrolling should not make 80 * need_wait_return to be set. This is a hack to make ":ts" 81 * work without an extra prompt. 82 * lines_left Number of lines available for messages before the 83 * more-prompt is to be given. -1 when not set. 84 * need_wait_return TRUE when the hit-return prompt is needed. 85 * Reset: After giving the hit-return prompt, when the user 86 * has answered some other prompt. 87 * Set: When the ruler or typeahead display is overwritten, 88 * scrolling the screen for some message. 89 * keep_msg Message to be displayed after redrawing the screen, in 90 * main_loop(). 91 * This is an allocated string or NULL when not used. 92 */ 93 94 /* 95 * msg(s) - displays the string 's' on the status line 96 * When terminal not initialized (yet) mch_errmsg(..) is used. 97 * return TRUE if wait_return not called 98 */ 99 int 100 msg(char *s) 101 { 102 return msg_attr_keep(s, 0, FALSE); 103 } 104 105 /* 106 * Like msg() but keep it silent when 'verbosefile' is set. 107 */ 108 int 109 verb_msg(char *s) 110 { 111 int n; 112 113 verbose_enter(); 114 n = msg_attr_keep(s, 0, FALSE); 115 verbose_leave(); 116 117 return n; 118 } 119 120 int 121 msg_attr(char *s, int attr) 122 { 123 return msg_attr_keep(s, attr, FALSE); 124 } 125 126 int 127 msg_attr_keep( 128 char *s, 129 int attr, 130 int keep) // TRUE: set keep_msg if it doesn't scroll 131 { 132 static int entered = 0; 133 int retval; 134 char_u *buf = NULL; 135 136 // Skip messages not matching ":filter pattern". 137 // Don't filter when there is an error. 138 if (!emsg_on_display && message_filtered((char_u *)s)) 139 return TRUE; 140 141 #ifdef FEAT_EVAL 142 if (attr == 0) 143 set_vim_var_string(VV_STATUSMSG, (char_u *)s, -1); 144 #endif 145 146 /* 147 * It is possible that displaying a messages causes a problem (e.g., 148 * when redrawing the window), which causes another message, etc.. To 149 * break this loop, limit the recursiveness to 3 levels. 150 */ 151 if (entered >= 3) 152 return TRUE; 153 ++entered; 154 155 // Add message to history (unless it's a repeated kept message or a 156 // truncated message) 157 if ((char_u *)s != keep_msg 158 || (*s != '<' 159 && last_msg_hist != NULL 160 && last_msg_hist->msg != NULL 161 && STRCMP(s, last_msg_hist->msg))) 162 add_msg_hist((char_u *)s, -1, attr); 163 164 #ifdef FEAT_JOB_CHANNEL 165 if (emsg_to_channel_log) 166 // Write message in the channel log. 167 ch_log(NULL, "ERROR: %s", (char *)s); 168 #endif 169 170 // Truncate the message if needed. 171 msg_start(); 172 buf = msg_strtrunc((char_u *)s, FALSE); 173 if (buf != NULL) 174 s = (char *)buf; 175 176 msg_outtrans_attr((char_u *)s, attr); 177 msg_clr_eos(); 178 retval = msg_end(); 179 180 if (keep && retval && vim_strsize((char_u *)s) 181 < (int)(Rows - cmdline_row - 1) * Columns + sc_col) 182 set_keep_msg((char_u *)s, 0); 183 184 vim_free(buf); 185 --entered; 186 return retval; 187 } 188 189 /* 190 * Truncate a string such that it can be printed without causing a scroll. 191 * Returns an allocated string or NULL when no truncating is done. 192 */ 193 char_u * 194 msg_strtrunc( 195 char_u *s, 196 int force) // always truncate 197 { 198 char_u *buf = NULL; 199 int len; 200 int room; 201 202 // May truncate message to avoid a hit-return prompt 203 if ((!msg_scroll && !need_wait_return && shortmess(SHM_TRUNCALL) 204 && !exmode_active && msg_silent == 0) || force) 205 { 206 len = vim_strsize(s); 207 if (msg_scrolled != 0) 208 // Use all the columns. 209 room = (int)(Rows - msg_row) * Columns - 1; 210 else 211 // Use up to 'showcmd' column. 212 room = (int)(Rows - msg_row - 1) * Columns + sc_col - 1; 213 if (len > room && room > 0) 214 { 215 if (enc_utf8) 216 // may have up to 18 bytes per cell (6 per char, up to two 217 // composing chars) 218 len = (room + 2) * 18; 219 else if (enc_dbcs == DBCS_JPNU) 220 // may have up to 2 bytes per cell for euc-jp 221 len = (room + 2) * 2; 222 else 223 len = room + 2; 224 buf = alloc(len); 225 if (buf != NULL) 226 trunc_string(s, buf, room, len); 227 } 228 } 229 return buf; 230 } 231 232 /* 233 * Truncate a string "s" to "buf" with cell width "room". 234 * "s" and "buf" may be equal. 235 */ 236 void 237 trunc_string( 238 char_u *s, 239 char_u *buf, 240 int room_in, 241 int buflen) 242 { 243 size_t room = room_in - 3; // "..." takes 3 chars 244 size_t half; 245 size_t len = 0; 246 int e; 247 int i; 248 int n; 249 250 if (*s == NUL) 251 { 252 if (buflen > 0) 253 *buf = NUL; 254 return; 255 } 256 257 if (room_in < 3) 258 room = 0; 259 half = room / 2; 260 261 // First part: Start of the string. 262 for (e = 0; len < half && e < buflen; ++e) 263 { 264 if (s[e] == NUL) 265 { 266 // text fits without truncating! 267 buf[e] = NUL; 268 return; 269 } 270 n = ptr2cells(s + e); 271 if (len + n > half) 272 break; 273 len += n; 274 buf[e] = s[e]; 275 if (has_mbyte) 276 for (n = (*mb_ptr2len)(s + e); --n > 0; ) 277 { 278 if (++e == buflen) 279 break; 280 buf[e] = s[e]; 281 } 282 } 283 284 // Last part: End of the string. 285 i = e; 286 if (enc_dbcs != 0) 287 { 288 // For DBCS going backwards in a string is slow, but 289 // computing the cell width isn't too slow: go forward 290 // until the rest fits. 291 n = vim_strsize(s + i); 292 while (len + n > room) 293 { 294 n -= ptr2cells(s + i); 295 i += (*mb_ptr2len)(s + i); 296 } 297 } 298 else if (enc_utf8) 299 { 300 // For UTF-8 we can go backwards easily. 301 half = i = (int)STRLEN(s); 302 for (;;) 303 { 304 do 305 half = half - utf_head_off(s, s + half - 1) - 1; 306 while (half > 0 && utf_iscomposing(utf_ptr2char(s + half))); 307 n = ptr2cells(s + half); 308 if (len + n > room || half == 0) 309 break; 310 len += n; 311 i = (int)half; 312 } 313 } 314 else 315 { 316 for (i = (int)STRLEN(s); 317 i - 1 >= 0 && len + (n = ptr2cells(s + i - 1)) <= room; --i) 318 len += n; 319 } 320 321 322 if (i <= e + 3) 323 { 324 // text fits without truncating 325 if (s != buf) 326 { 327 len = STRLEN(s); 328 if (len >= (size_t)buflen) 329 len = buflen - 1; 330 len = len - e + 1; 331 if (len < 1) 332 buf[e - 1] = NUL; 333 else 334 mch_memmove(buf + e, s + e, len); 335 } 336 } 337 else if (e + 3 < buflen) 338 { 339 // set the middle and copy the last part 340 mch_memmove(buf + e, "...", (size_t)3); 341 len = STRLEN(s + i) + 1; 342 if (len >= (size_t)buflen - e - 3) 343 len = buflen - e - 3 - 1; 344 mch_memmove(buf + e + 3, s + i, len); 345 buf[e + 3 + len - 1] = NUL; 346 } 347 else 348 { 349 // can't fit in the "...", just truncate it 350 buf[e - 1] = NUL; 351 } 352 } 353 354 /* 355 * Automatic prototype generation does not understand this function. 356 * Note: Caller of smsg() and smsg_attr() must check the resulting string is 357 * shorter than IOSIZE!!! 358 */ 359 #ifndef PROTO 360 361 int vim_snprintf(char *str, size_t str_m, const char *fmt, ...); 362 363 int 364 smsg(const char *s, ...) 365 { 366 if (IObuff == NULL) 367 { 368 // Very early in initialisation and already something wrong, just 369 // give the raw message so the user at least gets a hint. 370 return msg((char *)s); 371 } 372 else 373 { 374 va_list arglist; 375 376 va_start(arglist, s); 377 vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist); 378 va_end(arglist); 379 return msg((char *)IObuff); 380 } 381 } 382 383 int 384 smsg_attr(int attr, const char *s, ...) 385 { 386 if (IObuff == NULL) 387 { 388 // Very early in initialisation and already something wrong, just 389 // give the raw message so the user at least gets a hint. 390 return msg_attr((char *)s, attr); 391 } 392 else 393 { 394 va_list arglist; 395 396 va_start(arglist, s); 397 vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist); 398 va_end(arglist); 399 return msg_attr((char *)IObuff, attr); 400 } 401 } 402 403 int 404 smsg_attr_keep(int attr, const char *s, ...) 405 { 406 if (IObuff == NULL) 407 { 408 // Very early in initialisation and already something wrong, just 409 // give the raw message so the user at least gets a hint. 410 return msg_attr_keep((char *)s, attr, TRUE); 411 } 412 else 413 { 414 va_list arglist; 415 416 va_start(arglist, s); 417 vim_vsnprintf((char *)IObuff, IOSIZE, s, arglist); 418 va_end(arglist); 419 return msg_attr_keep((char *)IObuff, attr, TRUE); 420 } 421 } 422 423 #endif 424 425 /* 426 * Remember the last sourcing name/lnum used in an error message, so that it 427 * isn't printed each time when it didn't change. 428 */ 429 static int last_sourcing_lnum = 0; 430 static char_u *last_sourcing_name = NULL; 431 432 /* 433 * Reset the last used sourcing name/lnum. Makes sure it is displayed again 434 * for the next error message; 435 */ 436 void 437 reset_last_sourcing(void) 438 { 439 VIM_CLEAR(last_sourcing_name); 440 last_sourcing_lnum = 0; 441 } 442 443 /* 444 * Return TRUE if "SOURCING_NAME" differs from "last_sourcing_name". 445 */ 446 static int 447 other_sourcing_name(void) 448 { 449 if (SOURCING_NAME != NULL) 450 { 451 if (last_sourcing_name != NULL) 452 return STRCMP(SOURCING_NAME, last_sourcing_name) != 0; 453 return TRUE; 454 } 455 return FALSE; 456 } 457 458 /* 459 * Get the message about the source, as used for an error message. 460 * Returns an allocated string with room for one more character. 461 * Returns NULL when no message is to be given. 462 */ 463 static char_u * 464 get_emsg_source(void) 465 { 466 char_u *Buf, *p; 467 468 if (SOURCING_NAME != NULL && other_sourcing_name()) 469 { 470 char_u *sname = estack_sfile(ESTACK_NONE); 471 char_u *tofree = sname; 472 473 if (sname == NULL) 474 sname = SOURCING_NAME; 475 476 #ifdef FEAT_EVAL 477 if (estack_compiling) 478 p = (char_u *)_("Error detected while compiling %s:"); 479 else 480 #endif 481 p = (char_u *)_("Error detected while processing %s:"); 482 Buf = alloc(STRLEN(sname) + STRLEN(p)); 483 if (Buf != NULL) 484 sprintf((char *)Buf, (char *)p, sname); 485 vim_free(tofree); 486 return Buf; 487 } 488 return NULL; 489 } 490 491 /* 492 * Get the message about the source lnum, as used for an error message. 493 * Returns an allocated string with room for one more character. 494 * Returns NULL when no message is to be given. 495 */ 496 static char_u * 497 get_emsg_lnum(void) 498 { 499 char_u *Buf, *p; 500 501 // lnum is 0 when executing a command from the command line 502 // argument, we don't want a line number then 503 if (SOURCING_NAME != NULL 504 && (other_sourcing_name() || SOURCING_LNUM != last_sourcing_lnum) 505 && SOURCING_LNUM != 0) 506 { 507 p = (char_u *)_("line %4ld:"); 508 Buf = alloc(STRLEN(p) + 20); 509 if (Buf != NULL) 510 sprintf((char *)Buf, (char *)p, (long)SOURCING_LNUM); 511 return Buf; 512 } 513 return NULL; 514 } 515 516 /* 517 * Display name and line number for the source of an error. 518 * Remember the file name and line number, so that for the next error the info 519 * is only displayed if it changed. 520 */ 521 void 522 msg_source(int attr) 523 { 524 char_u *p; 525 526 ++no_wait_return; 527 p = get_emsg_source(); 528 if (p != NULL) 529 { 530 msg_attr((char *)p, attr); 531 vim_free(p); 532 } 533 p = get_emsg_lnum(); 534 if (p != NULL) 535 { 536 msg_attr((char *)p, HL_ATTR(HLF_N)); 537 vim_free(p); 538 last_sourcing_lnum = SOURCING_LNUM; // only once for each line 539 } 540 541 // remember the last sourcing name printed, also when it's empty 542 if (SOURCING_NAME == NULL || other_sourcing_name()) 543 { 544 vim_free(last_sourcing_name); 545 if (SOURCING_NAME == NULL) 546 last_sourcing_name = NULL; 547 else 548 last_sourcing_name = vim_strsave(SOURCING_NAME); 549 } 550 --no_wait_return; 551 } 552 553 /* 554 * Return TRUE if not giving error messages right now: 555 * If "emsg_off" is set: no error messages at the moment. 556 * If "msg" is in 'debug': do error message but without side effects. 557 * If "emsg_skip" is set: never do error messages. 558 */ 559 static int 560 emsg_not_now(void) 561 { 562 if ((emsg_off > 0 && vim_strchr(p_debug, 'm') == NULL 563 && vim_strchr(p_debug, 't') == NULL) 564 #ifdef FEAT_EVAL 565 || emsg_skip > 0 566 #endif 567 ) 568 return TRUE; 569 return FALSE; 570 } 571 572 #if defined(FEAT_EVAL) || defined(PROTO) 573 static garray_T ignore_error_list = GA_EMPTY; 574 575 void 576 ignore_error_for_testing(char_u *error) 577 { 578 if (ignore_error_list.ga_itemsize == 0) 579 ga_init2(&ignore_error_list, sizeof(char_u *), 1); 580 581 if (STRCMP("RESET", error) == 0) 582 ga_clear_strings(&ignore_error_list); 583 else 584 ga_add_string(&ignore_error_list, error); 585 } 586 587 static int 588 ignore_error(char_u *msg) 589 { 590 int i; 591 592 for (i = 0; i < ignore_error_list.ga_len; ++i) 593 if (strstr((char *)msg, 594 (char *)((char_u **)(ignore_error_list.ga_data))[i]) != NULL) 595 return TRUE; 596 return FALSE; 597 } 598 #endif 599 600 #if !defined(HAVE_STRERROR) || defined(PROTO) 601 /* 602 * Replacement for perror() that behaves more or less like emsg() was called. 603 * v:errmsg will be set and called_emsg will be incremented. 604 */ 605 void 606 do_perror(char *msg) 607 { 608 perror(msg); 609 ++emsg_silent; 610 emsg(msg); 611 --emsg_silent; 612 } 613 #endif 614 615 /* 616 * emsg_core() - display an error message 617 * 618 * Rings the bell, if appropriate, and calls message() to do the real work 619 * When terminal not initialized (yet) mch_errmsg(..) is used. 620 * 621 * Return TRUE if wait_return not called. 622 * Note: caller must check 'emsg_not_now()' before calling this. 623 */ 624 static int 625 emsg_core(char_u *s) 626 { 627 int attr; 628 char_u *p; 629 int r; 630 #ifdef FEAT_EVAL 631 int ignore = FALSE; 632 int severe; 633 #endif 634 635 #ifdef FEAT_EVAL 636 // When testing some errors are turned into a normal message. 637 if (ignore_error(s)) 638 // don't call msg() if it results in a dialog 639 return msg_use_printf() ? FALSE : msg((char *)s); 640 #endif 641 642 ++called_emsg; 643 644 #ifdef FEAT_EVAL 645 // If "emsg_severe" is TRUE: When an error exception is to be thrown, 646 // prefer this message over previous messages for the same command. 647 severe = emsg_severe; 648 emsg_severe = FALSE; 649 #endif 650 651 if (!emsg_off || vim_strchr(p_debug, 't') != NULL) 652 { 653 #ifdef FEAT_EVAL 654 /* 655 * Cause a throw of an error exception if appropriate. Don't display 656 * the error message in this case. (If no matching catch clause will 657 * be found, the message will be displayed later on.) "ignore" is set 658 * when the message should be ignored completely (used for the 659 * interrupt message). 660 */ 661 if (cause_errthrow(s, severe, &ignore) == TRUE) 662 { 663 if (!ignore) 664 ++did_emsg; 665 return TRUE; 666 } 667 668 if (in_assert_fails && emsg_assert_fails_msg == NULL) 669 { 670 emsg_assert_fails_msg = vim_strsave(s); 671 emsg_assert_fails_lnum = SOURCING_LNUM; 672 vim_free(emsg_assert_fails_context); 673 emsg_assert_fails_context = vim_strsave( 674 SOURCING_NAME == NULL ? (char_u *)"" : SOURCING_NAME); 675 } 676 677 // set "v:errmsg", also when using ":silent! cmd" 678 set_vim_var_string(VV_ERRMSG, s, -1); 679 #endif 680 681 /* 682 * When using ":silent! cmd" ignore error messages. 683 * But do write it to the redirection file. 684 */ 685 if (emsg_silent != 0) 686 { 687 #ifdef FEAT_EVAL 688 ++did_emsg_silent; 689 #endif 690 if (emsg_noredir == 0) 691 { 692 msg_start(); 693 p = get_emsg_source(); 694 if (p != NULL) 695 { 696 STRCAT(p, "\n"); 697 redir_write(p, -1); 698 vim_free(p); 699 } 700 p = get_emsg_lnum(); 701 if (p != NULL) 702 { 703 STRCAT(p, "\n"); 704 redir_write(p, -1); 705 vim_free(p); 706 } 707 redir_write(s, -1); 708 } 709 #ifdef FEAT_EVAL 710 // Only increment did_emsg_def when :silent! wasn't used inside the 711 // :def function. 712 if (emsg_silent == emsg_silent_def) 713 ++did_emsg_def; 714 #endif 715 #ifdef FEAT_JOB_CHANNEL 716 ch_log(NULL, "ERROR silent: %s", (char *)s); 717 #endif 718 return TRUE; 719 } 720 721 ex_exitval = 1; 722 723 // Reset msg_silent, an error causes messages to be switched back on. 724 msg_silent = 0; 725 cmd_silent = FALSE; 726 727 if (global_busy) // break :global command 728 ++global_busy; 729 730 if (p_eb) 731 beep_flush(); // also includes flush_buffers() 732 else 733 flush_buffers(FLUSH_MINIMAL); // flush internal buffers 734 ++did_emsg; // flag for DoOneCmd() 735 #ifdef FEAT_EVAL 736 ++uncaught_emsg; 737 #endif 738 } 739 740 emsg_on_display = TRUE; // remember there is an error message 741 ++msg_scroll; // don't overwrite a previous message 742 attr = HL_ATTR(HLF_E); // set highlight mode for error messages 743 if (msg_scrolled != 0) 744 need_wait_return = TRUE; // needed in case emsg() is called after 745 // wait_return has reset need_wait_return 746 // and a redraw is expected because 747 // msg_scrolled is non-zero 748 749 #ifdef FEAT_JOB_CHANNEL 750 emsg_to_channel_log = TRUE; 751 #endif 752 /* 753 * Display name and line number for the source of the error. 754 */ 755 msg_source(attr); 756 757 /* 758 * Display the error message itself. 759 */ 760 msg_nowait = FALSE; // wait for this msg 761 r = msg_attr((char *)s, attr); 762 763 #ifdef FEAT_JOB_CHANNEL 764 emsg_to_channel_log = FALSE; 765 #endif 766 return r; 767 } 768 769 /* 770 * Print an error message. 771 */ 772 int 773 emsg(char *s) 774 { 775 // Skip this if not giving error messages at the moment. 776 if (!emsg_not_now()) 777 return emsg_core((char_u *)s); 778 return TRUE; // no error messages at the moment 779 } 780 781 #ifndef PROTO // manual proto with __attribute__ 782 /* 783 * Print an error message with format string and variable arguments. 784 * Note: caller must not pass 'IObuff' as 1st argument. 785 */ 786 int 787 semsg(const char *s, ...) 788 { 789 // Skip this if not giving error messages at the moment. 790 if (!emsg_not_now()) 791 { 792 if (IObuff == NULL) 793 { 794 // Very early in initialisation and already something wrong, just 795 // give the raw message so the user at least gets a hint. 796 return emsg_core((char_u *)s); 797 } 798 else 799 { 800 va_list ap; 801 802 va_start(ap, s); 803 vim_vsnprintf((char *)IObuff, IOSIZE, s, ap); 804 va_end(ap); 805 return emsg_core(IObuff); 806 } 807 } 808 return TRUE; // no error messages at the moment 809 } 810 #endif 811 812 /* 813 * Same as emsg(...), but abort on error when ABORT_ON_INTERNAL_ERROR is 814 * defined. It is used for internal errors only, so that they can be 815 * detected when fuzzing vim. 816 */ 817 void 818 iemsg(char *s) 819 { 820 if (!emsg_not_now()) 821 emsg_core((char_u *)s); 822 #ifdef ABORT_ON_INTERNAL_ERROR 823 abort(); 824 #endif 825 } 826 827 #ifndef PROTO // manual proto with __attribute__ 828 /* 829 * Same as semsg(...) but abort on error when ABORT_ON_INTERNAL_ERROR is 830 * defined. It is used for internal errors only, so that they can be 831 * detected when fuzzing vim. 832 * Note: caller must not pass 'IObuff' as 1st argument. 833 */ 834 void 835 siemsg(const char *s, ...) 836 { 837 if (!emsg_not_now()) 838 { 839 if (IObuff == NULL) 840 { 841 // Very early in initialisation and already something wrong, just 842 // give the raw message so the user at least gets a hint. 843 emsg_core((char_u *)s); 844 } 845 else 846 { 847 va_list ap; 848 849 va_start(ap, s); 850 vim_vsnprintf((char *)IObuff, IOSIZE, s, ap); 851 va_end(ap); 852 emsg_core(IObuff); 853 } 854 } 855 # ifdef ABORT_ON_INTERNAL_ERROR 856 abort(); 857 # endif 858 } 859 #endif 860 861 /* 862 * Give an "Internal error" message. 863 */ 864 void 865 internal_error(char *where) 866 { 867 siemsg(_(e_intern2), where); 868 } 869 870 /* 871 * Like internal_error() but do not call abort(), to avoid tests using 872 * test_unknown() and test_void() causing Vim to exit. 873 */ 874 void 875 internal_error_no_abort(char *where) 876 { 877 semsg(_(e_intern2), where); 878 } 879 880 // emsg3() and emsgn() are in misc2.c to avoid warnings for the prototypes. 881 882 void 883 emsg_invreg(int name) 884 { 885 semsg(_("E354: Invalid register name: '%s'"), transchar(name)); 886 } 887 888 /* 889 * Give an error message which contains %s for "name[len]". 890 */ 891 void 892 emsg_namelen(char *msg, char_u *name, int len) 893 { 894 char_u *copy = vim_strnsave((char_u *)name, len); 895 896 semsg(msg, copy == NULL ? "NULL" : (char *)copy); 897 vim_free(copy); 898 } 899 900 /* 901 * Like msg(), but truncate to a single line if p_shm contains 't', or when 902 * "force" is TRUE. This truncates in another way as for normal messages. 903 * Careful: The string may be changed by msg_may_trunc()! 904 * Returns a pointer to the printed message, if wait_return() not called. 905 */ 906 char * 907 msg_trunc_attr(char *s, int force, int attr) 908 { 909 int n; 910 char *ts; 911 912 // Add message to history before truncating 913 add_msg_hist((char_u *)s, -1, attr); 914 915 ts = (char *)msg_may_trunc(force, (char_u *)s); 916 917 msg_hist_off = TRUE; 918 n = msg_attr(ts, attr); 919 msg_hist_off = FALSE; 920 921 if (n) 922 return ts; 923 return NULL; 924 } 925 926 /* 927 * Check if message "s" should be truncated at the start (for filenames). 928 * Return a pointer to where the truncated message starts. 929 * Note: May change the message by replacing a character with '<'. 930 */ 931 char_u * 932 msg_may_trunc(int force, char_u *s) 933 { 934 int n; 935 int room; 936 937 room = (int)(Rows - cmdline_row - 1) * Columns + sc_col - 1; 938 if ((force || (shortmess(SHM_TRUNC) && !exmode_active)) 939 && (n = (int)STRLEN(s) - room) > 0) 940 { 941 if (has_mbyte) 942 { 943 int size = vim_strsize(s); 944 945 // There may be room anyway when there are multibyte chars. 946 if (size <= room) 947 return s; 948 949 for (n = 0; size >= room; ) 950 { 951 size -= (*mb_ptr2cells)(s + n); 952 n += (*mb_ptr2len)(s + n); 953 } 954 --n; 955 } 956 s += n; 957 *s = '<'; 958 } 959 return s; 960 } 961 962 static void 963 add_msg_hist( 964 char_u *s, 965 int len, // -1 for undetermined length 966 int attr) 967 { 968 struct msg_hist *p; 969 970 if (msg_hist_off || msg_silent != 0) 971 return; 972 973 // Don't let the message history get too big 974 while (msg_hist_len > MAX_MSG_HIST_LEN) 975 (void)delete_first_msg(); 976 977 // allocate an entry and add the message at the end of the history 978 p = ALLOC_ONE(struct msg_hist); 979 if (p != NULL) 980 { 981 if (len < 0) 982 len = (int)STRLEN(s); 983 // remove leading and trailing newlines 984 while (len > 0 && *s == '\n') 985 { 986 ++s; 987 --len; 988 } 989 while (len > 0 && s[len - 1] == '\n') 990 --len; 991 p->msg = vim_strnsave(s, len); 992 p->next = NULL; 993 p->attr = attr; 994 if (last_msg_hist != NULL) 995 last_msg_hist->next = p; 996 last_msg_hist = p; 997 if (first_msg_hist == NULL) 998 first_msg_hist = last_msg_hist; 999 ++msg_hist_len; 1000 } 1001 } 1002 1003 /* 1004 * Delete the first (oldest) message from the history. 1005 * Returns FAIL if there are no messages. 1006 */ 1007 int 1008 delete_first_msg(void) 1009 { 1010 struct msg_hist *p; 1011 1012 if (msg_hist_len <= 0) 1013 return FAIL; 1014 p = first_msg_hist; 1015 first_msg_hist = p->next; 1016 if (first_msg_hist == NULL) 1017 last_msg_hist = NULL; // history is empty 1018 vim_free(p->msg); 1019 vim_free(p); 1020 --msg_hist_len; 1021 return OK; 1022 } 1023 1024 /* 1025 * ":messages" command. 1026 */ 1027 void 1028 ex_messages(exarg_T *eap) 1029 { 1030 struct msg_hist *p; 1031 char_u *s; 1032 int c = 0; 1033 1034 if (STRCMP(eap->arg, "clear") == 0) 1035 { 1036 int keep = eap->addr_count == 0 ? 0 : eap->line2; 1037 1038 while (msg_hist_len > keep) 1039 (void)delete_first_msg(); 1040 return; 1041 } 1042 1043 if (*eap->arg != NUL) 1044 { 1045 emsg(_(e_invarg)); 1046 return; 1047 } 1048 1049 msg_hist_off = TRUE; 1050 1051 p = first_msg_hist; 1052 if (eap->addr_count != 0) 1053 { 1054 // Count total messages 1055 for (; p != NULL && !got_int; p = p->next) 1056 c++; 1057 1058 c -= eap->line2; 1059 1060 // Skip without number of messages specified 1061 for (p = first_msg_hist; p != NULL && !got_int && c > 0; 1062 p = p->next, c--); 1063 } 1064 1065 if (p == first_msg_hist) 1066 { 1067 #ifdef FEAT_MULTI_LANG 1068 s = get_mess_lang(); 1069 #else 1070 s = mch_getenv((char_u *)"LANG"); 1071 #endif 1072 if (s != NULL && *s != NUL) 1073 // The next comment is extracted by xgettext and put in po file for 1074 // translators to read. 1075 msg_attr( 1076 // Translator: Please replace the name and email address 1077 // with the appropriate text for your translation. 1078 _("Messages maintainer: Bram Moolenaar <[email protected]>"), 1079 HL_ATTR(HLF_T)); 1080 } 1081 1082 // Display what was not skipped. 1083 for (; p != NULL && !got_int; p = p->next) 1084 if (p->msg != NULL) 1085 msg_attr((char *)p->msg, p->attr); 1086 1087 msg_hist_off = FALSE; 1088 } 1089 1090 #if defined(FEAT_CON_DIALOG) || defined(FIND_REPLACE_DIALOG) || defined(PROTO) 1091 /* 1092 * Call this after prompting the user. This will avoid a hit-return message 1093 * and a delay. 1094 */ 1095 void 1096 msg_end_prompt(void) 1097 { 1098 need_wait_return = FALSE; 1099 emsg_on_display = FALSE; 1100 cmdline_row = msg_row; 1101 msg_col = 0; 1102 msg_clr_eos(); 1103 lines_left = -1; 1104 } 1105 #endif 1106 1107 /* 1108 * Wait for the user to hit a key (normally Enter). 1109 * If "redraw" is TRUE, clear and redraw the screen. 1110 * If "redraw" is FALSE, just redraw the screen. 1111 * If "redraw" is -1, don't redraw at all. 1112 */ 1113 void 1114 wait_return(int redraw) 1115 { 1116 int c; 1117 int oldState; 1118 int tmpState; 1119 int had_got_int; 1120 int save_reg_recording; 1121 FILE *save_scriptout; 1122 1123 if (redraw == TRUE) 1124 must_redraw = CLEAR; 1125 1126 // If using ":silent cmd", don't wait for a return. Also don't set 1127 // need_wait_return to do it later. 1128 if (msg_silent != 0) 1129 return; 1130 1131 /* 1132 * When inside vgetc(), we can't wait for a typed character at all. 1133 * With the global command (and some others) we only need one return at 1134 * the end. Adjust cmdline_row to avoid the next message overwriting the 1135 * last one. 1136 */ 1137 if (vgetc_busy > 0) 1138 return; 1139 need_wait_return = TRUE; 1140 if (no_wait_return) 1141 { 1142 if (!exmode_active) 1143 cmdline_row = msg_row; 1144 return; 1145 } 1146 1147 redir_off = TRUE; // don't redirect this message 1148 oldState = State; 1149 if (quit_more) 1150 { 1151 c = CAR; // just pretend CR was hit 1152 quit_more = FALSE; 1153 got_int = FALSE; 1154 } 1155 else if (exmode_active) 1156 { 1157 msg_puts(" "); // make sure the cursor is on the right line 1158 c = CAR; // no need for a return in ex mode 1159 got_int = FALSE; 1160 } 1161 else 1162 { 1163 // Make sure the hit-return prompt is on screen when 'guioptions' was 1164 // just changed. 1165 screenalloc(FALSE); 1166 1167 State = HITRETURN; 1168 setmouse(); 1169 #ifdef USE_ON_FLY_SCROLL 1170 dont_scroll = TRUE; // disallow scrolling here 1171 #endif 1172 cmdline_row = msg_row; 1173 1174 // Avoid the sequence that the user types ":" at the hit-return prompt 1175 // to start an Ex command, but the file-changed dialog gets in the 1176 // way. 1177 if (need_check_timestamps) 1178 check_timestamps(FALSE); 1179 1180 hit_return_msg(); 1181 1182 do 1183 { 1184 // Remember "got_int", if it is set vgetc() probably returns a 1185 // CTRL-C, but we need to loop then. 1186 had_got_int = got_int; 1187 1188 // Don't do mappings here, we put the character back in the 1189 // typeahead buffer. 1190 ++no_mapping; 1191 ++allow_keys; 1192 1193 // Temporarily disable Recording. If Recording is active, the 1194 // character will be recorded later, since it will be added to the 1195 // typebuf after the loop 1196 save_reg_recording = reg_recording; 1197 save_scriptout = scriptout; 1198 reg_recording = 0; 1199 scriptout = NULL; 1200 c = safe_vgetc(); 1201 if (had_got_int && !global_busy) 1202 got_int = FALSE; 1203 --no_mapping; 1204 --allow_keys; 1205 reg_recording = save_reg_recording; 1206 scriptout = save_scriptout; 1207 1208 #ifdef FEAT_CLIPBOARD 1209 // Strange way to allow copying (yanking) a modeless selection at 1210 // the hit-enter prompt. Use CTRL-Y, because the same is used in 1211 // Cmdline-mode and it's harmless when there is no selection. 1212 if (c == Ctrl_Y && clip_star.state == SELECT_DONE) 1213 { 1214 clip_copy_modeless_selection(TRUE); 1215 c = K_IGNORE; 1216 } 1217 #endif 1218 1219 /* 1220 * Allow scrolling back in the messages. 1221 * Also accept scroll-down commands when messages fill the screen, 1222 * to avoid that typing one 'j' too many makes the messages 1223 * disappear. 1224 */ 1225 if (p_more && !p_cp) 1226 { 1227 if (c == 'b' || c == 'k' || c == 'u' || c == 'g' 1228 || c == K_UP || c == K_PAGEUP) 1229 { 1230 if (msg_scrolled > Rows) 1231 // scroll back to show older messages 1232 do_more_prompt(c); 1233 else 1234 { 1235 msg_didout = FALSE; 1236 c = K_IGNORE; 1237 msg_col = 1238 #ifdef FEAT_RIGHTLEFT 1239 cmdmsg_rl ? Columns - 1 : 1240 #endif 1241 0; 1242 } 1243 if (quit_more) 1244 { 1245 c = CAR; // just pretend CR was hit 1246 quit_more = FALSE; 1247 got_int = FALSE; 1248 } 1249 else if (c != K_IGNORE) 1250 { 1251 c = K_IGNORE; 1252 hit_return_msg(); 1253 } 1254 } 1255 else if (msg_scrolled > Rows - 2 1256 && (c == 'j' || c == 'd' || c == 'f' 1257 || c == K_DOWN || c == K_PAGEDOWN)) 1258 c = K_IGNORE; 1259 } 1260 } while ((had_got_int && c == Ctrl_C) 1261 || c == K_IGNORE 1262 #ifdef FEAT_GUI 1263 || c == K_VER_SCROLLBAR || c == K_HOR_SCROLLBAR 1264 #endif 1265 || c == K_LEFTDRAG || c == K_LEFTRELEASE 1266 || c == K_MIDDLEDRAG || c == K_MIDDLERELEASE 1267 || c == K_RIGHTDRAG || c == K_RIGHTRELEASE 1268 || c == K_MOUSELEFT || c == K_MOUSERIGHT 1269 || c == K_MOUSEDOWN || c == K_MOUSEUP 1270 || c == K_MOUSEMOVE 1271 || (!mouse_has(MOUSE_RETURN) 1272 && mouse_row < msg_row 1273 && (c == K_LEFTMOUSE 1274 || c == K_MIDDLEMOUSE 1275 || c == K_RIGHTMOUSE 1276 || c == K_X1MOUSE 1277 || c == K_X2MOUSE)) 1278 ); 1279 ui_breakcheck(); 1280 /* 1281 * Avoid that the mouse-up event causes visual mode to start. 1282 */ 1283 if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE 1284 || c == K_X1MOUSE || c == K_X2MOUSE) 1285 (void)jump_to_mouse(MOUSE_SETPOS, NULL, 0); 1286 else if (vim_strchr((char_u *)"\r\n ", c) == NULL && c != Ctrl_C) 1287 { 1288 // Put the character back in the typeahead buffer. Don't use the 1289 // stuff buffer, because lmaps wouldn't work. 1290 ins_char_typebuf(vgetc_char, vgetc_mod_mask); 1291 do_redraw = TRUE; // need a redraw even though there is 1292 // typeahead 1293 } 1294 } 1295 redir_off = FALSE; 1296 1297 /* 1298 * If the user hits ':', '?' or '/' we get a command line from the next 1299 * line. 1300 */ 1301 if (c == ':' || c == '?' || c == '/') 1302 { 1303 if (!exmode_active) 1304 cmdline_row = msg_row; 1305 skip_redraw = TRUE; // skip redraw once 1306 do_redraw = FALSE; 1307 #ifdef FEAT_TERMINAL 1308 skip_term_loop = TRUE; 1309 #endif 1310 } 1311 1312 /* 1313 * If the window size changed set_shellsize() will redraw the screen. 1314 * Otherwise the screen is only redrawn if 'redraw' is set and no ':' 1315 * typed. 1316 */ 1317 tmpState = State; 1318 State = oldState; // restore State before set_shellsize 1319 setmouse(); 1320 msg_check(); 1321 1322 #if defined(UNIX) || defined(VMS) 1323 /* 1324 * When switching screens, we need to output an extra newline on exit. 1325 */ 1326 if (swapping_screen() && !termcap_active) 1327 newline_on_exit = TRUE; 1328 #endif 1329 1330 need_wait_return = FALSE; 1331 did_wait_return = TRUE; 1332 emsg_on_display = FALSE; // can delete error message now 1333 lines_left = -1; // reset lines_left at next msg_start() 1334 reset_last_sourcing(); 1335 if (keep_msg != NULL && vim_strsize(keep_msg) >= 1336 (Rows - cmdline_row - 1) * Columns + sc_col) 1337 VIM_CLEAR(keep_msg); // don't redisplay message, it's too long 1338 1339 if (tmpState == SETWSIZE) // got resize event while in vgetc() 1340 { 1341 starttermcap(); // start termcap before redrawing 1342 shell_resized(); 1343 } 1344 else if (!skip_redraw 1345 && (redraw == TRUE || (msg_scrolled != 0 && redraw != -1))) 1346 { 1347 starttermcap(); // start termcap before redrawing 1348 redraw_later(VALID); 1349 } 1350 } 1351 1352 /* 1353 * Write the hit-return prompt. 1354 */ 1355 static void 1356 hit_return_msg(void) 1357 { 1358 int save_p_more = p_more; 1359 1360 p_more = FALSE; // don't want see this message when scrolling back 1361 if (msg_didout) // start on a new line 1362 msg_putchar('\n'); 1363 if (got_int) 1364 msg_puts(_("Interrupt: ")); 1365 1366 msg_puts_attr(_("Press ENTER or type command to continue"), HL_ATTR(HLF_R)); 1367 if (!msg_use_printf()) 1368 msg_clr_eos(); 1369 p_more = save_p_more; 1370 } 1371 1372 /* 1373 * Set "keep_msg" to "s". Free the old value and check for NULL pointer. 1374 */ 1375 void 1376 set_keep_msg(char_u *s, int attr) 1377 { 1378 vim_free(keep_msg); 1379 if (s != NULL && msg_silent == 0) 1380 keep_msg = vim_strsave(s); 1381 else 1382 keep_msg = NULL; 1383 keep_msg_more = FALSE; 1384 keep_msg_attr = attr; 1385 } 1386 1387 #if defined(FEAT_TERMRESPONSE) || defined(PROTO) 1388 /* 1389 * If there currently is a message being displayed, set "keep_msg" to it, so 1390 * that it will be displayed again after redraw. 1391 */ 1392 void 1393 set_keep_msg_from_hist(void) 1394 { 1395 if (keep_msg == NULL && last_msg_hist != NULL && msg_scrolled == 0 1396 && (State & NORMAL)) 1397 set_keep_msg(last_msg_hist->msg, last_msg_hist->attr); 1398 } 1399 #endif 1400 1401 /* 1402 * Prepare for outputting characters in the command line. 1403 */ 1404 void 1405 msg_start(void) 1406 { 1407 int did_return = FALSE; 1408 1409 if (!msg_silent) 1410 VIM_CLEAR(keep_msg); 1411 1412 #ifdef FEAT_EVAL 1413 if (need_clr_eos) 1414 { 1415 // Halfway an ":echo" command and getting an (error) message: clear 1416 // any text from the command. 1417 need_clr_eos = FALSE; 1418 msg_clr_eos(); 1419 } 1420 #endif 1421 1422 if (!msg_scroll && full_screen) // overwrite last message 1423 { 1424 msg_row = cmdline_row; 1425 msg_col = 1426 #ifdef FEAT_RIGHTLEFT 1427 cmdmsg_rl ? Columns - 1 : 1428 #endif 1429 0; 1430 } 1431 else if (msg_didout) // start message on next line 1432 { 1433 msg_putchar('\n'); 1434 did_return = TRUE; 1435 if (exmode_active != EXMODE_NORMAL) 1436 cmdline_row = msg_row; 1437 } 1438 if (!msg_didany || lines_left < 0) 1439 msg_starthere(); 1440 if (msg_silent == 0) 1441 { 1442 msg_didout = FALSE; // no output on current line yet 1443 cursor_off(); 1444 } 1445 1446 // when redirecting, may need to start a new line. 1447 if (!did_return) 1448 redir_write((char_u *)"\n", -1); 1449 } 1450 1451 /* 1452 * Note that the current msg position is where messages start. 1453 */ 1454 void 1455 msg_starthere(void) 1456 { 1457 lines_left = cmdline_row; 1458 msg_didany = FALSE; 1459 } 1460 1461 void 1462 msg_putchar(int c) 1463 { 1464 msg_putchar_attr(c, 0); 1465 } 1466 1467 void 1468 msg_putchar_attr(int c, int attr) 1469 { 1470 char_u buf[MB_MAXBYTES + 1]; 1471 1472 if (IS_SPECIAL(c)) 1473 { 1474 buf[0] = K_SPECIAL; 1475 buf[1] = K_SECOND(c); 1476 buf[2] = K_THIRD(c); 1477 buf[3] = NUL; 1478 } 1479 else 1480 buf[(*mb_char2bytes)(c, buf)] = NUL; 1481 msg_puts_attr((char *)buf, attr); 1482 } 1483 1484 void 1485 msg_outnum(long n) 1486 { 1487 char buf[20]; 1488 1489 sprintf(buf, "%ld", n); 1490 msg_puts(buf); 1491 } 1492 1493 void 1494 msg_home_replace(char_u *fname) 1495 { 1496 msg_home_replace_attr(fname, 0); 1497 } 1498 1499 #if defined(FEAT_FIND_ID) || defined(PROTO) 1500 void 1501 msg_home_replace_hl(char_u *fname) 1502 { 1503 msg_home_replace_attr(fname, HL_ATTR(HLF_D)); 1504 } 1505 #endif 1506 1507 static void 1508 msg_home_replace_attr(char_u *fname, int attr) 1509 { 1510 char_u *name; 1511 1512 name = home_replace_save(NULL, fname); 1513 if (name != NULL) 1514 msg_outtrans_attr(name, attr); 1515 vim_free(name); 1516 } 1517 1518 /* 1519 * Output 'len' characters in 'str' (including NULs) with translation 1520 * if 'len' is -1, output up to a NUL character. 1521 * Use attributes 'attr'. 1522 * Return the number of characters it takes on the screen. 1523 */ 1524 int 1525 msg_outtrans(char_u *str) 1526 { 1527 return msg_outtrans_attr(str, 0); 1528 } 1529 1530 int 1531 msg_outtrans_attr(char_u *str, int attr) 1532 { 1533 return msg_outtrans_len_attr(str, (int)STRLEN(str), attr); 1534 } 1535 1536 int 1537 msg_outtrans_len(char_u *str, int len) 1538 { 1539 return msg_outtrans_len_attr(str, len, 0); 1540 } 1541 1542 /* 1543 * Output one character at "p". Return pointer to the next character. 1544 * Handles multi-byte characters. 1545 */ 1546 char_u * 1547 msg_outtrans_one(char_u *p, int attr) 1548 { 1549 int l; 1550 1551 if (has_mbyte && (l = (*mb_ptr2len)(p)) > 1) 1552 { 1553 msg_outtrans_len_attr(p, l, attr); 1554 return p + l; 1555 } 1556 msg_puts_attr((char *)transchar_byte(*p), attr); 1557 return p + 1; 1558 } 1559 1560 int 1561 msg_outtrans_len_attr(char_u *msgstr, int len, int attr) 1562 { 1563 int retval = 0; 1564 char_u *str = msgstr; 1565 char_u *plain_start = msgstr; 1566 char_u *s; 1567 int mb_l; 1568 int c; 1569 int save_got_int = got_int; 1570 1571 // Only quit when got_int was set in here. 1572 got_int = FALSE; 1573 1574 // if MSG_HIST flag set, add message to history 1575 if (attr & MSG_HIST) 1576 { 1577 add_msg_hist(str, len, attr); 1578 attr &= ~MSG_HIST; 1579 } 1580 1581 // If the string starts with a composing character first draw a space on 1582 // which the composing char can be drawn. 1583 if (enc_utf8 && utf_iscomposing(utf_ptr2char(msgstr))) 1584 msg_puts_attr(" ", attr); 1585 1586 /* 1587 * Go over the string. Special characters are translated and printed. 1588 * Normal characters are printed several at a time. 1589 */ 1590 while (--len >= 0 && !got_int) 1591 { 1592 if (enc_utf8) 1593 // Don't include composing chars after the end. 1594 mb_l = utfc_ptr2len_len(str, len + 1); 1595 else if (has_mbyte) 1596 mb_l = (*mb_ptr2len)(str); 1597 else 1598 mb_l = 1; 1599 if (has_mbyte && mb_l > 1) 1600 { 1601 c = (*mb_ptr2char)(str); 1602 if (vim_isprintc(c)) 1603 // printable multi-byte char: count the cells. 1604 retval += (*mb_ptr2cells)(str); 1605 else 1606 { 1607 // unprintable multi-byte char: print the printable chars so 1608 // far and the translation of the unprintable char. 1609 if (str > plain_start) 1610 msg_puts_attr_len((char *)plain_start, 1611 (int)(str - plain_start), attr); 1612 plain_start = str + mb_l; 1613 msg_puts_attr((char *)transchar(c), 1614 attr == 0 ? HL_ATTR(HLF_8) : attr); 1615 retval += char2cells(c); 1616 } 1617 len -= mb_l - 1; 1618 str += mb_l; 1619 } 1620 else 1621 { 1622 s = transchar_byte(*str); 1623 if (s[1] != NUL) 1624 { 1625 // unprintable char: print the printable chars so far and the 1626 // translation of the unprintable char. 1627 if (str > plain_start) 1628 msg_puts_attr_len((char *)plain_start, 1629 (int)(str - plain_start), attr); 1630 plain_start = str + 1; 1631 msg_puts_attr((char *)s, attr == 0 ? HL_ATTR(HLF_8) : attr); 1632 retval += (int)STRLEN(s); 1633 } 1634 else 1635 ++retval; 1636 ++str; 1637 } 1638 } 1639 1640 if (str > plain_start && !got_int) 1641 // print the printable chars at the end 1642 msg_puts_attr_len((char *)plain_start, (int)(str - plain_start), attr); 1643 1644 got_int |= save_got_int; 1645 1646 return retval; 1647 } 1648 1649 #if defined(FEAT_QUICKFIX) || defined(PROTO) 1650 void 1651 msg_make(char_u *arg) 1652 { 1653 int i; 1654 static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB"; 1655 1656 arg = skipwhite(arg); 1657 for (i = 5; *arg && i >= 0; --i) 1658 if (*arg++ != str[i]) 1659 break; 1660 if (i < 0) 1661 { 1662 msg_putchar('\n'); 1663 for (i = 0; rs[i]; ++i) 1664 msg_putchar(rs[i] - 3); 1665 } 1666 } 1667 #endif 1668 1669 /* 1670 * Output the string 'str' up to a NUL character. 1671 * Return the number of characters it takes on the screen. 1672 * 1673 * If K_SPECIAL is encountered, then it is taken in conjunction with the 1674 * following character and shown as <F1>, <S-Up> etc. Any other character 1675 * which is not printable shown in <> form. 1676 * If 'from' is TRUE (lhs of a mapping), a space is shown as <Space>. 1677 * If a character is displayed in one of these special ways, is also 1678 * highlighted (its highlight name is '8' in the p_hl variable). 1679 * Otherwise characters are not highlighted. 1680 * This function is used to show mappings, where we want to see how to type 1681 * the character/string -- webb 1682 */ 1683 int 1684 msg_outtrans_special( 1685 char_u *strstart, 1686 int from, // TRUE for lhs of a mapping 1687 int maxlen) // screen columns, 0 for unlimited 1688 { 1689 char_u *str = strstart; 1690 int retval = 0; 1691 char *text; 1692 int attr; 1693 int len; 1694 1695 attr = HL_ATTR(HLF_8); 1696 while (*str != NUL) 1697 { 1698 // Leading and trailing spaces need to be displayed in <> form. 1699 if ((str == strstart || str[1] == NUL) && *str == ' ') 1700 { 1701 text = "<Space>"; 1702 ++str; 1703 } 1704 else 1705 text = (char *)str2special(&str, from); 1706 len = vim_strsize((char_u *)text); 1707 if (maxlen > 0 && retval + len >= maxlen) 1708 break; 1709 // Highlight special keys 1710 msg_puts_attr(text, len > 1 1711 && (*mb_ptr2len)((char_u *)text) <= 1 ? attr : 0); 1712 retval += len; 1713 } 1714 return retval; 1715 } 1716 1717 #if defined(FEAT_EVAL) || defined(PROTO) 1718 /* 1719 * Return the lhs or rhs of a mapping, with the key codes turned into printable 1720 * strings, in an allocated string. 1721 */ 1722 char_u * 1723 str2special_save( 1724 char_u *str, 1725 int is_lhs) // TRUE for lhs, FALSE for rhs 1726 { 1727 garray_T ga; 1728 char_u *p = str; 1729 1730 ga_init2(&ga, 1, 40); 1731 while (*p != NUL) 1732 ga_concat(&ga, str2special(&p, is_lhs)); 1733 ga_append(&ga, NUL); 1734 return (char_u *)ga.ga_data; 1735 } 1736 #endif 1737 1738 /* 1739 * Return the printable string for the key codes at "*sp". 1740 * Used for translating the lhs or rhs of a mapping to printable chars. 1741 * Advances "sp" to the next code. 1742 */ 1743 char_u * 1744 str2special( 1745 char_u **sp, 1746 int from) // TRUE for lhs of mapping 1747 { 1748 int c; 1749 static char_u buf[7]; 1750 char_u *str = *sp; 1751 int modifiers = 0; 1752 int special = FALSE; 1753 1754 if (has_mbyte) 1755 { 1756 char_u *p; 1757 1758 // Try to un-escape a multi-byte character. Return the un-escaped 1759 // string if it is a multi-byte character. 1760 p = mb_unescape(sp); 1761 if (p != NULL) 1762 return p; 1763 } 1764 1765 c = *str; 1766 if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) 1767 { 1768 if (str[1] == KS_MODIFIER) 1769 { 1770 modifiers = str[2]; 1771 str += 3; 1772 c = *str; 1773 } 1774 if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL) 1775 { 1776 c = TO_SPECIAL(str[1], str[2]); 1777 str += 2; 1778 } 1779 if (IS_SPECIAL(c) || modifiers) // special key 1780 special = TRUE; 1781 } 1782 1783 if (has_mbyte && !IS_SPECIAL(c)) 1784 { 1785 int len = (*mb_ptr2len)(str); 1786 1787 // For multi-byte characters check for an illegal byte. 1788 if (has_mbyte && MB_BYTE2LEN(*str) > len) 1789 { 1790 transchar_nonprint(curbuf, buf, c); 1791 *sp = str + 1; 1792 return buf; 1793 } 1794 // Since 'special' is TRUE the multi-byte character 'c' will be 1795 // processed by get_special_key_name() 1796 c = (*mb_ptr2char)(str); 1797 *sp = str + len; 1798 } 1799 else 1800 *sp = str + 1; 1801 1802 // Make unprintable characters in <> form, also <M-Space> and <Tab>. 1803 // Use <Space> only for lhs of a mapping. 1804 if (special || char2cells(c) > 1 || (from && c == ' ')) 1805 return get_special_key_name(c, modifiers); 1806 buf[0] = c; 1807 buf[1] = NUL; 1808 return buf; 1809 } 1810 1811 /* 1812 * Translate a key sequence into special key names. 1813 */ 1814 void 1815 str2specialbuf(char_u *sp, char_u *buf, int len) 1816 { 1817 char_u *s; 1818 1819 *buf = NUL; 1820 while (*sp) 1821 { 1822 s = str2special(&sp, FALSE); 1823 if ((int)(STRLEN(s) + STRLEN(buf)) < len) 1824 STRCAT(buf, s); 1825 } 1826 } 1827 1828 /* 1829 * print line for :print or :list command 1830 */ 1831 void 1832 msg_prt_line(char_u *s, int list) 1833 { 1834 int c; 1835 int col = 0; 1836 int n_extra = 0; 1837 int c_extra = 0; 1838 int c_final = 0; 1839 char_u *p_extra = NULL; // init to make SASC shut up 1840 int n; 1841 int attr = 0; 1842 char_u *trail = NULL; 1843 char_u *lead = NULL; 1844 int in_multispace = FALSE; 1845 int multispace_pos = 0; 1846 int l; 1847 char_u buf[MB_MAXBYTES + 1]; 1848 1849 if (curwin->w_p_list) 1850 list = TRUE; 1851 1852 if (list) 1853 { 1854 // find start of trailing whitespace 1855 if (curwin->w_lcs_chars.trail) 1856 { 1857 trail = s + STRLEN(s); 1858 while (trail > s && VIM_ISWHITE(trail[-1])) 1859 --trail; 1860 } 1861 // find end of leading whitespace 1862 if (curwin->w_lcs_chars.lead) 1863 { 1864 lead = s; 1865 while (VIM_ISWHITE(lead[0])) 1866 lead++; 1867 // in a line full of spaces all of them are treated as trailing 1868 if (*lead == NUL) 1869 lead = NULL; 1870 } 1871 } 1872 1873 // output a space for an empty line, otherwise the line will be 1874 // overwritten 1875 if (*s == NUL && !(list && curwin->w_lcs_chars.eol != NUL)) 1876 msg_putchar(' '); 1877 1878 while (!got_int) 1879 { 1880 if (n_extra > 0) 1881 { 1882 --n_extra; 1883 if (n_extra == 0 && c_final) 1884 c = c_final; 1885 else if (c_extra) 1886 c = c_extra; 1887 else 1888 c = *p_extra++; 1889 } 1890 else if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1) 1891 { 1892 col += (*mb_ptr2cells)(s); 1893 if (l >= MB_MAXBYTES) 1894 { 1895 STRCPY(buf, "?"); 1896 } 1897 else if (curwin->w_lcs_chars.nbsp != NUL && list 1898 && (mb_ptr2char(s) == 160 1899 || mb_ptr2char(s) == 0x202f)) 1900 { 1901 mb_char2bytes(curwin->w_lcs_chars.nbsp, buf); 1902 buf[(*mb_ptr2len)(buf)] = NUL; 1903 } 1904 else 1905 { 1906 mch_memmove(buf, s, (size_t)l); 1907 buf[l] = NUL; 1908 } 1909 msg_puts((char *)buf); 1910 s += l; 1911 continue; 1912 } 1913 else 1914 { 1915 attr = 0; 1916 c = *s++; 1917 in_multispace = c == ' ' 1918 && ((col > 0 && s[-2] == ' ') || *s == ' '); 1919 if (!in_multispace) 1920 multispace_pos = 0; 1921 if (c == TAB && (!list || curwin->w_lcs_chars.tab1)) 1922 { 1923 // tab amount depends on current column 1924 #ifdef FEAT_VARTABS 1925 n_extra = tabstop_padding(col, curbuf->b_p_ts, 1926 curbuf->b_p_vts_array) - 1; 1927 #else 1928 n_extra = curbuf->b_p_ts - col % curbuf->b_p_ts - 1; 1929 #endif 1930 if (!list) 1931 { 1932 c = ' '; 1933 c_extra = ' '; 1934 c_final = NUL; 1935 } 1936 else 1937 { 1938 c = (n_extra == 0 && curwin->w_lcs_chars.tab3) 1939 ? curwin->w_lcs_chars.tab3 1940 : curwin->w_lcs_chars.tab1; 1941 c_extra = curwin->w_lcs_chars.tab2; 1942 c_final = curwin->w_lcs_chars.tab3; 1943 attr = HL_ATTR(HLF_8); 1944 } 1945 } 1946 else if (c == 160 && list && curwin->w_lcs_chars.nbsp != NUL) 1947 { 1948 c = curwin->w_lcs_chars.nbsp; 1949 attr = HL_ATTR(HLF_8); 1950 } 1951 else if (c == NUL && list && curwin->w_lcs_chars.eol != NUL) 1952 { 1953 p_extra = (char_u *)""; 1954 c_extra = NUL; 1955 c_final = NUL; 1956 n_extra = 1; 1957 c = curwin->w_lcs_chars.eol; 1958 attr = HL_ATTR(HLF_AT); 1959 --s; 1960 } 1961 else if (c != NUL && (n = byte2cells(c)) > 1) 1962 { 1963 n_extra = n - 1; 1964 p_extra = transchar_byte(c); 1965 c_extra = NUL; 1966 c_final = NUL; 1967 c = *p_extra++; 1968 // Use special coloring to be able to distinguish <hex> from 1969 // the same in plain text. 1970 attr = HL_ATTR(HLF_8); 1971 } 1972 else if (c == ' ') 1973 { 1974 if (lead != NULL && s <= lead) 1975 { 1976 c = curwin->w_lcs_chars.lead; 1977 attr = HL_ATTR(HLF_8); 1978 } 1979 else if (trail != NULL && s > trail) 1980 { 1981 c = curwin->w_lcs_chars.trail; 1982 attr = HL_ATTR(HLF_8); 1983 } 1984 else if (list && in_multispace 1985 && curwin->w_lcs_chars.multispace != NULL) 1986 { 1987 c = curwin->w_lcs_chars.multispace[multispace_pos++]; 1988 if (curwin->w_lcs_chars.multispace[multispace_pos] == NUL) 1989 multispace_pos = 0; 1990 attr = HL_ATTR(HLF_8); 1991 } 1992 else if (list && curwin->w_lcs_chars.space != NUL) 1993 { 1994 c = curwin->w_lcs_chars.space; 1995 attr = HL_ATTR(HLF_8); 1996 } 1997 } 1998 } 1999 2000 if (c == NUL) 2001 break; 2002 2003 msg_putchar_attr(c, attr); 2004 col++; 2005 } 2006 msg_clr_eos(); 2007 } 2008 2009 /* 2010 * Use screen_puts() to output one multi-byte character. 2011 * Return the pointer "s" advanced to the next character. 2012 */ 2013 static char_u * 2014 screen_puts_mbyte(char_u *s, int l, int attr) 2015 { 2016 int cw; 2017 2018 msg_didout = TRUE; // remember that line is not empty 2019 cw = (*mb_ptr2cells)(s); 2020 if (cw > 1 && ( 2021 #ifdef FEAT_RIGHTLEFT 2022 cmdmsg_rl ? msg_col <= 1 : 2023 #endif 2024 msg_col == Columns - 1)) 2025 { 2026 // Doesn't fit, print a highlighted '>' to fill it up. 2027 msg_screen_putchar('>', HL_ATTR(HLF_AT)); 2028 return s; 2029 } 2030 2031 screen_puts_len(s, l, msg_row, msg_col, attr); 2032 #ifdef FEAT_RIGHTLEFT 2033 if (cmdmsg_rl) 2034 { 2035 msg_col -= cw; 2036 if (msg_col == 0) 2037 { 2038 msg_col = Columns; 2039 ++msg_row; 2040 } 2041 } 2042 else 2043 #endif 2044 { 2045 msg_col += cw; 2046 if (msg_col >= Columns) 2047 { 2048 msg_col = 0; 2049 ++msg_row; 2050 } 2051 } 2052 return s + l; 2053 } 2054 2055 /* 2056 * Output a string to the screen at position msg_row, msg_col. 2057 * Update msg_row and msg_col for the next message. 2058 */ 2059 void 2060 msg_puts(char *s) 2061 { 2062 msg_puts_attr(s, 0); 2063 } 2064 2065 void 2066 msg_puts_title(char *s) 2067 { 2068 msg_puts_attr(s, HL_ATTR(HLF_T)); 2069 } 2070 2071 /* 2072 * Show a message in such a way that it always fits in the line. Cut out a 2073 * part in the middle and replace it with "..." when necessary. 2074 * Does not handle multi-byte characters! 2075 */ 2076 static void 2077 msg_outtrans_long_len_attr(char_u *longstr, int len, int attr) 2078 { 2079 int slen = len; 2080 int room; 2081 2082 room = Columns - msg_col; 2083 if (len > room && room >= 20) 2084 { 2085 slen = (room - 3) / 2; 2086 msg_outtrans_len_attr(longstr, slen, attr); 2087 msg_puts_attr("...", HL_ATTR(HLF_8)); 2088 } 2089 msg_outtrans_len_attr(longstr + len - slen, slen, attr); 2090 } 2091 2092 void 2093 msg_outtrans_long_attr(char_u *longstr, int attr) 2094 { 2095 msg_outtrans_long_len_attr(longstr, (int)STRLEN(longstr), attr); 2096 } 2097 2098 /* 2099 * Basic function for writing a message with highlight attributes. 2100 */ 2101 void 2102 msg_puts_attr(char *s, int attr) 2103 { 2104 msg_puts_attr_len(s, -1, attr); 2105 } 2106 2107 /* 2108 * Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes). 2109 * When "maxlen" is -1 there is no maximum length. 2110 * When "maxlen" is >= 0 the message is not put in the history. 2111 */ 2112 static void 2113 msg_puts_attr_len(char *str, int maxlen, int attr) 2114 { 2115 /* 2116 * If redirection is on, also write to the redirection file. 2117 */ 2118 redir_write((char_u *)str, maxlen); 2119 2120 /* 2121 * Don't print anything when using ":silent cmd". 2122 */ 2123 if (msg_silent != 0) 2124 return; 2125 2126 // if MSG_HIST flag set, add message to history 2127 if ((attr & MSG_HIST) && maxlen < 0) 2128 { 2129 add_msg_hist((char_u *)str, -1, attr); 2130 attr &= ~MSG_HIST; 2131 } 2132 2133 // When writing something to the screen after it has scrolled, requires a 2134 // wait-return prompt later. Needed when scrolling, resetting 2135 // need_wait_return after some prompt, and then outputting something 2136 // without scrolling 2137 // Not needed when only using CR to move the cursor. 2138 if (msg_scrolled != 0 && !msg_scrolled_ign && STRCMP(str, "\r") != 0) 2139 need_wait_return = TRUE; 2140 msg_didany = TRUE; // remember that something was outputted 2141 2142 /* 2143 * If there is no valid screen, use fprintf so we can see error messages. 2144 * If termcap is not active, we may be writing in an alternate console 2145 * window, cursor positioning may not work correctly (window size may be 2146 * different, e.g. for Win32 console) or we just don't know where the 2147 * cursor is. 2148 */ 2149 if (msg_use_printf()) 2150 msg_puts_printf((char_u *)str, maxlen); 2151 else 2152 msg_puts_display((char_u *)str, maxlen, attr, FALSE); 2153 } 2154 2155 /* 2156 * The display part of msg_puts_attr_len(). 2157 * May be called recursively to display scroll-back text. 2158 */ 2159 static void 2160 msg_puts_display( 2161 char_u *str, 2162 int maxlen, 2163 int attr, 2164 int recurse) 2165 { 2166 char_u *s = str; 2167 char_u *t_s = str; // string from "t_s" to "s" is still todo 2168 int t_col = 0; // screen cells todo, 0 when "t_s" not used 2169 int l; 2170 int cw; 2171 char_u *sb_str = str; 2172 int sb_col = msg_col; 2173 int wrap; 2174 int did_last_char; 2175 2176 did_wait_return = FALSE; 2177 while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) 2178 { 2179 /* 2180 * We are at the end of the screen line when: 2181 * - When outputting a newline. 2182 * - When outputting a character in the last column. 2183 */ 2184 if (!recurse && msg_row >= Rows - 1 && (*s == '\n' || ( 2185 #ifdef FEAT_RIGHTLEFT 2186 cmdmsg_rl 2187 ? ( 2188 msg_col <= 1 2189 || (*s == TAB && msg_col <= 7) 2190 || (has_mbyte && (*mb_ptr2cells)(s) > 1 && msg_col <= 2)) 2191 : 2192 #endif 2193 ((*s != '\r' && msg_col + t_col >= Columns - 1) 2194 || (*s == TAB && msg_col + t_col >= ((Columns - 1) & ~7)) 2195 || (has_mbyte && (*mb_ptr2cells)(s) > 1 2196 && msg_col + t_col >= Columns - 2))))) 2197 { 2198 /* 2199 * The screen is scrolled up when at the last row (some terminals 2200 * scroll automatically, some don't. To avoid problems we scroll 2201 * ourselves). 2202 */ 2203 if (t_col > 0) 2204 // output postponed text 2205 t_puts(&t_col, t_s, s, attr); 2206 2207 // When no more prompt and no more room, truncate here 2208 if (msg_no_more && lines_left == 0) 2209 break; 2210 2211 // Scroll the screen up one line. 2212 msg_scroll_up(); 2213 2214 msg_row = Rows - 2; 2215 if (msg_col >= Columns) // can happen after screen resize 2216 msg_col = Columns - 1; 2217 2218 // Display char in last column before showing more-prompt. 2219 if (*s >= ' ' 2220 #ifdef FEAT_RIGHTLEFT 2221 && !cmdmsg_rl 2222 #endif 2223 ) 2224 { 2225 if (has_mbyte) 2226 { 2227 if (enc_utf8 && maxlen >= 0) 2228 // avoid including composing chars after the end 2229 l = utfc_ptr2len_len(s, (int)((str + maxlen) - s)); 2230 else 2231 l = (*mb_ptr2len)(s); 2232 s = screen_puts_mbyte(s, l, attr); 2233 } 2234 else 2235 msg_screen_putchar(*s++, attr); 2236 did_last_char = TRUE; 2237 } 2238 else 2239 did_last_char = FALSE; 2240 2241 if (p_more) 2242 // store text for scrolling back 2243 store_sb_text(&sb_str, s, attr, &sb_col, TRUE); 2244 2245 inc_msg_scrolled(); 2246 need_wait_return = TRUE; // may need wait_return in main() 2247 redraw_cmdline = TRUE; 2248 if (cmdline_row > 0 && !exmode_active) 2249 --cmdline_row; 2250 2251 /* 2252 * If screen is completely filled and 'more' is set then wait 2253 * for a character. 2254 */ 2255 if (lines_left > 0) 2256 --lines_left; 2257 if (p_more && lines_left == 0 && State != HITRETURN 2258 && !msg_no_more && !exmode_active) 2259 { 2260 #ifdef FEAT_CON_DIALOG 2261 if (do_more_prompt(NUL)) 2262 s = confirm_msg_tail; 2263 #else 2264 (void)do_more_prompt(NUL); 2265 #endif 2266 if (quit_more) 2267 return; 2268 } 2269 2270 // When we displayed a char in last column need to check if there 2271 // is still more. 2272 if (did_last_char) 2273 continue; 2274 } 2275 2276 wrap = *s == '\n' 2277 || msg_col + t_col >= Columns 2278 || (has_mbyte && (*mb_ptr2cells)(s) > 1 2279 && msg_col + t_col >= Columns - 1); 2280 if (t_col > 0 && (wrap || *s == '\r' || *s == '\b' 2281 || *s == '\t' || *s == BELL)) 2282 // output any postponed text 2283 t_puts(&t_col, t_s, s, attr); 2284 2285 if (wrap && p_more && !recurse) 2286 // store text for scrolling back 2287 store_sb_text(&sb_str, s, attr, &sb_col, TRUE); 2288 2289 if (*s == '\n') // go to next line 2290 { 2291 msg_didout = FALSE; // remember that line is empty 2292 #ifdef FEAT_RIGHTLEFT 2293 if (cmdmsg_rl) 2294 msg_col = Columns - 1; 2295 else 2296 #endif 2297 msg_col = 0; 2298 if (++msg_row >= Rows) // safety check 2299 msg_row = Rows - 1; 2300 } 2301 else if (*s == '\r') // go to column 0 2302 { 2303 msg_col = 0; 2304 } 2305 else if (*s == '\b') // go to previous char 2306 { 2307 if (msg_col) 2308 --msg_col; 2309 } 2310 else if (*s == TAB) // translate Tab into spaces 2311 { 2312 do 2313 msg_screen_putchar(' ', attr); 2314 while (msg_col & 7); 2315 } 2316 else if (*s == BELL) // beep (from ":sh") 2317 vim_beep(BO_SH); 2318 else 2319 { 2320 if (has_mbyte) 2321 { 2322 cw = (*mb_ptr2cells)(s); 2323 if (enc_utf8 && maxlen >= 0) 2324 // avoid including composing chars after the end 2325 l = utfc_ptr2len_len(s, (int)((str + maxlen) - s)); 2326 else 2327 l = (*mb_ptr2len)(s); 2328 } 2329 else 2330 { 2331 cw = 1; 2332 l = 1; 2333 } 2334 2335 // When drawing from right to left or when a double-wide character 2336 // doesn't fit, draw a single character here. Otherwise collect 2337 // characters and draw them all at once later. 2338 if ( 2339 # ifdef FEAT_RIGHTLEFT 2340 cmdmsg_rl || 2341 # endif 2342 (cw > 1 && msg_col + t_col >= Columns - 1)) 2343 { 2344 if (l > 1) 2345 s = screen_puts_mbyte(s, l, attr) - 1; 2346 else 2347 msg_screen_putchar(*s, attr); 2348 } 2349 else 2350 { 2351 // postpone this character until later 2352 if (t_col == 0) 2353 t_s = s; 2354 t_col += cw; 2355 s += l - 1; 2356 } 2357 } 2358 ++s; 2359 } 2360 2361 // output any postponed text 2362 if (t_col > 0) 2363 t_puts(&t_col, t_s, s, attr); 2364 if (p_more && !recurse) 2365 store_sb_text(&sb_str, s, attr, &sb_col, FALSE); 2366 2367 msg_check(); 2368 } 2369 2370 /* 2371 * Return TRUE when ":filter pattern" was used and "msg" does not match 2372 * "pattern". 2373 */ 2374 int 2375 message_filtered(char_u *msg) 2376 { 2377 int match; 2378 2379 if (cmdmod.cmod_filter_regmatch.regprog == NULL) 2380 return FALSE; 2381 match = vim_regexec(&cmdmod.cmod_filter_regmatch, msg, (colnr_T)0); 2382 return cmdmod.cmod_filter_force ? match : !match; 2383 } 2384 2385 /* 2386 * Scroll the screen up one line for displaying the next message line. 2387 */ 2388 static void 2389 msg_scroll_up(void) 2390 { 2391 #ifdef FEAT_GUI 2392 // Remove the cursor before scrolling, ScreenLines[] is going 2393 // to become invalid. 2394 if (gui.in_use) 2395 gui_undraw_cursor(); 2396 #endif 2397 // scrolling up always works 2398 mch_disable_flush(); 2399 screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL); 2400 mch_enable_flush(); 2401 2402 if (!can_clear((char_u *)" ")) 2403 { 2404 // Scrolling up doesn't result in the right background. Set the 2405 // background here. It's not efficient, but avoids that we have to do 2406 // it all over the code. 2407 screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 2408 2409 // Also clear the last char of the last but one line if it was not 2410 // cleared before to avoid a scroll-up. 2411 if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1] == (sattr_T)-1) 2412 screen_fill((int)Rows - 2, (int)Rows - 1, 2413 (int)Columns - 1, (int)Columns, ' ', ' ', 0); 2414 } 2415 } 2416 2417 /* 2418 * Increment "msg_scrolled". 2419 */ 2420 static void 2421 inc_msg_scrolled(void) 2422 { 2423 #ifdef FEAT_EVAL 2424 if (*get_vim_var_str(VV_SCROLLSTART) == NUL) 2425 { 2426 char_u *p = SOURCING_NAME; 2427 char_u *tofree = NULL; 2428 int len; 2429 2430 // v:scrollstart is empty, set it to the script/function name and line 2431 // number 2432 if (p == NULL) 2433 p = (char_u *)_("Unknown"); 2434 else 2435 { 2436 len = (int)STRLEN(p) + 40; 2437 tofree = alloc(len); 2438 if (tofree != NULL) 2439 { 2440 vim_snprintf((char *)tofree, len, _("%s line %ld"), 2441 p, (long)SOURCING_LNUM); 2442 p = tofree; 2443 } 2444 } 2445 set_vim_var_string(VV_SCROLLSTART, p, -1); 2446 vim_free(tofree); 2447 } 2448 #endif 2449 ++msg_scrolled; 2450 if (must_redraw < VALID) 2451 must_redraw = VALID; 2452 } 2453 2454 /* 2455 * To be able to scroll back at the "more" and "hit-enter" prompts we need to 2456 * store the displayed text and remember where screen lines start. 2457 */ 2458 typedef struct msgchunk_S msgchunk_T; 2459 struct msgchunk_S 2460 { 2461 msgchunk_T *sb_next; 2462 msgchunk_T *sb_prev; 2463 char sb_eol; // TRUE when line ends after this text 2464 int sb_msg_col; // column in which text starts 2465 int sb_attr; // text attributes 2466 char_u sb_text[1]; // text to be displayed, actually longer 2467 }; 2468 2469 static msgchunk_T *last_msgchunk = NULL; // last displayed text 2470 2471 static msgchunk_T *msg_sb_start(msgchunk_T *mps); 2472 2473 typedef enum { 2474 SB_CLEAR_NONE = 0, 2475 SB_CLEAR_ALL, 2476 SB_CLEAR_CMDLINE_BUSY, 2477 SB_CLEAR_CMDLINE_DONE 2478 } sb_clear_T; 2479 2480 // When to clear text on next msg. 2481 static sb_clear_T do_clear_sb_text = SB_CLEAR_NONE; 2482 2483 /* 2484 * Store part of a printed message for displaying when scrolling back. 2485 */ 2486 static void 2487 store_sb_text( 2488 char_u **sb_str, // start of string 2489 char_u *s, // just after string 2490 int attr, 2491 int *sb_col, 2492 int finish) // line ends 2493 { 2494 msgchunk_T *mp; 2495 2496 if (do_clear_sb_text == SB_CLEAR_ALL 2497 || do_clear_sb_text == SB_CLEAR_CMDLINE_DONE) 2498 { 2499 clear_sb_text(do_clear_sb_text == SB_CLEAR_ALL); 2500 do_clear_sb_text = SB_CLEAR_NONE; 2501 } 2502 2503 if (s > *sb_str) 2504 { 2505 mp = alloc(sizeof(msgchunk_T) + (s - *sb_str)); 2506 if (mp != NULL) 2507 { 2508 mp->sb_eol = finish; 2509 mp->sb_msg_col = *sb_col; 2510 mp->sb_attr = attr; 2511 vim_strncpy(mp->sb_text, *sb_str, s - *sb_str); 2512 2513 if (last_msgchunk == NULL) 2514 { 2515 last_msgchunk = mp; 2516 mp->sb_prev = NULL; 2517 } 2518 else 2519 { 2520 mp->sb_prev = last_msgchunk; 2521 last_msgchunk->sb_next = mp; 2522 last_msgchunk = mp; 2523 } 2524 mp->sb_next = NULL; 2525 } 2526 } 2527 else if (finish && last_msgchunk != NULL) 2528 last_msgchunk->sb_eol = TRUE; 2529 2530 *sb_str = s; 2531 *sb_col = 0; 2532 } 2533 2534 /* 2535 * Finished showing messages, clear the scroll-back text on the next message. 2536 */ 2537 void 2538 may_clear_sb_text(void) 2539 { 2540 do_clear_sb_text = SB_CLEAR_ALL; 2541 } 2542 2543 /* 2544 * Starting to edit the command line, do not clear messages now. 2545 */ 2546 void 2547 sb_text_start_cmdline(void) 2548 { 2549 do_clear_sb_text = SB_CLEAR_CMDLINE_BUSY; 2550 msg_sb_eol(); 2551 } 2552 2553 /* 2554 * Ending to edit the command line. Clear old lines but the last one later. 2555 */ 2556 void 2557 sb_text_end_cmdline(void) 2558 { 2559 do_clear_sb_text = SB_CLEAR_CMDLINE_DONE; 2560 } 2561 2562 /* 2563 * Clear any text remembered for scrolling back. 2564 * When "all" is FALSE keep the last line. 2565 * Called when redrawing the screen. 2566 */ 2567 void 2568 clear_sb_text(int all) 2569 { 2570 msgchunk_T *mp; 2571 msgchunk_T **lastp; 2572 2573 if (all) 2574 lastp = &last_msgchunk; 2575 else 2576 { 2577 if (last_msgchunk == NULL) 2578 return; 2579 lastp = &last_msgchunk->sb_prev; 2580 } 2581 2582 while (*lastp != NULL) 2583 { 2584 mp = (*lastp)->sb_prev; 2585 vim_free(*lastp); 2586 *lastp = mp; 2587 } 2588 } 2589 2590 /* 2591 * "g<" command. 2592 */ 2593 void 2594 show_sb_text(void) 2595 { 2596 msgchunk_T *mp; 2597 2598 // Only show something if there is more than one line, otherwise it looks 2599 // weird, typing a command without output results in one line. 2600 mp = msg_sb_start(last_msgchunk); 2601 if (mp == NULL || mp->sb_prev == NULL) 2602 vim_beep(BO_MESS); 2603 else 2604 { 2605 do_more_prompt('G'); 2606 wait_return(FALSE); 2607 } 2608 } 2609 2610 /* 2611 * Move to the start of screen line in already displayed text. 2612 */ 2613 static msgchunk_T * 2614 msg_sb_start(msgchunk_T *mps) 2615 { 2616 msgchunk_T *mp = mps; 2617 2618 while (mp != NULL && mp->sb_prev != NULL && !mp->sb_prev->sb_eol) 2619 mp = mp->sb_prev; 2620 return mp; 2621 } 2622 2623 /* 2624 * Mark the last message chunk as finishing the line. 2625 */ 2626 void 2627 msg_sb_eol(void) 2628 { 2629 if (last_msgchunk != NULL) 2630 last_msgchunk->sb_eol = TRUE; 2631 } 2632 2633 /* 2634 * Display a screen line from previously displayed text at row "row". 2635 * Returns a pointer to the text for the next line (can be NULL). 2636 */ 2637 static msgchunk_T * 2638 disp_sb_line(int row, msgchunk_T *smp) 2639 { 2640 msgchunk_T *mp = smp; 2641 char_u *p; 2642 2643 for (;;) 2644 { 2645 msg_row = row; 2646 msg_col = mp->sb_msg_col; 2647 p = mp->sb_text; 2648 if (*p == '\n') // don't display the line break 2649 ++p; 2650 msg_puts_display(p, -1, mp->sb_attr, TRUE); 2651 if (mp->sb_eol || mp->sb_next == NULL) 2652 break; 2653 mp = mp->sb_next; 2654 } 2655 return mp->sb_next; 2656 } 2657 2658 /* 2659 * Output any postponed text for msg_puts_attr_len(). 2660 */ 2661 static void 2662 t_puts( 2663 int *t_col, 2664 char_u *t_s, 2665 char_u *s, 2666 int attr) 2667 { 2668 // output postponed text 2669 msg_didout = TRUE; // remember that line is not empty 2670 screen_puts_len(t_s, (int)(s - t_s), msg_row, msg_col, attr); 2671 msg_col += *t_col; 2672 *t_col = 0; 2673 // If the string starts with a composing character don't increment the 2674 // column position for it. 2675 if (enc_utf8 && utf_iscomposing(utf_ptr2char(t_s))) 2676 --msg_col; 2677 if (msg_col >= Columns) 2678 { 2679 msg_col = 0; 2680 ++msg_row; 2681 } 2682 } 2683 2684 /* 2685 * Returns TRUE when messages should be printed with mch_errmsg(). 2686 * This is used when there is no valid screen, so we can see error messages. 2687 * If termcap is not active, we may be writing in an alternate console 2688 * window, cursor positioning may not work correctly (window size may be 2689 * different, e.g. for Win32 console) or we just don't know where the 2690 * cursor is. 2691 */ 2692 int 2693 msg_use_printf(void) 2694 { 2695 return (!msg_check_screen() 2696 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 2697 # ifdef VIMDLL 2698 || (!gui.in_use && !termcap_active) 2699 # else 2700 || !termcap_active 2701 # endif 2702 #endif 2703 || (swapping_screen() && !termcap_active) 2704 ); 2705 } 2706 2707 /* 2708 * Print a message when there is no valid screen. 2709 */ 2710 static void 2711 msg_puts_printf(char_u *str, int maxlen) 2712 { 2713 char_u *s = str; 2714 char_u *buf = NULL; 2715 char_u *p = s; 2716 2717 #ifdef MSWIN 2718 if (!(silent_mode && p_verbose == 0)) 2719 mch_settmode(TMODE_COOK); // handle CR and NL correctly 2720 #endif 2721 while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) 2722 { 2723 if (!(silent_mode && p_verbose == 0)) 2724 { 2725 // NL --> CR NL translation (for Unix, not for "--version") 2726 if (*s == NL) 2727 { 2728 int n = (int)(s - p); 2729 2730 buf = alloc(n + 3); 2731 if (buf != NULL) 2732 { 2733 memcpy(buf, p, n); 2734 if (!info_message) 2735 buf[n++] = CAR; 2736 buf[n++] = NL; 2737 buf[n++] = NUL; 2738 if (info_message) // informative message, not an error 2739 mch_msg((char *)buf); 2740 else 2741 mch_errmsg((char *)buf); 2742 vim_free(buf); 2743 } 2744 p = s + 1; 2745 } 2746 } 2747 2748 // primitive way to compute the current column 2749 #ifdef FEAT_RIGHTLEFT 2750 if (cmdmsg_rl) 2751 { 2752 if (*s == CAR || *s == NL) 2753 msg_col = Columns - 1; 2754 else 2755 --msg_col; 2756 } 2757 else 2758 #endif 2759 { 2760 if (*s == CAR || *s == NL) 2761 msg_col = 0; 2762 else 2763 ++msg_col; 2764 } 2765 ++s; 2766 } 2767 2768 if (*p != NUL && !(silent_mode && p_verbose == 0)) 2769 { 2770 char_u *tofree = NULL; 2771 2772 if (maxlen > 0 && STRLEN(p) > (size_t)maxlen) 2773 { 2774 tofree = vim_strnsave(p, (size_t)maxlen); 2775 p = tofree; 2776 } 2777 if (p != NULL) 2778 { 2779 if (info_message) 2780 mch_msg((char *)p); 2781 else 2782 mch_errmsg((char *)p); 2783 vim_free(tofree); 2784 } 2785 } 2786 2787 msg_didout = TRUE; // assume that line is not empty 2788 2789 #ifdef MSWIN 2790 if (!(silent_mode && p_verbose == 0)) 2791 mch_settmode(TMODE_RAW); 2792 #endif 2793 } 2794 2795 /* 2796 * Show the more-prompt and handle the user response. 2797 * This takes care of scrolling back and displaying previously displayed text. 2798 * When at hit-enter prompt "typed_char" is the already typed character, 2799 * otherwise it's NUL. 2800 * Returns TRUE when jumping ahead to "confirm_msg_tail". 2801 */ 2802 static int 2803 do_more_prompt(int typed_char) 2804 { 2805 static int entered = FALSE; 2806 int used_typed_char = typed_char; 2807 int oldState = State; 2808 int c; 2809 #ifdef FEAT_CON_DIALOG 2810 int retval = FALSE; 2811 #endif 2812 int toscroll; 2813 msgchunk_T *mp_last = NULL; 2814 msgchunk_T *mp; 2815 int i; 2816 2817 // We get called recursively when a timer callback outputs a message. In 2818 // that case don't show another prompt. Also when at the hit-Enter prompt 2819 // and nothing was typed. 2820 if (entered || (State == HITRETURN && typed_char == 0)) 2821 return FALSE; 2822 entered = TRUE; 2823 2824 if (typed_char == 'G') 2825 { 2826 // "g<": Find first line on the last page. 2827 mp_last = msg_sb_start(last_msgchunk); 2828 for (i = 0; i < Rows - 2 && mp_last != NULL 2829 && mp_last->sb_prev != NULL; ++i) 2830 mp_last = msg_sb_start(mp_last->sb_prev); 2831 } 2832 2833 State = ASKMORE; 2834 setmouse(); 2835 if (typed_char == NUL) 2836 msg_moremsg(FALSE); 2837 for (;;) 2838 { 2839 /* 2840 * Get a typed character directly from the user. 2841 */ 2842 if (used_typed_char != NUL) 2843 { 2844 c = used_typed_char; // was typed at hit-enter prompt 2845 used_typed_char = NUL; 2846 } 2847 else 2848 c = get_keystroke(); 2849 2850 #if defined(FEAT_MENU) && defined(FEAT_GUI) 2851 if (c == K_MENU) 2852 { 2853 int idx = get_menu_index(current_menu, ASKMORE); 2854 2855 // Used a menu. If it starts with CTRL-Y, it must 2856 // be a "Copy" for the clipboard. Otherwise 2857 // assume that we end 2858 if (idx == MENU_INDEX_INVALID) 2859 continue; 2860 c = *current_menu->strings[idx]; 2861 if (c != NUL && current_menu->strings[idx][1] != NUL) 2862 ins_typebuf(current_menu->strings[idx] + 1, 2863 current_menu->noremap[idx], 0, TRUE, 2864 current_menu->silent[idx]); 2865 } 2866 #endif 2867 2868 toscroll = 0; 2869 switch (c) 2870 { 2871 case BS: // scroll one line back 2872 case K_BS: 2873 case 'k': 2874 case K_UP: 2875 toscroll = -1; 2876 break; 2877 2878 case CAR: // one extra line 2879 case NL: 2880 case 'j': 2881 case K_DOWN: 2882 toscroll = 1; 2883 break; 2884 2885 case 'u': // Up half a page 2886 toscroll = -(Rows / 2); 2887 break; 2888 2889 case 'd': // Down half a page 2890 toscroll = Rows / 2; 2891 break; 2892 2893 case 'b': // one page back 2894 case K_PAGEUP: 2895 toscroll = -(Rows - 1); 2896 break; 2897 2898 case ' ': // one extra page 2899 case 'f': 2900 case K_PAGEDOWN: 2901 case K_LEFTMOUSE: 2902 toscroll = Rows - 1; 2903 break; 2904 2905 case 'g': // all the way back to the start 2906 toscroll = -999999; 2907 break; 2908 2909 case 'G': // all the way to the end 2910 toscroll = 999999; 2911 lines_left = 999999; 2912 break; 2913 2914 case ':': // start new command line 2915 #ifdef FEAT_CON_DIALOG 2916 if (!confirm_msg_used) 2917 #endif 2918 { 2919 // Since got_int is set all typeahead will be flushed, but we 2920 // want to keep this ':', remember that in a special way. 2921 typeahead_noflush(':'); 2922 #ifdef FEAT_TERMINAL 2923 skip_term_loop = TRUE; 2924 #endif 2925 cmdline_row = Rows - 1; // put ':' on this line 2926 skip_redraw = TRUE; // skip redraw once 2927 need_wait_return = FALSE; // don't wait in main() 2928 } 2929 // FALLTHROUGH 2930 case 'q': // quit 2931 case Ctrl_C: 2932 case ESC: 2933 #ifdef FEAT_CON_DIALOG 2934 if (confirm_msg_used) 2935 { 2936 // Jump to the choices of the dialog. 2937 retval = TRUE; 2938 } 2939 else 2940 #endif 2941 { 2942 got_int = TRUE; 2943 quit_more = TRUE; 2944 } 2945 // When there is some more output (wrapping line) display that 2946 // without another prompt. 2947 lines_left = Rows - 1; 2948 break; 2949 2950 #ifdef FEAT_CLIPBOARD 2951 case Ctrl_Y: 2952 // Strange way to allow copying (yanking) a modeless 2953 // selection at the more prompt. Use CTRL-Y, 2954 // because the same is used in Cmdline-mode and at the 2955 // hit-enter prompt. However, scrolling one line up 2956 // might be expected... 2957 if (clip_star.state == SELECT_DONE) 2958 clip_copy_modeless_selection(TRUE); 2959 continue; 2960 #endif 2961 default: // no valid response 2962 msg_moremsg(TRUE); 2963 continue; 2964 } 2965 2966 if (toscroll != 0) 2967 { 2968 if (toscroll < 0) 2969 { 2970 // go to start of last line 2971 if (mp_last == NULL) 2972 mp = msg_sb_start(last_msgchunk); 2973 else if (mp_last->sb_prev != NULL) 2974 mp = msg_sb_start(mp_last->sb_prev); 2975 else 2976 mp = NULL; 2977 2978 // go to start of line at top of the screen 2979 for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL; 2980 ++i) 2981 mp = msg_sb_start(mp->sb_prev); 2982 2983 if (mp != NULL && mp->sb_prev != NULL) 2984 { 2985 // Find line to be displayed at top. 2986 for (i = 0; i > toscroll; --i) 2987 { 2988 if (mp == NULL || mp->sb_prev == NULL) 2989 break; 2990 mp = msg_sb_start(mp->sb_prev); 2991 if (mp_last == NULL) 2992 mp_last = msg_sb_start(last_msgchunk); 2993 else 2994 mp_last = msg_sb_start(mp_last->sb_prev); 2995 } 2996 2997 if (toscroll == -1 && screen_ins_lines(0, 0, 1, 2998 (int)Rows, 0, NULL) == OK) 2999 { 3000 // display line at top 3001 (void)disp_sb_line(0, mp); 3002 } 3003 else 3004 { 3005 // redisplay all lines 3006 screenclear(); 3007 for (i = 0; mp != NULL && i < Rows - 1; ++i) 3008 { 3009 mp = disp_sb_line(i, mp); 3010 ++msg_scrolled; 3011 } 3012 } 3013 toscroll = 0; 3014 } 3015 } 3016 else 3017 { 3018 // First display any text that we scrolled back. 3019 while (toscroll > 0 && mp_last != NULL) 3020 { 3021 // scroll up, display line at bottom 3022 msg_scroll_up(); 3023 inc_msg_scrolled(); 3024 screen_fill((int)Rows - 2, (int)Rows - 1, 0, 3025 (int)Columns, ' ', ' ', 0); 3026 mp_last = disp_sb_line((int)Rows - 2, mp_last); 3027 --toscroll; 3028 } 3029 } 3030 3031 if (toscroll <= 0) 3032 { 3033 // displayed the requested text, more prompt again 3034 screen_fill((int)Rows - 1, (int)Rows, 0, 3035 (int)Columns, ' ', ' ', 0); 3036 msg_moremsg(FALSE); 3037 continue; 3038 } 3039 3040 // display more text, return to caller 3041 lines_left = toscroll; 3042 } 3043 3044 break; 3045 } 3046 3047 // clear the --more-- message 3048 screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 3049 State = oldState; 3050 setmouse(); 3051 if (quit_more) 3052 { 3053 msg_row = Rows - 1; 3054 msg_col = 0; 3055 } 3056 #ifdef FEAT_RIGHTLEFT 3057 else if (cmdmsg_rl) 3058 msg_col = Columns - 1; 3059 #endif 3060 3061 entered = FALSE; 3062 #ifdef FEAT_CON_DIALOG 3063 return retval; 3064 #else 3065 return FALSE; 3066 #endif 3067 } 3068 3069 #if defined(USE_MCH_ERRMSG) || defined(PROTO) 3070 3071 #ifdef mch_errmsg 3072 # undef mch_errmsg 3073 #endif 3074 #ifdef mch_msg 3075 # undef mch_msg 3076 #endif 3077 3078 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3079 static void 3080 mch_errmsg_c(char *str) 3081 { 3082 int len = (int)STRLEN(str); 3083 DWORD nwrite = 0; 3084 DWORD mode = 0; 3085 HANDLE h = GetStdHandle(STD_ERROR_HANDLE); 3086 3087 if (GetConsoleMode(h, &mode) && enc_codepage >= 0 3088 && (int)GetConsoleCP() != enc_codepage) 3089 { 3090 WCHAR *w = enc_to_utf16((char_u *)str, &len); 3091 3092 WriteConsoleW(h, w, len, &nwrite, NULL); 3093 vim_free(w); 3094 } 3095 else 3096 { 3097 fprintf(stderr, "%s", str); 3098 } 3099 } 3100 #endif 3101 3102 /* 3103 * Give an error message. To be used when the screen hasn't been initialized 3104 * yet. When stderr can't be used, collect error messages until the GUI has 3105 * started and they can be displayed in a message box. 3106 */ 3107 void 3108 mch_errmsg(char *str) 3109 { 3110 #if !defined(MSWIN) || defined(FEAT_GUI_MSWIN) 3111 int len; 3112 #endif 3113 3114 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL) 3115 // On Unix use stderr if it's a tty. 3116 // When not going to start the GUI also use stderr. 3117 // On Mac, when started from Finder, stderr is the console. 3118 if ( 3119 # ifdef UNIX 3120 # ifdef MACOS_X 3121 (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0) 3122 # else 3123 isatty(2) 3124 # endif 3125 # ifdef FEAT_GUI 3126 || 3127 # endif 3128 # endif 3129 # ifdef FEAT_GUI 3130 !(gui.in_use || gui.starting) 3131 # endif 3132 ) 3133 { 3134 fprintf(stderr, "%s", str); 3135 return; 3136 } 3137 #endif 3138 3139 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3140 # ifdef VIMDLL 3141 if (!(gui.in_use || gui.starting)) 3142 # endif 3143 { 3144 mch_errmsg_c(str); 3145 return; 3146 } 3147 #endif 3148 3149 #if !defined(MSWIN) || defined(FEAT_GUI_MSWIN) 3150 // avoid a delay for a message that isn't there 3151 emsg_on_display = FALSE; 3152 3153 len = (int)STRLEN(str) + 1; 3154 if (error_ga.ga_growsize == 0) 3155 { 3156 error_ga.ga_growsize = 80; 3157 error_ga.ga_itemsize = 1; 3158 } 3159 if (ga_grow(&error_ga, len) == OK) 3160 { 3161 mch_memmove((char_u *)error_ga.ga_data + error_ga.ga_len, 3162 (char_u *)str, len); 3163 # ifdef UNIX 3164 // remove CR characters, they are displayed 3165 { 3166 char_u *p; 3167 3168 p = (char_u *)error_ga.ga_data + error_ga.ga_len; 3169 for (;;) 3170 { 3171 p = vim_strchr(p, '\r'); 3172 if (p == NULL) 3173 break; 3174 *p = ' '; 3175 } 3176 } 3177 # endif 3178 --len; // don't count the NUL at the end 3179 error_ga.ga_len += len; 3180 } 3181 #endif 3182 } 3183 3184 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3185 static void 3186 mch_msg_c(char *str) 3187 { 3188 int len = (int)STRLEN(str); 3189 DWORD nwrite = 0; 3190 DWORD mode; 3191 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); 3192 3193 3194 if (GetConsoleMode(h, &mode) && enc_codepage >= 0 3195 && (int)GetConsoleCP() != enc_codepage) 3196 { 3197 WCHAR *w = enc_to_utf16((char_u *)str, &len); 3198 3199 WriteConsoleW(h, w, len, &nwrite, NULL); 3200 vim_free(w); 3201 } 3202 else 3203 { 3204 printf("%s", str); 3205 } 3206 } 3207 #endif 3208 3209 /* 3210 * Give a message. To be used when the screen hasn't been initialized yet. 3211 * When there is no tty, collect messages until the GUI has started and they 3212 * can be displayed in a message box. 3213 */ 3214 void 3215 mch_msg(char *str) 3216 { 3217 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL) 3218 // On Unix use stdout if we have a tty. This allows "vim -h | more" and 3219 // uses mch_errmsg() when started from the desktop. 3220 // When not going to start the GUI also use stdout. 3221 // On Mac, when started from Finder, stderr is the console. 3222 if ( 3223 # ifdef UNIX 3224 # ifdef MACOS_X 3225 (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0) 3226 # else 3227 isatty(2) 3228 # endif 3229 # ifdef FEAT_GUI 3230 || 3231 # endif 3232 # endif 3233 # ifdef FEAT_GUI 3234 !(gui.in_use || gui.starting) 3235 # endif 3236 ) 3237 { 3238 printf("%s", str); 3239 return; 3240 } 3241 #endif 3242 3243 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3244 # ifdef VIMDLL 3245 if (!(gui.in_use || gui.starting)) 3246 # endif 3247 { 3248 mch_msg_c(str); 3249 return; 3250 } 3251 #endif 3252 #if !defined(MSWIN) || defined(FEAT_GUI_MSWIN) 3253 mch_errmsg(str); 3254 #endif 3255 } 3256 #endif // USE_MCH_ERRMSG 3257 3258 /* 3259 * Put a character on the screen at the current message position and advance 3260 * to the next position. Only for printable ASCII! 3261 */ 3262 static void 3263 msg_screen_putchar(int c, int attr) 3264 { 3265 msg_didout = TRUE; // remember that line is not empty 3266 screen_putchar(c, msg_row, msg_col, attr); 3267 #ifdef FEAT_RIGHTLEFT 3268 if (cmdmsg_rl) 3269 { 3270 if (--msg_col == 0) 3271 { 3272 msg_col = Columns; 3273 ++msg_row; 3274 } 3275 } 3276 else 3277 #endif 3278 { 3279 if (++msg_col >= Columns) 3280 { 3281 msg_col = 0; 3282 ++msg_row; 3283 } 3284 } 3285 } 3286 3287 static void 3288 msg_moremsg(int full) 3289 { 3290 int attr; 3291 char_u *s = (char_u *)_("-- More --"); 3292 3293 attr = HL_ATTR(HLF_M); 3294 screen_puts(s, (int)Rows - 1, 0, attr); 3295 if (full) 3296 screen_puts((char_u *) 3297 _(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "), 3298 (int)Rows - 1, vim_strsize(s), attr); 3299 } 3300 3301 /* 3302 * Repeat the message for the current mode: ASKMORE, EXTERNCMD, CONFIRM or 3303 * exmode_active. 3304 */ 3305 void 3306 repeat_message(void) 3307 { 3308 if (State == ASKMORE) 3309 { 3310 msg_moremsg(TRUE); // display --more-- message again 3311 msg_row = Rows - 1; 3312 } 3313 #ifdef FEAT_CON_DIALOG 3314 else if (State == CONFIRM) 3315 { 3316 display_confirm_msg(); // display ":confirm" message again 3317 msg_row = Rows - 1; 3318 } 3319 #endif 3320 else if (State == EXTERNCMD) 3321 { 3322 windgoto(msg_row, msg_col); // put cursor back 3323 } 3324 else if (State == HITRETURN || State == SETWSIZE) 3325 { 3326 if (msg_row == Rows - 1) 3327 { 3328 // Avoid drawing the "hit-enter" prompt below the previous one, 3329 // overwrite it. Esp. useful when regaining focus and a 3330 // FocusGained autocmd exists but didn't draw anything. 3331 msg_didout = FALSE; 3332 msg_col = 0; 3333 msg_clr_eos(); 3334 } 3335 hit_return_msg(); 3336 msg_row = Rows - 1; 3337 } 3338 } 3339 3340 /* 3341 * msg_check_screen - check if the screen is initialized. 3342 * Also check msg_row and msg_col, if they are too big it may cause a crash. 3343 * While starting the GUI the terminal codes will be set for the GUI, but the 3344 * output goes to the terminal. Don't use the terminal codes then. 3345 */ 3346 static int 3347 msg_check_screen(void) 3348 { 3349 if (!full_screen || !screen_valid(FALSE)) 3350 return FALSE; 3351 3352 if (msg_row >= Rows) 3353 msg_row = Rows - 1; 3354 if (msg_col >= Columns) 3355 msg_col = Columns - 1; 3356 return TRUE; 3357 } 3358 3359 /* 3360 * Clear from current message position to end of screen. 3361 * Skip this when ":silent" was used, no need to clear for redirection. 3362 */ 3363 void 3364 msg_clr_eos(void) 3365 { 3366 if (msg_silent == 0) 3367 msg_clr_eos_force(); 3368 } 3369 3370 /* 3371 * Clear from current message position to end of screen. 3372 * Note: msg_col is not updated, so we remember the end of the message 3373 * for msg_check(). 3374 */ 3375 void 3376 msg_clr_eos_force(void) 3377 { 3378 if (msg_use_printf()) 3379 { 3380 if (full_screen) // only when termcap codes are valid 3381 { 3382 if (*T_CD) 3383 out_str(T_CD); // clear to end of display 3384 else if (*T_CE) 3385 out_str(T_CE); // clear to end of line 3386 } 3387 } 3388 else 3389 { 3390 #ifdef FEAT_RIGHTLEFT 3391 if (cmdmsg_rl) 3392 { 3393 screen_fill(msg_row, msg_row + 1, 0, msg_col + 1, ' ', ' ', 0); 3394 screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 3395 } 3396 else 3397 #endif 3398 { 3399 screen_fill(msg_row, msg_row + 1, msg_col, (int)Columns, 3400 ' ', ' ', 0); 3401 screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 3402 } 3403 } 3404 } 3405 3406 /* 3407 * Clear the command line. 3408 */ 3409 void 3410 msg_clr_cmdline(void) 3411 { 3412 msg_row = cmdline_row; 3413 msg_col = 0; 3414 msg_clr_eos_force(); 3415 } 3416 3417 /* 3418 * end putting a message on the screen 3419 * call wait_return if the message does not fit in the available space 3420 * return TRUE if wait_return not called. 3421 */ 3422 int 3423 msg_end(void) 3424 { 3425 /* 3426 * If the string is larger than the window, 3427 * or the ruler option is set and we run into it, 3428 * we have to redraw the window. 3429 * Do not do this if we are abandoning the file or editing the command line. 3430 */ 3431 if (!exiting && need_wait_return && !(State & CMDLINE)) 3432 { 3433 wait_return(FALSE); 3434 return FALSE; 3435 } 3436 out_flush(); 3437 return TRUE; 3438 } 3439 3440 /* 3441 * If the written message runs into the shown command or ruler, we have to 3442 * wait for hit-return and redraw the window later. 3443 */ 3444 void 3445 msg_check(void) 3446 { 3447 if (msg_row == Rows - 1 && msg_col >= sc_col) 3448 { 3449 need_wait_return = TRUE; 3450 redraw_cmdline = TRUE; 3451 } 3452 } 3453 3454 /* 3455 * May write a string to the redirection file. 3456 * When "maxlen" is -1 write the whole string, otherwise up to "maxlen" bytes. 3457 */ 3458 static void 3459 redir_write(char_u *str, int maxlen) 3460 { 3461 char_u *s = str; 3462 static int cur_col = 0; 3463 3464 // Don't do anything for displaying prompts and the like. 3465 if (redir_off) 3466 return; 3467 3468 // If 'verbosefile' is set prepare for writing in that file. 3469 if (*p_vfile != NUL && verbose_fd == NULL) 3470 verbose_open(); 3471 3472 if (redirecting()) 3473 { 3474 // If the string doesn't start with CR or NL, go to msg_col 3475 if (*s != '\n' && *s != '\r') 3476 { 3477 while (cur_col < msg_col) 3478 { 3479 #ifdef FEAT_EVAL 3480 if (redir_execute) 3481 execute_redir_str((char_u *)" ", -1); 3482 else if (redir_reg) 3483 write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE); 3484 else if (redir_vname) 3485 var_redir_str((char_u *)" ", -1); 3486 else 3487 #endif 3488 if (redir_fd != NULL) 3489 fputs(" ", redir_fd); 3490 if (verbose_fd != NULL) 3491 fputs(" ", verbose_fd); 3492 ++cur_col; 3493 } 3494 } 3495 3496 #ifdef FEAT_EVAL 3497 if (redir_execute) 3498 execute_redir_str(s, maxlen); 3499 else if (redir_reg) 3500 write_reg_contents(redir_reg, s, maxlen, TRUE); 3501 else if (redir_vname) 3502 var_redir_str(s, maxlen); 3503 #endif 3504 3505 // Write and adjust the current column. 3506 while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) 3507 { 3508 #ifdef FEAT_EVAL 3509 if (!redir_reg && !redir_vname && !redir_execute) 3510 #endif 3511 if (redir_fd != NULL) 3512 putc(*s, redir_fd); 3513 if (verbose_fd != NULL) 3514 putc(*s, verbose_fd); 3515 if (*s == '\r' || *s == '\n') 3516 cur_col = 0; 3517 else if (*s == '\t') 3518 cur_col += (8 - cur_col % 8); 3519 else 3520 ++cur_col; 3521 ++s; 3522 } 3523 3524 if (msg_silent != 0) // should update msg_col 3525 msg_col = cur_col; 3526 } 3527 } 3528 3529 int 3530 redirecting(void) 3531 { 3532 return redir_fd != NULL || *p_vfile != NUL 3533 #ifdef FEAT_EVAL 3534 || redir_reg || redir_vname || redir_execute 3535 #endif 3536 ; 3537 } 3538 3539 /* 3540 * Before giving verbose message. 3541 * Must always be called paired with verbose_leave()! 3542 */ 3543 void 3544 verbose_enter(void) 3545 { 3546 if (*p_vfile != NUL) 3547 ++msg_silent; 3548 } 3549 3550 /* 3551 * After giving verbose message. 3552 * Must always be called paired with verbose_enter()! 3553 */ 3554 void 3555 verbose_leave(void) 3556 { 3557 if (*p_vfile != NUL) 3558 if (--msg_silent < 0) 3559 msg_silent = 0; 3560 } 3561 3562 /* 3563 * Like verbose_enter() and set msg_scroll when displaying the message. 3564 */ 3565 void 3566 verbose_enter_scroll(void) 3567 { 3568 if (*p_vfile != NUL) 3569 ++msg_silent; 3570 else 3571 // always scroll up, don't overwrite 3572 msg_scroll = TRUE; 3573 } 3574 3575 /* 3576 * Like verbose_leave() and set cmdline_row when displaying the message. 3577 */ 3578 void 3579 verbose_leave_scroll(void) 3580 { 3581 if (*p_vfile != NUL) 3582 { 3583 if (--msg_silent < 0) 3584 msg_silent = 0; 3585 } 3586 else 3587 cmdline_row = msg_row; 3588 } 3589 3590 /* 3591 * Called when 'verbosefile' is set: stop writing to the file. 3592 */ 3593 void 3594 verbose_stop(void) 3595 { 3596 if (verbose_fd != NULL) 3597 { 3598 fclose(verbose_fd); 3599 verbose_fd = NULL; 3600 } 3601 verbose_did_open = FALSE; 3602 } 3603 3604 /* 3605 * Open the file 'verbosefile'. 3606 * Return FAIL or OK. 3607 */ 3608 int 3609 verbose_open(void) 3610 { 3611 if (verbose_fd == NULL && !verbose_did_open) 3612 { 3613 // Only give the error message once. 3614 verbose_did_open = TRUE; 3615 3616 verbose_fd = mch_fopen((char *)p_vfile, "a"); 3617 if (verbose_fd == NULL) 3618 { 3619 semsg(_(e_notopen), p_vfile); 3620 return FAIL; 3621 } 3622 } 3623 return OK; 3624 } 3625 3626 /* 3627 * Give a warning message (for searching). 3628 * Use 'w' highlighting and may repeat the message after redrawing 3629 */ 3630 void 3631 give_warning(char_u *message, int hl) 3632 { 3633 give_warning_with_source(message, hl, FALSE); 3634 } 3635 3636 void 3637 give_warning_with_source(char_u *message, int hl, int with_source) 3638 { 3639 // Don't do this for ":silent". 3640 if (msg_silent != 0) 3641 return; 3642 3643 // Don't want a hit-enter prompt here. 3644 ++no_wait_return; 3645 3646 #ifdef FEAT_EVAL 3647 set_vim_var_string(VV_WARNINGMSG, message, -1); 3648 #endif 3649 VIM_CLEAR(keep_msg); 3650 if (hl) 3651 keep_msg_attr = HL_ATTR(HLF_W); 3652 else 3653 keep_msg_attr = 0; 3654 3655 if (with_source) 3656 { 3657 // Do what msg() does, but with a column offset if the warning should 3658 // be after the mode message. 3659 msg_start(); 3660 msg_source(HL_ATTR(HLF_W)); 3661 msg_puts(" "); 3662 msg_puts_attr((char *)message, HL_ATTR(HLF_W) | MSG_HIST); 3663 msg_clr_eos(); 3664 (void)msg_end(); 3665 } 3666 else if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0) 3667 set_keep_msg(message, keep_msg_attr); 3668 3669 msg_didout = FALSE; // overwrite this message 3670 msg_nowait = TRUE; // don't wait for this message 3671 msg_col = 0; 3672 3673 --no_wait_return; 3674 } 3675 3676 #if defined(FEAT_EVAL) || defined(PROTO) 3677 void 3678 give_warning2(char_u *message, char_u *a1, int hl) 3679 { 3680 if (IObuff == NULL) 3681 { 3682 // Very early in initialisation and already something wrong, just give 3683 // the raw message so the user at least gets a hint. 3684 give_warning((char_u *)message, hl); 3685 } 3686 else 3687 { 3688 vim_snprintf((char *)IObuff, IOSIZE, (char *)message, a1); 3689 give_warning(IObuff, hl); 3690 } 3691 } 3692 #endif 3693 3694 /* 3695 * Advance msg cursor to column "col". 3696 */ 3697 void 3698 msg_advance(int col) 3699 { 3700 if (msg_silent != 0) // nothing to advance to 3701 { 3702 msg_col = col; // for redirection, may fill it up later 3703 return; 3704 } 3705 if (col >= Columns) // not enough room 3706 col = Columns - 1; 3707 #ifdef FEAT_RIGHTLEFT 3708 if (cmdmsg_rl) 3709 while (msg_col > Columns - col) 3710 msg_putchar(' '); 3711 else 3712 #endif 3713 while (msg_col < col) 3714 msg_putchar(' '); 3715 } 3716 3717 #if defined(FEAT_CON_DIALOG) || defined(PROTO) 3718 /* 3719 * Used for "confirm()" function, and the :confirm command prefix. 3720 * Versions which haven't got flexible dialogs yet, and console 3721 * versions, get this generic handler which uses the command line. 3722 * 3723 * type = one of: 3724 * VIM_QUESTION, VIM_INFO, VIM_WARNING, VIM_ERROR or VIM_GENERIC 3725 * title = title string (can be NULL for default) 3726 * (neither used in console dialogs at the moment) 3727 * 3728 * Format of the "buttons" string: 3729 * "Button1Name\nButton2Name\nButton3Name" 3730 * The first button should normally be the default/accept 3731 * The second button should be the 'Cancel' button 3732 * Other buttons- use your imagination! 3733 * A '&' in a button name becomes a shortcut, so each '&' should be before a 3734 * different letter. 3735 */ 3736 int 3737 do_dialog( 3738 int type UNUSED, 3739 char_u *title UNUSED, 3740 char_u *message, 3741 char_u *buttons, 3742 int dfltbutton, 3743 char_u *textfield UNUSED, // IObuff for inputdialog(), NULL 3744 // otherwise 3745 int ex_cmd) // when TRUE pressing : accepts default and starts 3746 // Ex command 3747 { 3748 int oldState; 3749 int retval = 0; 3750 char_u *hotkeys; 3751 int c; 3752 int i; 3753 tmode_T save_tmode; 3754 3755 #ifndef NO_CONSOLE 3756 // Don't output anything in silent mode ("ex -s") 3757 if (silent_mode) 3758 return dfltbutton; // return default option 3759 #endif 3760 3761 #ifdef FEAT_GUI_DIALOG 3762 // When GUI is running and 'c' not in 'guioptions', use the GUI dialog 3763 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL) 3764 { 3765 c = gui_mch_dialog(type, title, message, buttons, dfltbutton, 3766 textfield, ex_cmd); 3767 // avoid a hit-enter prompt without clearing the cmdline 3768 need_wait_return = FALSE; 3769 emsg_on_display = FALSE; 3770 cmdline_row = msg_row; 3771 3772 // Flush output to avoid that further messages and redrawing is done 3773 // in the wrong order. 3774 out_flush(); 3775 gui_mch_update(); 3776 3777 return c; 3778 } 3779 #endif 3780 3781 oldState = State; 3782 State = CONFIRM; 3783 setmouse(); 3784 3785 // Ensure raw mode here. 3786 save_tmode = cur_tmode; 3787 settmode(TMODE_RAW); 3788 3789 /* 3790 * Since we wait for a keypress, don't make the 3791 * user press RETURN as well afterwards. 3792 */ 3793 ++no_wait_return; 3794 hotkeys = msg_show_console_dialog(message, buttons, dfltbutton); 3795 3796 if (hotkeys != NULL) 3797 { 3798 for (;;) 3799 { 3800 // Get a typed character directly from the user. 3801 c = get_keystroke(); 3802 switch (c) 3803 { 3804 case CAR: // User accepts default option 3805 case NL: 3806 retval = dfltbutton; 3807 break; 3808 case Ctrl_C: // User aborts/cancels 3809 case ESC: 3810 retval = 0; 3811 break; 3812 default: // Could be a hotkey? 3813 if (c < 0) // special keys are ignored here 3814 continue; 3815 if (c == ':' && ex_cmd) 3816 { 3817 retval = dfltbutton; 3818 ins_char_typebuf(':', 0); 3819 break; 3820 } 3821 3822 // Make the character lowercase, as chars in "hotkeys" are. 3823 c = MB_TOLOWER(c); 3824 retval = 1; 3825 for (i = 0; hotkeys[i]; ++i) 3826 { 3827 if (has_mbyte) 3828 { 3829 if ((*mb_ptr2char)(hotkeys + i) == c) 3830 break; 3831 i += (*mb_ptr2len)(hotkeys + i) - 1; 3832 } 3833 else 3834 if (hotkeys[i] == c) 3835 break; 3836 ++retval; 3837 } 3838 if (hotkeys[i]) 3839 break; 3840 // No hotkey match, so keep waiting 3841 continue; 3842 } 3843 break; 3844 } 3845 3846 vim_free(hotkeys); 3847 } 3848 3849 settmode(save_tmode); 3850 State = oldState; 3851 setmouse(); 3852 --no_wait_return; 3853 msg_end_prompt(); 3854 3855 return retval; 3856 } 3857 3858 /* 3859 * Copy one character from "*from" to "*to", taking care of multi-byte 3860 * characters. Return the length of the character in bytes. 3861 */ 3862 static int 3863 copy_char( 3864 char_u *from, 3865 char_u *to, 3866 int lowercase) // make character lower case 3867 { 3868 int len; 3869 int c; 3870 3871 if (has_mbyte) 3872 { 3873 if (lowercase) 3874 { 3875 c = MB_TOLOWER((*mb_ptr2char)(from)); 3876 return (*mb_char2bytes)(c, to); 3877 } 3878 else 3879 { 3880 len = (*mb_ptr2len)(from); 3881 mch_memmove(to, from, (size_t)len); 3882 return len; 3883 } 3884 } 3885 else 3886 { 3887 if (lowercase) 3888 *to = (char_u)TOLOWER_LOC(*from); 3889 else 3890 *to = *from; 3891 return 1; 3892 } 3893 } 3894 3895 /* 3896 * Format the dialog string, and display it at the bottom of 3897 * the screen. Return a string of hotkey chars (if defined) for 3898 * each 'button'. If a button has no hotkey defined, the first character of 3899 * the button is used. 3900 * The hotkeys can be multi-byte characters, but without combining chars. 3901 * 3902 * Returns an allocated string with hotkeys, or NULL for error. 3903 */ 3904 static char_u * 3905 msg_show_console_dialog( 3906 char_u *message, 3907 char_u *buttons, 3908 int dfltbutton) 3909 { 3910 int len = 0; 3911 #define HOTK_LEN (has_mbyte ? MB_MAXBYTES : 1) 3912 int lenhotkey = HOTK_LEN; // count first button 3913 char_u *hotk = NULL; 3914 char_u *msgp = NULL; 3915 char_u *hotkp = NULL; 3916 char_u *r; 3917 int copy; 3918 #define HAS_HOTKEY_LEN 30 3919 char_u has_hotkey[HAS_HOTKEY_LEN]; 3920 int first_hotkey = FALSE; // first char of button is hotkey 3921 int idx; 3922 3923 has_hotkey[0] = FALSE; 3924 3925 /* 3926 * First loop: compute the size of memory to allocate. 3927 * Second loop: copy to the allocated memory. 3928 */ 3929 for (copy = 0; copy <= 1; ++copy) 3930 { 3931 r = buttons; 3932 idx = 0; 3933 while (*r) 3934 { 3935 if (*r == DLG_BUTTON_SEP) 3936 { 3937 if (copy) 3938 { 3939 *msgp++ = ','; 3940 *msgp++ = ' '; // '\n' -> ', ' 3941 3942 // advance to next hotkey and set default hotkey 3943 if (has_mbyte) 3944 hotkp += STRLEN(hotkp); 3945 else 3946 ++hotkp; 3947 hotkp[copy_char(r + 1, hotkp, TRUE)] = NUL; 3948 if (dfltbutton) 3949 --dfltbutton; 3950 3951 // If no hotkey is specified first char is used. 3952 if (idx < HAS_HOTKEY_LEN - 1 && !has_hotkey[++idx]) 3953 first_hotkey = TRUE; 3954 } 3955 else 3956 { 3957 len += 3; // '\n' -> ', '; 'x' -> '(x)' 3958 lenhotkey += HOTK_LEN; // each button needs a hotkey 3959 if (idx < HAS_HOTKEY_LEN - 1) 3960 has_hotkey[++idx] = FALSE; 3961 } 3962 } 3963 else if (*r == DLG_HOTKEY_CHAR || first_hotkey) 3964 { 3965 if (*r == DLG_HOTKEY_CHAR) 3966 ++r; 3967 first_hotkey = FALSE; 3968 if (copy) 3969 { 3970 if (*r == DLG_HOTKEY_CHAR) // '&&a' -> '&a' 3971 *msgp++ = *r; 3972 else 3973 { 3974 // '&a' -> '[a]' 3975 *msgp++ = (dfltbutton == 1) ? '[' : '('; 3976 msgp += copy_char(r, msgp, FALSE); 3977 *msgp++ = (dfltbutton == 1) ? ']' : ')'; 3978 3979 // redefine hotkey 3980 hotkp[copy_char(r, hotkp, TRUE)] = NUL; 3981 } 3982 } 3983 else 3984 { 3985 ++len; // '&a' -> '[a]' 3986 if (idx < HAS_HOTKEY_LEN - 1) 3987 has_hotkey[idx] = TRUE; 3988 } 3989 } 3990 else 3991 { 3992 // everything else copy literally 3993 if (copy) 3994 msgp += copy_char(r, msgp, FALSE); 3995 } 3996 3997 // advance to the next character 3998 MB_PTR_ADV(r); 3999 } 4000 4001 if (copy) 4002 { 4003 *msgp++ = ':'; 4004 *msgp++ = ' '; 4005 *msgp = NUL; 4006 } 4007 else 4008 { 4009 len += (int)(STRLEN(message) 4010 + 2 // for the NL's 4011 + STRLEN(buttons) 4012 + 3); // for the ": " and NUL 4013 lenhotkey++; // for the NUL 4014 4015 // If no hotkey is specified first char is used. 4016 if (!has_hotkey[0]) 4017 { 4018 first_hotkey = TRUE; 4019 len += 2; // "x" -> "[x]" 4020 } 4021 4022 /* 4023 * Now allocate and load the strings 4024 */ 4025 vim_free(confirm_msg); 4026 confirm_msg = alloc(len); 4027 if (confirm_msg == NULL) 4028 return NULL; 4029 *confirm_msg = NUL; 4030 hotk = alloc(lenhotkey); 4031 if (hotk == NULL) 4032 return NULL; 4033 4034 *confirm_msg = '\n'; 4035 STRCPY(confirm_msg + 1, message); 4036 4037 msgp = confirm_msg + 1 + STRLEN(message); 4038 hotkp = hotk; 4039 4040 // Define first default hotkey. Keep the hotkey string NUL 4041 // terminated to avoid reading past the end. 4042 hotkp[copy_char(buttons, hotkp, TRUE)] = NUL; 4043 4044 // Remember where the choices start, displaying starts here when 4045 // "hotkp" typed at the more prompt. 4046 confirm_msg_tail = msgp; 4047 *msgp++ = '\n'; 4048 } 4049 } 4050 4051 display_confirm_msg(); 4052 return hotk; 4053 } 4054 4055 /* 4056 * Display the ":confirm" message. Also called when screen resized. 4057 */ 4058 static void 4059 display_confirm_msg(void) 4060 { 4061 // avoid that 'q' at the more prompt truncates the message here 4062 ++confirm_msg_used; 4063 if (confirm_msg != NULL) 4064 msg_puts_attr((char *)confirm_msg, HL_ATTR(HLF_M)); 4065 --confirm_msg_used; 4066 } 4067 4068 #endif // FEAT_CON_DIALOG 4069 4070 #if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG) 4071 4072 int 4073 vim_dialog_yesno( 4074 int type, 4075 char_u *title, 4076 char_u *message, 4077 int dflt) 4078 { 4079 if (do_dialog(type, 4080 title == NULL ? (char_u *)_("Question") : title, 4081 message, 4082 (char_u *)_("&Yes\n&No"), dflt, NULL, FALSE) == 1) 4083 return VIM_YES; 4084 return VIM_NO; 4085 } 4086 4087 int 4088 vim_dialog_yesnocancel( 4089 int type, 4090 char_u *title, 4091 char_u *message, 4092 int dflt) 4093 { 4094 switch (do_dialog(type, 4095 title == NULL ? (char_u *)_("Question") : title, 4096 message, 4097 (char_u *)_("&Yes\n&No\n&Cancel"), dflt, NULL, FALSE)) 4098 { 4099 case 1: return VIM_YES; 4100 case 2: return VIM_NO; 4101 } 4102 return VIM_CANCEL; 4103 } 4104 4105 int 4106 vim_dialog_yesnoallcancel( 4107 int type, 4108 char_u *title, 4109 char_u *message, 4110 int dflt) 4111 { 4112 switch (do_dialog(type, 4113 title == NULL ? (char_u *)"Question" : title, 4114 message, 4115 (char_u *)_("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"), 4116 dflt, NULL, FALSE)) 4117 { 4118 case 1: return VIM_YES; 4119 case 2: return VIM_NO; 4120 case 3: return VIM_ALL; 4121 case 4: return VIM_DISCARDALL; 4122 } 4123 return VIM_CANCEL; 4124 } 4125 4126 #endif // FEAT_GUI_DIALOG || FEAT_CON_DIALOG 4127