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 l; 1845 char_u buf[MB_MAXBYTES + 1]; 1846 1847 if (curwin->w_p_list) 1848 list = TRUE; 1849 1850 if (list) 1851 { 1852 // find start of trailing whitespace 1853 if (curwin->w_lcs_chars.trail) 1854 { 1855 trail = s + STRLEN(s); 1856 while (trail > s && VIM_ISWHITE(trail[-1])) 1857 --trail; 1858 } 1859 // find end of leading whitespace 1860 if (curwin->w_lcs_chars.lead) 1861 { 1862 lead = s; 1863 while (VIM_ISWHITE(lead[0])) 1864 lead++; 1865 // in a line full of spaces all of them are treated as trailing 1866 if (*lead == NUL) 1867 lead = NULL; 1868 } 1869 } 1870 1871 // output a space for an empty line, otherwise the line will be 1872 // overwritten 1873 if (*s == NUL && !(list && curwin->w_lcs_chars.eol != NUL)) 1874 msg_putchar(' '); 1875 1876 while (!got_int) 1877 { 1878 if (n_extra > 0) 1879 { 1880 --n_extra; 1881 if (n_extra == 0 && c_final) 1882 c = c_final; 1883 else if (c_extra) 1884 c = c_extra; 1885 else 1886 c = *p_extra++; 1887 } 1888 else if (has_mbyte && (l = (*mb_ptr2len)(s)) > 1) 1889 { 1890 col += (*mb_ptr2cells)(s); 1891 if (l >= MB_MAXBYTES) 1892 { 1893 STRCPY(buf, "?"); 1894 } 1895 else if (curwin->w_lcs_chars.nbsp != NUL && list 1896 && (mb_ptr2char(s) == 160 1897 || mb_ptr2char(s) == 0x202f)) 1898 { 1899 mb_char2bytes(curwin->w_lcs_chars.nbsp, buf); 1900 buf[(*mb_ptr2len)(buf)] = NUL; 1901 } 1902 else 1903 { 1904 mch_memmove(buf, s, (size_t)l); 1905 buf[l] = NUL; 1906 } 1907 msg_puts((char *)buf); 1908 s += l; 1909 continue; 1910 } 1911 else 1912 { 1913 attr = 0; 1914 c = *s++; 1915 if (c == TAB && (!list || curwin->w_lcs_chars.tab1)) 1916 { 1917 // tab amount depends on current column 1918 #ifdef FEAT_VARTABS 1919 n_extra = tabstop_padding(col, curbuf->b_p_ts, 1920 curbuf->b_p_vts_array) - 1; 1921 #else 1922 n_extra = curbuf->b_p_ts - col % curbuf->b_p_ts - 1; 1923 #endif 1924 if (!list) 1925 { 1926 c = ' '; 1927 c_extra = ' '; 1928 c_final = NUL; 1929 } 1930 else 1931 { 1932 c = (n_extra == 0 && curwin->w_lcs_chars.tab3) 1933 ? curwin->w_lcs_chars.tab3 1934 : curwin->w_lcs_chars.tab1; 1935 c_extra = curwin->w_lcs_chars.tab2; 1936 c_final = curwin->w_lcs_chars.tab3; 1937 attr = HL_ATTR(HLF_8); 1938 } 1939 } 1940 else if (c == 160 && list && curwin->w_lcs_chars.nbsp != NUL) 1941 { 1942 c = curwin->w_lcs_chars.nbsp; 1943 attr = HL_ATTR(HLF_8); 1944 } 1945 else if (c == NUL && list && curwin->w_lcs_chars.eol != NUL) 1946 { 1947 p_extra = (char_u *)""; 1948 c_extra = NUL; 1949 c_final = NUL; 1950 n_extra = 1; 1951 c = curwin->w_lcs_chars.eol; 1952 attr = HL_ATTR(HLF_AT); 1953 --s; 1954 } 1955 else if (c != NUL && (n = byte2cells(c)) > 1) 1956 { 1957 n_extra = n - 1; 1958 p_extra = transchar_byte(c); 1959 c_extra = NUL; 1960 c_final = NUL; 1961 c = *p_extra++; 1962 // Use special coloring to be able to distinguish <hex> from 1963 // the same in plain text. 1964 attr = HL_ATTR(HLF_8); 1965 } 1966 else if (c == ' ' && lead != NULL && s <= lead) 1967 { 1968 c = curwin->w_lcs_chars.lead; 1969 attr = HL_ATTR(HLF_8); 1970 } 1971 else if (c == ' ' && trail != NULL && s > trail) 1972 { 1973 c = curwin->w_lcs_chars.trail; 1974 attr = HL_ATTR(HLF_8); 1975 } 1976 else if (c == ' ' && list && curwin->w_lcs_chars.space != NUL) 1977 { 1978 c = curwin->w_lcs_chars.space; 1979 attr = HL_ATTR(HLF_8); 1980 } 1981 } 1982 1983 if (c == NUL) 1984 break; 1985 1986 msg_putchar_attr(c, attr); 1987 col++; 1988 } 1989 msg_clr_eos(); 1990 } 1991 1992 /* 1993 * Use screen_puts() to output one multi-byte character. 1994 * Return the pointer "s" advanced to the next character. 1995 */ 1996 static char_u * 1997 screen_puts_mbyte(char_u *s, int l, int attr) 1998 { 1999 int cw; 2000 2001 msg_didout = TRUE; // remember that line is not empty 2002 cw = (*mb_ptr2cells)(s); 2003 if (cw > 1 && ( 2004 #ifdef FEAT_RIGHTLEFT 2005 cmdmsg_rl ? msg_col <= 1 : 2006 #endif 2007 msg_col == Columns - 1)) 2008 { 2009 // Doesn't fit, print a highlighted '>' to fill it up. 2010 msg_screen_putchar('>', HL_ATTR(HLF_AT)); 2011 return s; 2012 } 2013 2014 screen_puts_len(s, l, msg_row, msg_col, attr); 2015 #ifdef FEAT_RIGHTLEFT 2016 if (cmdmsg_rl) 2017 { 2018 msg_col -= cw; 2019 if (msg_col == 0) 2020 { 2021 msg_col = Columns; 2022 ++msg_row; 2023 } 2024 } 2025 else 2026 #endif 2027 { 2028 msg_col += cw; 2029 if (msg_col >= Columns) 2030 { 2031 msg_col = 0; 2032 ++msg_row; 2033 } 2034 } 2035 return s + l; 2036 } 2037 2038 /* 2039 * Output a string to the screen at position msg_row, msg_col. 2040 * Update msg_row and msg_col for the next message. 2041 */ 2042 void 2043 msg_puts(char *s) 2044 { 2045 msg_puts_attr(s, 0); 2046 } 2047 2048 void 2049 msg_puts_title(char *s) 2050 { 2051 msg_puts_attr(s, HL_ATTR(HLF_T)); 2052 } 2053 2054 /* 2055 * Show a message in such a way that it always fits in the line. Cut out a 2056 * part in the middle and replace it with "..." when necessary. 2057 * Does not handle multi-byte characters! 2058 */ 2059 static void 2060 msg_outtrans_long_len_attr(char_u *longstr, int len, int attr) 2061 { 2062 int slen = len; 2063 int room; 2064 2065 room = Columns - msg_col; 2066 if (len > room && room >= 20) 2067 { 2068 slen = (room - 3) / 2; 2069 msg_outtrans_len_attr(longstr, slen, attr); 2070 msg_puts_attr("...", HL_ATTR(HLF_8)); 2071 } 2072 msg_outtrans_len_attr(longstr + len - slen, slen, attr); 2073 } 2074 2075 void 2076 msg_outtrans_long_attr(char_u *longstr, int attr) 2077 { 2078 msg_outtrans_long_len_attr(longstr, (int)STRLEN(longstr), attr); 2079 } 2080 2081 /* 2082 * Basic function for writing a message with highlight attributes. 2083 */ 2084 void 2085 msg_puts_attr(char *s, int attr) 2086 { 2087 msg_puts_attr_len(s, -1, attr); 2088 } 2089 2090 /* 2091 * Like msg_puts_attr(), but with a maximum length "maxlen" (in bytes). 2092 * When "maxlen" is -1 there is no maximum length. 2093 * When "maxlen" is >= 0 the message is not put in the history. 2094 */ 2095 static void 2096 msg_puts_attr_len(char *str, int maxlen, int attr) 2097 { 2098 /* 2099 * If redirection is on, also write to the redirection file. 2100 */ 2101 redir_write((char_u *)str, maxlen); 2102 2103 /* 2104 * Don't print anything when using ":silent cmd". 2105 */ 2106 if (msg_silent != 0) 2107 return; 2108 2109 // if MSG_HIST flag set, add message to history 2110 if ((attr & MSG_HIST) && maxlen < 0) 2111 { 2112 add_msg_hist((char_u *)str, -1, attr); 2113 attr &= ~MSG_HIST; 2114 } 2115 2116 // When writing something to the screen after it has scrolled, requires a 2117 // wait-return prompt later. Needed when scrolling, resetting 2118 // need_wait_return after some prompt, and then outputting something 2119 // without scrolling 2120 // Not needed when only using CR to move the cursor. 2121 if (msg_scrolled != 0 && !msg_scrolled_ign && STRCMP(str, "\r") != 0) 2122 need_wait_return = TRUE; 2123 msg_didany = TRUE; // remember that something was outputted 2124 2125 /* 2126 * If there is no valid screen, use fprintf so we can see error messages. 2127 * If termcap is not active, we may be writing in an alternate console 2128 * window, cursor positioning may not work correctly (window size may be 2129 * different, e.g. for Win32 console) or we just don't know where the 2130 * cursor is. 2131 */ 2132 if (msg_use_printf()) 2133 msg_puts_printf((char_u *)str, maxlen); 2134 else 2135 msg_puts_display((char_u *)str, maxlen, attr, FALSE); 2136 } 2137 2138 /* 2139 * The display part of msg_puts_attr_len(). 2140 * May be called recursively to display scroll-back text. 2141 */ 2142 static void 2143 msg_puts_display( 2144 char_u *str, 2145 int maxlen, 2146 int attr, 2147 int recurse) 2148 { 2149 char_u *s = str; 2150 char_u *t_s = str; // string from "t_s" to "s" is still todo 2151 int t_col = 0; // screen cells todo, 0 when "t_s" not used 2152 int l; 2153 int cw; 2154 char_u *sb_str = str; 2155 int sb_col = msg_col; 2156 int wrap; 2157 int did_last_char; 2158 2159 did_wait_return = FALSE; 2160 while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) 2161 { 2162 /* 2163 * We are at the end of the screen line when: 2164 * - When outputting a newline. 2165 * - When outputting a character in the last column. 2166 */ 2167 if (!recurse && msg_row >= Rows - 1 && (*s == '\n' || ( 2168 #ifdef FEAT_RIGHTLEFT 2169 cmdmsg_rl 2170 ? ( 2171 msg_col <= 1 2172 || (*s == TAB && msg_col <= 7) 2173 || (has_mbyte && (*mb_ptr2cells)(s) > 1 && msg_col <= 2)) 2174 : 2175 #endif 2176 ((*s != '\r' && msg_col + t_col >= Columns - 1) 2177 || (*s == TAB && msg_col + t_col >= ((Columns - 1) & ~7)) 2178 || (has_mbyte && (*mb_ptr2cells)(s) > 1 2179 && msg_col + t_col >= Columns - 2))))) 2180 { 2181 /* 2182 * The screen is scrolled up when at the last row (some terminals 2183 * scroll automatically, some don't. To avoid problems we scroll 2184 * ourselves). 2185 */ 2186 if (t_col > 0) 2187 // output postponed text 2188 t_puts(&t_col, t_s, s, attr); 2189 2190 // When no more prompt and no more room, truncate here 2191 if (msg_no_more && lines_left == 0) 2192 break; 2193 2194 // Scroll the screen up one line. 2195 msg_scroll_up(); 2196 2197 msg_row = Rows - 2; 2198 if (msg_col >= Columns) // can happen after screen resize 2199 msg_col = Columns - 1; 2200 2201 // Display char in last column before showing more-prompt. 2202 if (*s >= ' ' 2203 #ifdef FEAT_RIGHTLEFT 2204 && !cmdmsg_rl 2205 #endif 2206 ) 2207 { 2208 if (has_mbyte) 2209 { 2210 if (enc_utf8 && maxlen >= 0) 2211 // avoid including composing chars after the end 2212 l = utfc_ptr2len_len(s, (int)((str + maxlen) - s)); 2213 else 2214 l = (*mb_ptr2len)(s); 2215 s = screen_puts_mbyte(s, l, attr); 2216 } 2217 else 2218 msg_screen_putchar(*s++, attr); 2219 did_last_char = TRUE; 2220 } 2221 else 2222 did_last_char = FALSE; 2223 2224 if (p_more) 2225 // store text for scrolling back 2226 store_sb_text(&sb_str, s, attr, &sb_col, TRUE); 2227 2228 inc_msg_scrolled(); 2229 need_wait_return = TRUE; // may need wait_return in main() 2230 redraw_cmdline = TRUE; 2231 if (cmdline_row > 0 && !exmode_active) 2232 --cmdline_row; 2233 2234 /* 2235 * If screen is completely filled and 'more' is set then wait 2236 * for a character. 2237 */ 2238 if (lines_left > 0) 2239 --lines_left; 2240 if (p_more && lines_left == 0 && State != HITRETURN 2241 && !msg_no_more && !exmode_active) 2242 { 2243 #ifdef FEAT_CON_DIALOG 2244 if (do_more_prompt(NUL)) 2245 s = confirm_msg_tail; 2246 #else 2247 (void)do_more_prompt(NUL); 2248 #endif 2249 if (quit_more) 2250 return; 2251 } 2252 2253 // When we displayed a char in last column need to check if there 2254 // is still more. 2255 if (did_last_char) 2256 continue; 2257 } 2258 2259 wrap = *s == '\n' 2260 || msg_col + t_col >= Columns 2261 || (has_mbyte && (*mb_ptr2cells)(s) > 1 2262 && msg_col + t_col >= Columns - 1); 2263 if (t_col > 0 && (wrap || *s == '\r' || *s == '\b' 2264 || *s == '\t' || *s == BELL)) 2265 // output any postponed text 2266 t_puts(&t_col, t_s, s, attr); 2267 2268 if (wrap && p_more && !recurse) 2269 // store text for scrolling back 2270 store_sb_text(&sb_str, s, attr, &sb_col, TRUE); 2271 2272 if (*s == '\n') // go to next line 2273 { 2274 msg_didout = FALSE; // remember that line is empty 2275 #ifdef FEAT_RIGHTLEFT 2276 if (cmdmsg_rl) 2277 msg_col = Columns - 1; 2278 else 2279 #endif 2280 msg_col = 0; 2281 if (++msg_row >= Rows) // safety check 2282 msg_row = Rows - 1; 2283 } 2284 else if (*s == '\r') // go to column 0 2285 { 2286 msg_col = 0; 2287 } 2288 else if (*s == '\b') // go to previous char 2289 { 2290 if (msg_col) 2291 --msg_col; 2292 } 2293 else if (*s == TAB) // translate Tab into spaces 2294 { 2295 do 2296 msg_screen_putchar(' ', attr); 2297 while (msg_col & 7); 2298 } 2299 else if (*s == BELL) // beep (from ":sh") 2300 vim_beep(BO_SH); 2301 else 2302 { 2303 if (has_mbyte) 2304 { 2305 cw = (*mb_ptr2cells)(s); 2306 if (enc_utf8 && maxlen >= 0) 2307 // avoid including composing chars after the end 2308 l = utfc_ptr2len_len(s, (int)((str + maxlen) - s)); 2309 else 2310 l = (*mb_ptr2len)(s); 2311 } 2312 else 2313 { 2314 cw = 1; 2315 l = 1; 2316 } 2317 2318 // When drawing from right to left or when a double-wide character 2319 // doesn't fit, draw a single character here. Otherwise collect 2320 // characters and draw them all at once later. 2321 if ( 2322 # ifdef FEAT_RIGHTLEFT 2323 cmdmsg_rl || 2324 # endif 2325 (cw > 1 && msg_col + t_col >= Columns - 1)) 2326 { 2327 if (l > 1) 2328 s = screen_puts_mbyte(s, l, attr) - 1; 2329 else 2330 msg_screen_putchar(*s, attr); 2331 } 2332 else 2333 { 2334 // postpone this character until later 2335 if (t_col == 0) 2336 t_s = s; 2337 t_col += cw; 2338 s += l - 1; 2339 } 2340 } 2341 ++s; 2342 } 2343 2344 // output any postponed text 2345 if (t_col > 0) 2346 t_puts(&t_col, t_s, s, attr); 2347 if (p_more && !recurse) 2348 store_sb_text(&sb_str, s, attr, &sb_col, FALSE); 2349 2350 msg_check(); 2351 } 2352 2353 /* 2354 * Return TRUE when ":filter pattern" was used and "msg" does not match 2355 * "pattern". 2356 */ 2357 int 2358 message_filtered(char_u *msg) 2359 { 2360 int match; 2361 2362 if (cmdmod.cmod_filter_regmatch.regprog == NULL) 2363 return FALSE; 2364 match = vim_regexec(&cmdmod.cmod_filter_regmatch, msg, (colnr_T)0); 2365 return cmdmod.cmod_filter_force ? match : !match; 2366 } 2367 2368 /* 2369 * Scroll the screen up one line for displaying the next message line. 2370 */ 2371 static void 2372 msg_scroll_up(void) 2373 { 2374 #ifdef FEAT_GUI 2375 // Remove the cursor before scrolling, ScreenLines[] is going 2376 // to become invalid. 2377 if (gui.in_use) 2378 gui_undraw_cursor(); 2379 #endif 2380 // scrolling up always works 2381 mch_disable_flush(); 2382 screen_del_lines(0, 0, 1, (int)Rows, TRUE, 0, NULL); 2383 mch_enable_flush(); 2384 2385 if (!can_clear((char_u *)" ")) 2386 { 2387 // Scrolling up doesn't result in the right background. Set the 2388 // background here. It's not efficient, but avoids that we have to do 2389 // it all over the code. 2390 screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 2391 2392 // Also clear the last char of the last but one line if it was not 2393 // cleared before to avoid a scroll-up. 2394 if (ScreenAttrs[LineOffset[Rows - 2] + Columns - 1] == (sattr_T)-1) 2395 screen_fill((int)Rows - 2, (int)Rows - 1, 2396 (int)Columns - 1, (int)Columns, ' ', ' ', 0); 2397 } 2398 } 2399 2400 /* 2401 * Increment "msg_scrolled". 2402 */ 2403 static void 2404 inc_msg_scrolled(void) 2405 { 2406 #ifdef FEAT_EVAL 2407 if (*get_vim_var_str(VV_SCROLLSTART) == NUL) 2408 { 2409 char_u *p = SOURCING_NAME; 2410 char_u *tofree = NULL; 2411 int len; 2412 2413 // v:scrollstart is empty, set it to the script/function name and line 2414 // number 2415 if (p == NULL) 2416 p = (char_u *)_("Unknown"); 2417 else 2418 { 2419 len = (int)STRLEN(p) + 40; 2420 tofree = alloc(len); 2421 if (tofree != NULL) 2422 { 2423 vim_snprintf((char *)tofree, len, _("%s line %ld"), 2424 p, (long)SOURCING_LNUM); 2425 p = tofree; 2426 } 2427 } 2428 set_vim_var_string(VV_SCROLLSTART, p, -1); 2429 vim_free(tofree); 2430 } 2431 #endif 2432 ++msg_scrolled; 2433 if (must_redraw < VALID) 2434 must_redraw = VALID; 2435 } 2436 2437 /* 2438 * To be able to scroll back at the "more" and "hit-enter" prompts we need to 2439 * store the displayed text and remember where screen lines start. 2440 */ 2441 typedef struct msgchunk_S msgchunk_T; 2442 struct msgchunk_S 2443 { 2444 msgchunk_T *sb_next; 2445 msgchunk_T *sb_prev; 2446 char sb_eol; // TRUE when line ends after this text 2447 int sb_msg_col; // column in which text starts 2448 int sb_attr; // text attributes 2449 char_u sb_text[1]; // text to be displayed, actually longer 2450 }; 2451 2452 static msgchunk_T *last_msgchunk = NULL; // last displayed text 2453 2454 static msgchunk_T *msg_sb_start(msgchunk_T *mps); 2455 2456 typedef enum { 2457 SB_CLEAR_NONE = 0, 2458 SB_CLEAR_ALL, 2459 SB_CLEAR_CMDLINE_BUSY, 2460 SB_CLEAR_CMDLINE_DONE 2461 } sb_clear_T; 2462 2463 // When to clear text on next msg. 2464 static sb_clear_T do_clear_sb_text = SB_CLEAR_NONE; 2465 2466 /* 2467 * Store part of a printed message for displaying when scrolling back. 2468 */ 2469 static void 2470 store_sb_text( 2471 char_u **sb_str, // start of string 2472 char_u *s, // just after string 2473 int attr, 2474 int *sb_col, 2475 int finish) // line ends 2476 { 2477 msgchunk_T *mp; 2478 2479 if (do_clear_sb_text == SB_CLEAR_ALL 2480 || do_clear_sb_text == SB_CLEAR_CMDLINE_DONE) 2481 { 2482 clear_sb_text(do_clear_sb_text == SB_CLEAR_ALL); 2483 do_clear_sb_text = SB_CLEAR_NONE; 2484 } 2485 2486 if (s > *sb_str) 2487 { 2488 mp = alloc(sizeof(msgchunk_T) + (s - *sb_str)); 2489 if (mp != NULL) 2490 { 2491 mp->sb_eol = finish; 2492 mp->sb_msg_col = *sb_col; 2493 mp->sb_attr = attr; 2494 vim_strncpy(mp->sb_text, *sb_str, s - *sb_str); 2495 2496 if (last_msgchunk == NULL) 2497 { 2498 last_msgchunk = mp; 2499 mp->sb_prev = NULL; 2500 } 2501 else 2502 { 2503 mp->sb_prev = last_msgchunk; 2504 last_msgchunk->sb_next = mp; 2505 last_msgchunk = mp; 2506 } 2507 mp->sb_next = NULL; 2508 } 2509 } 2510 else if (finish && last_msgchunk != NULL) 2511 last_msgchunk->sb_eol = TRUE; 2512 2513 *sb_str = s; 2514 *sb_col = 0; 2515 } 2516 2517 /* 2518 * Finished showing messages, clear the scroll-back text on the next message. 2519 */ 2520 void 2521 may_clear_sb_text(void) 2522 { 2523 do_clear_sb_text = SB_CLEAR_ALL; 2524 } 2525 2526 /* 2527 * Starting to edit the command line, do not clear messages now. 2528 */ 2529 void 2530 sb_text_start_cmdline(void) 2531 { 2532 do_clear_sb_text = SB_CLEAR_CMDLINE_BUSY; 2533 msg_sb_eol(); 2534 } 2535 2536 /* 2537 * Ending to edit the command line. Clear old lines but the last one later. 2538 */ 2539 void 2540 sb_text_end_cmdline(void) 2541 { 2542 do_clear_sb_text = SB_CLEAR_CMDLINE_DONE; 2543 } 2544 2545 /* 2546 * Clear any text remembered for scrolling back. 2547 * When "all" is FALSE keep the last line. 2548 * Called when redrawing the screen. 2549 */ 2550 void 2551 clear_sb_text(int all) 2552 { 2553 msgchunk_T *mp; 2554 msgchunk_T **lastp; 2555 2556 if (all) 2557 lastp = &last_msgchunk; 2558 else 2559 { 2560 if (last_msgchunk == NULL) 2561 return; 2562 lastp = &last_msgchunk->sb_prev; 2563 } 2564 2565 while (*lastp != NULL) 2566 { 2567 mp = (*lastp)->sb_prev; 2568 vim_free(*lastp); 2569 *lastp = mp; 2570 } 2571 } 2572 2573 /* 2574 * "g<" command. 2575 */ 2576 void 2577 show_sb_text(void) 2578 { 2579 msgchunk_T *mp; 2580 2581 // Only show something if there is more than one line, otherwise it looks 2582 // weird, typing a command without output results in one line. 2583 mp = msg_sb_start(last_msgchunk); 2584 if (mp == NULL || mp->sb_prev == NULL) 2585 vim_beep(BO_MESS); 2586 else 2587 { 2588 do_more_prompt('G'); 2589 wait_return(FALSE); 2590 } 2591 } 2592 2593 /* 2594 * Move to the start of screen line in already displayed text. 2595 */ 2596 static msgchunk_T * 2597 msg_sb_start(msgchunk_T *mps) 2598 { 2599 msgchunk_T *mp = mps; 2600 2601 while (mp != NULL && mp->sb_prev != NULL && !mp->sb_prev->sb_eol) 2602 mp = mp->sb_prev; 2603 return mp; 2604 } 2605 2606 /* 2607 * Mark the last message chunk as finishing the line. 2608 */ 2609 void 2610 msg_sb_eol(void) 2611 { 2612 if (last_msgchunk != NULL) 2613 last_msgchunk->sb_eol = TRUE; 2614 } 2615 2616 /* 2617 * Display a screen line from previously displayed text at row "row". 2618 * Returns a pointer to the text for the next line (can be NULL). 2619 */ 2620 static msgchunk_T * 2621 disp_sb_line(int row, msgchunk_T *smp) 2622 { 2623 msgchunk_T *mp = smp; 2624 char_u *p; 2625 2626 for (;;) 2627 { 2628 msg_row = row; 2629 msg_col = mp->sb_msg_col; 2630 p = mp->sb_text; 2631 if (*p == '\n') // don't display the line break 2632 ++p; 2633 msg_puts_display(p, -1, mp->sb_attr, TRUE); 2634 if (mp->sb_eol || mp->sb_next == NULL) 2635 break; 2636 mp = mp->sb_next; 2637 } 2638 return mp->sb_next; 2639 } 2640 2641 /* 2642 * Output any postponed text for msg_puts_attr_len(). 2643 */ 2644 static void 2645 t_puts( 2646 int *t_col, 2647 char_u *t_s, 2648 char_u *s, 2649 int attr) 2650 { 2651 // output postponed text 2652 msg_didout = TRUE; // remember that line is not empty 2653 screen_puts_len(t_s, (int)(s - t_s), msg_row, msg_col, attr); 2654 msg_col += *t_col; 2655 *t_col = 0; 2656 // If the string starts with a composing character don't increment the 2657 // column position for it. 2658 if (enc_utf8 && utf_iscomposing(utf_ptr2char(t_s))) 2659 --msg_col; 2660 if (msg_col >= Columns) 2661 { 2662 msg_col = 0; 2663 ++msg_row; 2664 } 2665 } 2666 2667 /* 2668 * Returns TRUE when messages should be printed with mch_errmsg(). 2669 * This is used when there is no valid screen, so we can see error messages. 2670 * If termcap is not active, we may be writing in an alternate console 2671 * window, cursor positioning may not work correctly (window size may be 2672 * different, e.g. for Win32 console) or we just don't know where the 2673 * cursor is. 2674 */ 2675 int 2676 msg_use_printf(void) 2677 { 2678 return (!msg_check_screen() 2679 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 2680 # ifdef VIMDLL 2681 || (!gui.in_use && !termcap_active) 2682 # else 2683 || !termcap_active 2684 # endif 2685 #endif 2686 || (swapping_screen() && !termcap_active) 2687 ); 2688 } 2689 2690 /* 2691 * Print a message when there is no valid screen. 2692 */ 2693 static void 2694 msg_puts_printf(char_u *str, int maxlen) 2695 { 2696 char_u *s = str; 2697 char_u *buf = NULL; 2698 char_u *p = s; 2699 2700 #ifdef MSWIN 2701 if (!(silent_mode && p_verbose == 0)) 2702 mch_settmode(TMODE_COOK); // handle CR and NL correctly 2703 #endif 2704 while ((maxlen < 0 || (int)(s - str) < maxlen) && *s != NUL) 2705 { 2706 if (!(silent_mode && p_verbose == 0)) 2707 { 2708 // NL --> CR NL translation (for Unix, not for "--version") 2709 if (*s == NL) 2710 { 2711 int n = (int)(s - p); 2712 2713 buf = alloc(n + 3); 2714 if (buf != NULL) 2715 { 2716 memcpy(buf, p, n); 2717 if (!info_message) 2718 buf[n++] = CAR; 2719 buf[n++] = NL; 2720 buf[n++] = NUL; 2721 if (info_message) // informative message, not an error 2722 mch_msg((char *)buf); 2723 else 2724 mch_errmsg((char *)buf); 2725 vim_free(buf); 2726 } 2727 p = s + 1; 2728 } 2729 } 2730 2731 // primitive way to compute the current column 2732 #ifdef FEAT_RIGHTLEFT 2733 if (cmdmsg_rl) 2734 { 2735 if (*s == CAR || *s == NL) 2736 msg_col = Columns - 1; 2737 else 2738 --msg_col; 2739 } 2740 else 2741 #endif 2742 { 2743 if (*s == CAR || *s == NL) 2744 msg_col = 0; 2745 else 2746 ++msg_col; 2747 } 2748 ++s; 2749 } 2750 2751 if (*p != NUL && !(silent_mode && p_verbose == 0)) 2752 { 2753 char_u *tofree = NULL; 2754 2755 if (maxlen > 0 && STRLEN(p) > (size_t)maxlen) 2756 { 2757 tofree = vim_strnsave(p, (size_t)maxlen); 2758 p = tofree; 2759 } 2760 if (p != NULL) 2761 { 2762 if (info_message) 2763 mch_msg((char *)p); 2764 else 2765 mch_errmsg((char *)p); 2766 vim_free(tofree); 2767 } 2768 } 2769 2770 msg_didout = TRUE; // assume that line is not empty 2771 2772 #ifdef MSWIN 2773 if (!(silent_mode && p_verbose == 0)) 2774 mch_settmode(TMODE_RAW); 2775 #endif 2776 } 2777 2778 /* 2779 * Show the more-prompt and handle the user response. 2780 * This takes care of scrolling back and displaying previously displayed text. 2781 * When at hit-enter prompt "typed_char" is the already typed character, 2782 * otherwise it's NUL. 2783 * Returns TRUE when jumping ahead to "confirm_msg_tail". 2784 */ 2785 static int 2786 do_more_prompt(int typed_char) 2787 { 2788 static int entered = FALSE; 2789 int used_typed_char = typed_char; 2790 int oldState = State; 2791 int c; 2792 #ifdef FEAT_CON_DIALOG 2793 int retval = FALSE; 2794 #endif 2795 int toscroll; 2796 msgchunk_T *mp_last = NULL; 2797 msgchunk_T *mp; 2798 int i; 2799 2800 // We get called recursively when a timer callback outputs a message. In 2801 // that case don't show another prompt. Also when at the hit-Enter prompt 2802 // and nothing was typed. 2803 if (entered || (State == HITRETURN && typed_char == 0)) 2804 return FALSE; 2805 entered = TRUE; 2806 2807 if (typed_char == 'G') 2808 { 2809 // "g<": Find first line on the last page. 2810 mp_last = msg_sb_start(last_msgchunk); 2811 for (i = 0; i < Rows - 2 && mp_last != NULL 2812 && mp_last->sb_prev != NULL; ++i) 2813 mp_last = msg_sb_start(mp_last->sb_prev); 2814 } 2815 2816 State = ASKMORE; 2817 setmouse(); 2818 if (typed_char == NUL) 2819 msg_moremsg(FALSE); 2820 for (;;) 2821 { 2822 /* 2823 * Get a typed character directly from the user. 2824 */ 2825 if (used_typed_char != NUL) 2826 { 2827 c = used_typed_char; // was typed at hit-enter prompt 2828 used_typed_char = NUL; 2829 } 2830 else 2831 c = get_keystroke(); 2832 2833 #if defined(FEAT_MENU) && defined(FEAT_GUI) 2834 if (c == K_MENU) 2835 { 2836 int idx = get_menu_index(current_menu, ASKMORE); 2837 2838 // Used a menu. If it starts with CTRL-Y, it must 2839 // be a "Copy" for the clipboard. Otherwise 2840 // assume that we end 2841 if (idx == MENU_INDEX_INVALID) 2842 continue; 2843 c = *current_menu->strings[idx]; 2844 if (c != NUL && current_menu->strings[idx][1] != NUL) 2845 ins_typebuf(current_menu->strings[idx] + 1, 2846 current_menu->noremap[idx], 0, TRUE, 2847 current_menu->silent[idx]); 2848 } 2849 #endif 2850 2851 toscroll = 0; 2852 switch (c) 2853 { 2854 case BS: // scroll one line back 2855 case K_BS: 2856 case 'k': 2857 case K_UP: 2858 toscroll = -1; 2859 break; 2860 2861 case CAR: // one extra line 2862 case NL: 2863 case 'j': 2864 case K_DOWN: 2865 toscroll = 1; 2866 break; 2867 2868 case 'u': // Up half a page 2869 toscroll = -(Rows / 2); 2870 break; 2871 2872 case 'd': // Down half a page 2873 toscroll = Rows / 2; 2874 break; 2875 2876 case 'b': // one page back 2877 case K_PAGEUP: 2878 toscroll = -(Rows - 1); 2879 break; 2880 2881 case ' ': // one extra page 2882 case 'f': 2883 case K_PAGEDOWN: 2884 case K_LEFTMOUSE: 2885 toscroll = Rows - 1; 2886 break; 2887 2888 case 'g': // all the way back to the start 2889 toscroll = -999999; 2890 break; 2891 2892 case 'G': // all the way to the end 2893 toscroll = 999999; 2894 lines_left = 999999; 2895 break; 2896 2897 case ':': // start new command line 2898 #ifdef FEAT_CON_DIALOG 2899 if (!confirm_msg_used) 2900 #endif 2901 { 2902 // Since got_int is set all typeahead will be flushed, but we 2903 // want to keep this ':', remember that in a special way. 2904 typeahead_noflush(':'); 2905 #ifdef FEAT_TERMINAL 2906 skip_term_loop = TRUE; 2907 #endif 2908 cmdline_row = Rows - 1; // put ':' on this line 2909 skip_redraw = TRUE; // skip redraw once 2910 need_wait_return = FALSE; // don't wait in main() 2911 } 2912 // FALLTHROUGH 2913 case 'q': // quit 2914 case Ctrl_C: 2915 case ESC: 2916 #ifdef FEAT_CON_DIALOG 2917 if (confirm_msg_used) 2918 { 2919 // Jump to the choices of the dialog. 2920 retval = TRUE; 2921 } 2922 else 2923 #endif 2924 { 2925 got_int = TRUE; 2926 quit_more = TRUE; 2927 } 2928 // When there is some more output (wrapping line) display that 2929 // without another prompt. 2930 lines_left = Rows - 1; 2931 break; 2932 2933 #ifdef FEAT_CLIPBOARD 2934 case Ctrl_Y: 2935 // Strange way to allow copying (yanking) a modeless 2936 // selection at the more prompt. Use CTRL-Y, 2937 // because the same is used in Cmdline-mode and at the 2938 // hit-enter prompt. However, scrolling one line up 2939 // might be expected... 2940 if (clip_star.state == SELECT_DONE) 2941 clip_copy_modeless_selection(TRUE); 2942 continue; 2943 #endif 2944 default: // no valid response 2945 msg_moremsg(TRUE); 2946 continue; 2947 } 2948 2949 if (toscroll != 0) 2950 { 2951 if (toscroll < 0) 2952 { 2953 // go to start of last line 2954 if (mp_last == NULL) 2955 mp = msg_sb_start(last_msgchunk); 2956 else if (mp_last->sb_prev != NULL) 2957 mp = msg_sb_start(mp_last->sb_prev); 2958 else 2959 mp = NULL; 2960 2961 // go to start of line at top of the screen 2962 for (i = 0; i < Rows - 2 && mp != NULL && mp->sb_prev != NULL; 2963 ++i) 2964 mp = msg_sb_start(mp->sb_prev); 2965 2966 if (mp != NULL && mp->sb_prev != NULL) 2967 { 2968 // Find line to be displayed at top. 2969 for (i = 0; i > toscroll; --i) 2970 { 2971 if (mp == NULL || mp->sb_prev == NULL) 2972 break; 2973 mp = msg_sb_start(mp->sb_prev); 2974 if (mp_last == NULL) 2975 mp_last = msg_sb_start(last_msgchunk); 2976 else 2977 mp_last = msg_sb_start(mp_last->sb_prev); 2978 } 2979 2980 if (toscroll == -1 && screen_ins_lines(0, 0, 1, 2981 (int)Rows, 0, NULL) == OK) 2982 { 2983 // display line at top 2984 (void)disp_sb_line(0, mp); 2985 } 2986 else 2987 { 2988 // redisplay all lines 2989 screenclear(); 2990 for (i = 0; mp != NULL && i < Rows - 1; ++i) 2991 { 2992 mp = disp_sb_line(i, mp); 2993 ++msg_scrolled; 2994 } 2995 } 2996 toscroll = 0; 2997 } 2998 } 2999 else 3000 { 3001 // First display any text that we scrolled back. 3002 while (toscroll > 0 && mp_last != NULL) 3003 { 3004 // scroll up, display line at bottom 3005 msg_scroll_up(); 3006 inc_msg_scrolled(); 3007 screen_fill((int)Rows - 2, (int)Rows - 1, 0, 3008 (int)Columns, ' ', ' ', 0); 3009 mp_last = disp_sb_line((int)Rows - 2, mp_last); 3010 --toscroll; 3011 } 3012 } 3013 3014 if (toscroll <= 0) 3015 { 3016 // displayed the requested text, more prompt again 3017 screen_fill((int)Rows - 1, (int)Rows, 0, 3018 (int)Columns, ' ', ' ', 0); 3019 msg_moremsg(FALSE); 3020 continue; 3021 } 3022 3023 // display more text, return to caller 3024 lines_left = toscroll; 3025 } 3026 3027 break; 3028 } 3029 3030 // clear the --more-- message 3031 screen_fill((int)Rows - 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 3032 State = oldState; 3033 setmouse(); 3034 if (quit_more) 3035 { 3036 msg_row = Rows - 1; 3037 msg_col = 0; 3038 } 3039 #ifdef FEAT_RIGHTLEFT 3040 else if (cmdmsg_rl) 3041 msg_col = Columns - 1; 3042 #endif 3043 3044 entered = FALSE; 3045 #ifdef FEAT_CON_DIALOG 3046 return retval; 3047 #else 3048 return FALSE; 3049 #endif 3050 } 3051 3052 #if defined(USE_MCH_ERRMSG) || defined(PROTO) 3053 3054 #ifdef mch_errmsg 3055 # undef mch_errmsg 3056 #endif 3057 #ifdef mch_msg 3058 # undef mch_msg 3059 #endif 3060 3061 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3062 static void 3063 mch_errmsg_c(char *str) 3064 { 3065 int len = (int)STRLEN(str); 3066 DWORD nwrite = 0; 3067 DWORD mode = 0; 3068 HANDLE h = GetStdHandle(STD_ERROR_HANDLE); 3069 3070 if (GetConsoleMode(h, &mode) && enc_codepage >= 0 3071 && (int)GetConsoleCP() != enc_codepage) 3072 { 3073 WCHAR *w = enc_to_utf16((char_u *)str, &len); 3074 3075 WriteConsoleW(h, w, len, &nwrite, NULL); 3076 vim_free(w); 3077 } 3078 else 3079 { 3080 fprintf(stderr, "%s", str); 3081 } 3082 } 3083 #endif 3084 3085 /* 3086 * Give an error message. To be used when the screen hasn't been initialized 3087 * yet. When stderr can't be used, collect error messages until the GUI has 3088 * started and they can be displayed in a message box. 3089 */ 3090 void 3091 mch_errmsg(char *str) 3092 { 3093 #if !defined(MSWIN) || defined(FEAT_GUI_MSWIN) 3094 int len; 3095 #endif 3096 3097 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL) 3098 // On Unix use stderr if it's a tty. 3099 // When not going to start the GUI also use stderr. 3100 // On Mac, when started from Finder, stderr is the console. 3101 if ( 3102 # ifdef UNIX 3103 # ifdef MACOS_X 3104 (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0) 3105 # else 3106 isatty(2) 3107 # endif 3108 # ifdef FEAT_GUI 3109 || 3110 # endif 3111 # endif 3112 # ifdef FEAT_GUI 3113 !(gui.in_use || gui.starting) 3114 # endif 3115 ) 3116 { 3117 fprintf(stderr, "%s", str); 3118 return; 3119 } 3120 #endif 3121 3122 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3123 # ifdef VIMDLL 3124 if (!(gui.in_use || gui.starting)) 3125 # endif 3126 { 3127 mch_errmsg_c(str); 3128 return; 3129 } 3130 #endif 3131 3132 #if !defined(MSWIN) || defined(FEAT_GUI_MSWIN) 3133 // avoid a delay for a message that isn't there 3134 emsg_on_display = FALSE; 3135 3136 len = (int)STRLEN(str) + 1; 3137 if (error_ga.ga_growsize == 0) 3138 { 3139 error_ga.ga_growsize = 80; 3140 error_ga.ga_itemsize = 1; 3141 } 3142 if (ga_grow(&error_ga, len) == OK) 3143 { 3144 mch_memmove((char_u *)error_ga.ga_data + error_ga.ga_len, 3145 (char_u *)str, len); 3146 # ifdef UNIX 3147 // remove CR characters, they are displayed 3148 { 3149 char_u *p; 3150 3151 p = (char_u *)error_ga.ga_data + error_ga.ga_len; 3152 for (;;) 3153 { 3154 p = vim_strchr(p, '\r'); 3155 if (p == NULL) 3156 break; 3157 *p = ' '; 3158 } 3159 } 3160 # endif 3161 --len; // don't count the NUL at the end 3162 error_ga.ga_len += len; 3163 } 3164 #endif 3165 } 3166 3167 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3168 static void 3169 mch_msg_c(char *str) 3170 { 3171 int len = (int)STRLEN(str); 3172 DWORD nwrite = 0; 3173 DWORD mode; 3174 HANDLE h = GetStdHandle(STD_OUTPUT_HANDLE); 3175 3176 3177 if (GetConsoleMode(h, &mode) && enc_codepage >= 0 3178 && (int)GetConsoleCP() != enc_codepage) 3179 { 3180 WCHAR *w = enc_to_utf16((char_u *)str, &len); 3181 3182 WriteConsoleW(h, w, len, &nwrite, NULL); 3183 vim_free(w); 3184 } 3185 else 3186 { 3187 printf("%s", str); 3188 } 3189 } 3190 #endif 3191 3192 /* 3193 * Give a message. To be used when the screen hasn't been initialized yet. 3194 * When there is no tty, collect messages until the GUI has started and they 3195 * can be displayed in a message box. 3196 */ 3197 void 3198 mch_msg(char *str) 3199 { 3200 #if (defined(UNIX) || defined(FEAT_GUI)) && !defined(ALWAYS_USE_GUI) && !defined(VIMDLL) 3201 // On Unix use stdout if we have a tty. This allows "vim -h | more" and 3202 // uses mch_errmsg() when started from the desktop. 3203 // When not going to start the GUI also use stdout. 3204 // On Mac, when started from Finder, stderr is the console. 3205 if ( 3206 # ifdef UNIX 3207 # ifdef MACOS_X 3208 (isatty(2) && strcmp("/dev/console", ttyname(2)) != 0) 3209 # else 3210 isatty(2) 3211 # endif 3212 # ifdef FEAT_GUI 3213 || 3214 # endif 3215 # endif 3216 # ifdef FEAT_GUI 3217 !(gui.in_use || gui.starting) 3218 # endif 3219 ) 3220 { 3221 printf("%s", str); 3222 return; 3223 } 3224 #endif 3225 3226 #if defined(MSWIN) && (!defined(FEAT_GUI_MSWIN) || defined(VIMDLL)) 3227 # ifdef VIMDLL 3228 if (!(gui.in_use || gui.starting)) 3229 # endif 3230 { 3231 mch_msg_c(str); 3232 return; 3233 } 3234 #endif 3235 #if !defined(MSWIN) || defined(FEAT_GUI_MSWIN) 3236 mch_errmsg(str); 3237 #endif 3238 } 3239 #endif // USE_MCH_ERRMSG 3240 3241 /* 3242 * Put a character on the screen at the current message position and advance 3243 * to the next position. Only for printable ASCII! 3244 */ 3245 static void 3246 msg_screen_putchar(int c, int attr) 3247 { 3248 msg_didout = TRUE; // remember that line is not empty 3249 screen_putchar(c, msg_row, msg_col, attr); 3250 #ifdef FEAT_RIGHTLEFT 3251 if (cmdmsg_rl) 3252 { 3253 if (--msg_col == 0) 3254 { 3255 msg_col = Columns; 3256 ++msg_row; 3257 } 3258 } 3259 else 3260 #endif 3261 { 3262 if (++msg_col >= Columns) 3263 { 3264 msg_col = 0; 3265 ++msg_row; 3266 } 3267 } 3268 } 3269 3270 static void 3271 msg_moremsg(int full) 3272 { 3273 int attr; 3274 char_u *s = (char_u *)_("-- More --"); 3275 3276 attr = HL_ATTR(HLF_M); 3277 screen_puts(s, (int)Rows - 1, 0, attr); 3278 if (full) 3279 screen_puts((char_u *) 3280 _(" SPACE/d/j: screen/page/line down, b/u/k: up, q: quit "), 3281 (int)Rows - 1, vim_strsize(s), attr); 3282 } 3283 3284 /* 3285 * Repeat the message for the current mode: ASKMORE, EXTERNCMD, CONFIRM or 3286 * exmode_active. 3287 */ 3288 void 3289 repeat_message(void) 3290 { 3291 if (State == ASKMORE) 3292 { 3293 msg_moremsg(TRUE); // display --more-- message again 3294 msg_row = Rows - 1; 3295 } 3296 #ifdef FEAT_CON_DIALOG 3297 else if (State == CONFIRM) 3298 { 3299 display_confirm_msg(); // display ":confirm" message again 3300 msg_row = Rows - 1; 3301 } 3302 #endif 3303 else if (State == EXTERNCMD) 3304 { 3305 windgoto(msg_row, msg_col); // put cursor back 3306 } 3307 else if (State == HITRETURN || State == SETWSIZE) 3308 { 3309 if (msg_row == Rows - 1) 3310 { 3311 // Avoid drawing the "hit-enter" prompt below the previous one, 3312 // overwrite it. Esp. useful when regaining focus and a 3313 // FocusGained autocmd exists but didn't draw anything. 3314 msg_didout = FALSE; 3315 msg_col = 0; 3316 msg_clr_eos(); 3317 } 3318 hit_return_msg(); 3319 msg_row = Rows - 1; 3320 } 3321 } 3322 3323 /* 3324 * msg_check_screen - check if the screen is initialized. 3325 * Also check msg_row and msg_col, if they are too big it may cause a crash. 3326 * While starting the GUI the terminal codes will be set for the GUI, but the 3327 * output goes to the terminal. Don't use the terminal codes then. 3328 */ 3329 static int 3330 msg_check_screen(void) 3331 { 3332 if (!full_screen || !screen_valid(FALSE)) 3333 return FALSE; 3334 3335 if (msg_row >= Rows) 3336 msg_row = Rows - 1; 3337 if (msg_col >= Columns) 3338 msg_col = Columns - 1; 3339 return TRUE; 3340 } 3341 3342 /* 3343 * Clear from current message position to end of screen. 3344 * Skip this when ":silent" was used, no need to clear for redirection. 3345 */ 3346 void 3347 msg_clr_eos(void) 3348 { 3349 if (msg_silent == 0) 3350 msg_clr_eos_force(); 3351 } 3352 3353 /* 3354 * Clear from current message position to end of screen. 3355 * Note: msg_col is not updated, so we remember the end of the message 3356 * for msg_check(). 3357 */ 3358 void 3359 msg_clr_eos_force(void) 3360 { 3361 if (msg_use_printf()) 3362 { 3363 if (full_screen) // only when termcap codes are valid 3364 { 3365 if (*T_CD) 3366 out_str(T_CD); // clear to end of display 3367 else if (*T_CE) 3368 out_str(T_CE); // clear to end of line 3369 } 3370 } 3371 else 3372 { 3373 #ifdef FEAT_RIGHTLEFT 3374 if (cmdmsg_rl) 3375 { 3376 screen_fill(msg_row, msg_row + 1, 0, msg_col + 1, ' ', ' ', 0); 3377 screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 3378 } 3379 else 3380 #endif 3381 { 3382 screen_fill(msg_row, msg_row + 1, msg_col, (int)Columns, 3383 ' ', ' ', 0); 3384 screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0); 3385 } 3386 } 3387 } 3388 3389 /* 3390 * Clear the command line. 3391 */ 3392 void 3393 msg_clr_cmdline(void) 3394 { 3395 msg_row = cmdline_row; 3396 msg_col = 0; 3397 msg_clr_eos_force(); 3398 } 3399 3400 /* 3401 * end putting a message on the screen 3402 * call wait_return if the message does not fit in the available space 3403 * return TRUE if wait_return not called. 3404 */ 3405 int 3406 msg_end(void) 3407 { 3408 /* 3409 * If the string is larger than the window, 3410 * or the ruler option is set and we run into it, 3411 * we have to redraw the window. 3412 * Do not do this if we are abandoning the file or editing the command line. 3413 */ 3414 if (!exiting && need_wait_return && !(State & CMDLINE)) 3415 { 3416 wait_return(FALSE); 3417 return FALSE; 3418 } 3419 out_flush(); 3420 return TRUE; 3421 } 3422 3423 /* 3424 * If the written message runs into the shown command or ruler, we have to 3425 * wait for hit-return and redraw the window later. 3426 */ 3427 void 3428 msg_check(void) 3429 { 3430 if (msg_row == Rows - 1 && msg_col >= sc_col) 3431 { 3432 need_wait_return = TRUE; 3433 redraw_cmdline = TRUE; 3434 } 3435 } 3436 3437 /* 3438 * May write a string to the redirection file. 3439 * When "maxlen" is -1 write the whole string, otherwise up to "maxlen" bytes. 3440 */ 3441 static void 3442 redir_write(char_u *str, int maxlen) 3443 { 3444 char_u *s = str; 3445 static int cur_col = 0; 3446 3447 // Don't do anything for displaying prompts and the like. 3448 if (redir_off) 3449 return; 3450 3451 // If 'verbosefile' is set prepare for writing in that file. 3452 if (*p_vfile != NUL && verbose_fd == NULL) 3453 verbose_open(); 3454 3455 if (redirecting()) 3456 { 3457 // If the string doesn't start with CR or NL, go to msg_col 3458 if (*s != '\n' && *s != '\r') 3459 { 3460 while (cur_col < msg_col) 3461 { 3462 #ifdef FEAT_EVAL 3463 if (redir_execute) 3464 execute_redir_str((char_u *)" ", -1); 3465 else if (redir_reg) 3466 write_reg_contents(redir_reg, (char_u *)" ", -1, TRUE); 3467 else if (redir_vname) 3468 var_redir_str((char_u *)" ", -1); 3469 else 3470 #endif 3471 if (redir_fd != NULL) 3472 fputs(" ", redir_fd); 3473 if (verbose_fd != NULL) 3474 fputs(" ", verbose_fd); 3475 ++cur_col; 3476 } 3477 } 3478 3479 #ifdef FEAT_EVAL 3480 if (redir_execute) 3481 execute_redir_str(s, maxlen); 3482 else if (redir_reg) 3483 write_reg_contents(redir_reg, s, maxlen, TRUE); 3484 else if (redir_vname) 3485 var_redir_str(s, maxlen); 3486 #endif 3487 3488 // Write and adjust the current column. 3489 while (*s != NUL && (maxlen < 0 || (int)(s - str) < maxlen)) 3490 { 3491 #ifdef FEAT_EVAL 3492 if (!redir_reg && !redir_vname && !redir_execute) 3493 #endif 3494 if (redir_fd != NULL) 3495 putc(*s, redir_fd); 3496 if (verbose_fd != NULL) 3497 putc(*s, verbose_fd); 3498 if (*s == '\r' || *s == '\n') 3499 cur_col = 0; 3500 else if (*s == '\t') 3501 cur_col += (8 - cur_col % 8); 3502 else 3503 ++cur_col; 3504 ++s; 3505 } 3506 3507 if (msg_silent != 0) // should update msg_col 3508 msg_col = cur_col; 3509 } 3510 } 3511 3512 int 3513 redirecting(void) 3514 { 3515 return redir_fd != NULL || *p_vfile != NUL 3516 #ifdef FEAT_EVAL 3517 || redir_reg || redir_vname || redir_execute 3518 #endif 3519 ; 3520 } 3521 3522 /* 3523 * Before giving verbose message. 3524 * Must always be called paired with verbose_leave()! 3525 */ 3526 void 3527 verbose_enter(void) 3528 { 3529 if (*p_vfile != NUL) 3530 ++msg_silent; 3531 } 3532 3533 /* 3534 * After giving verbose message. 3535 * Must always be called paired with verbose_enter()! 3536 */ 3537 void 3538 verbose_leave(void) 3539 { 3540 if (*p_vfile != NUL) 3541 if (--msg_silent < 0) 3542 msg_silent = 0; 3543 } 3544 3545 /* 3546 * Like verbose_enter() and set msg_scroll when displaying the message. 3547 */ 3548 void 3549 verbose_enter_scroll(void) 3550 { 3551 if (*p_vfile != NUL) 3552 ++msg_silent; 3553 else 3554 // always scroll up, don't overwrite 3555 msg_scroll = TRUE; 3556 } 3557 3558 /* 3559 * Like verbose_leave() and set cmdline_row when displaying the message. 3560 */ 3561 void 3562 verbose_leave_scroll(void) 3563 { 3564 if (*p_vfile != NUL) 3565 { 3566 if (--msg_silent < 0) 3567 msg_silent = 0; 3568 } 3569 else 3570 cmdline_row = msg_row; 3571 } 3572 3573 /* 3574 * Called when 'verbosefile' is set: stop writing to the file. 3575 */ 3576 void 3577 verbose_stop(void) 3578 { 3579 if (verbose_fd != NULL) 3580 { 3581 fclose(verbose_fd); 3582 verbose_fd = NULL; 3583 } 3584 verbose_did_open = FALSE; 3585 } 3586 3587 /* 3588 * Open the file 'verbosefile'. 3589 * Return FAIL or OK. 3590 */ 3591 int 3592 verbose_open(void) 3593 { 3594 if (verbose_fd == NULL && !verbose_did_open) 3595 { 3596 // Only give the error message once. 3597 verbose_did_open = TRUE; 3598 3599 verbose_fd = mch_fopen((char *)p_vfile, "a"); 3600 if (verbose_fd == NULL) 3601 { 3602 semsg(_(e_notopen), p_vfile); 3603 return FAIL; 3604 } 3605 } 3606 return OK; 3607 } 3608 3609 /* 3610 * Give a warning message (for searching). 3611 * Use 'w' highlighting and may repeat the message after redrawing 3612 */ 3613 void 3614 give_warning(char_u *message, int hl) 3615 { 3616 give_warning_with_source(message, hl, FALSE); 3617 } 3618 3619 void 3620 give_warning_with_source(char_u *message, int hl, int with_source) 3621 { 3622 // Don't do this for ":silent". 3623 if (msg_silent != 0) 3624 return; 3625 3626 // Don't want a hit-enter prompt here. 3627 ++no_wait_return; 3628 3629 #ifdef FEAT_EVAL 3630 set_vim_var_string(VV_WARNINGMSG, message, -1); 3631 #endif 3632 VIM_CLEAR(keep_msg); 3633 if (hl) 3634 keep_msg_attr = HL_ATTR(HLF_W); 3635 else 3636 keep_msg_attr = 0; 3637 3638 if (with_source) 3639 { 3640 // Do what msg() does, but with a column offset if the warning should 3641 // be after the mode message. 3642 msg_start(); 3643 msg_source(HL_ATTR(HLF_W)); 3644 msg_puts(" "); 3645 msg_puts_attr((char *)message, HL_ATTR(HLF_W) | MSG_HIST); 3646 msg_clr_eos(); 3647 (void)msg_end(); 3648 } 3649 else if (msg_attr((char *)message, keep_msg_attr) && msg_scrolled == 0) 3650 set_keep_msg(message, keep_msg_attr); 3651 3652 msg_didout = FALSE; // overwrite this message 3653 msg_nowait = TRUE; // don't wait for this message 3654 msg_col = 0; 3655 3656 --no_wait_return; 3657 } 3658 3659 #if defined(FEAT_EVAL) || defined(PROTO) 3660 void 3661 give_warning2(char_u *message, char_u *a1, int hl) 3662 { 3663 if (IObuff == NULL) 3664 { 3665 // Very early in initialisation and already something wrong, just give 3666 // the raw message so the user at least gets a hint. 3667 give_warning((char_u *)message, hl); 3668 } 3669 else 3670 { 3671 vim_snprintf((char *)IObuff, IOSIZE, (char *)message, a1); 3672 give_warning(IObuff, hl); 3673 } 3674 } 3675 #endif 3676 3677 /* 3678 * Advance msg cursor to column "col". 3679 */ 3680 void 3681 msg_advance(int col) 3682 { 3683 if (msg_silent != 0) // nothing to advance to 3684 { 3685 msg_col = col; // for redirection, may fill it up later 3686 return; 3687 } 3688 if (col >= Columns) // not enough room 3689 col = Columns - 1; 3690 #ifdef FEAT_RIGHTLEFT 3691 if (cmdmsg_rl) 3692 while (msg_col > Columns - col) 3693 msg_putchar(' '); 3694 else 3695 #endif 3696 while (msg_col < col) 3697 msg_putchar(' '); 3698 } 3699 3700 #if defined(FEAT_CON_DIALOG) || defined(PROTO) 3701 /* 3702 * Used for "confirm()" function, and the :confirm command prefix. 3703 * Versions which haven't got flexible dialogs yet, and console 3704 * versions, get this generic handler which uses the command line. 3705 * 3706 * type = one of: 3707 * VIM_QUESTION, VIM_INFO, VIM_WARNING, VIM_ERROR or VIM_GENERIC 3708 * title = title string (can be NULL for default) 3709 * (neither used in console dialogs at the moment) 3710 * 3711 * Format of the "buttons" string: 3712 * "Button1Name\nButton2Name\nButton3Name" 3713 * The first button should normally be the default/accept 3714 * The second button should be the 'Cancel' button 3715 * Other buttons- use your imagination! 3716 * A '&' in a button name becomes a shortcut, so each '&' should be before a 3717 * different letter. 3718 */ 3719 int 3720 do_dialog( 3721 int type UNUSED, 3722 char_u *title UNUSED, 3723 char_u *message, 3724 char_u *buttons, 3725 int dfltbutton, 3726 char_u *textfield UNUSED, // IObuff for inputdialog(), NULL 3727 // otherwise 3728 int ex_cmd) // when TRUE pressing : accepts default and starts 3729 // Ex command 3730 { 3731 int oldState; 3732 int retval = 0; 3733 char_u *hotkeys; 3734 int c; 3735 int i; 3736 tmode_T save_tmode; 3737 3738 #ifndef NO_CONSOLE 3739 // Don't output anything in silent mode ("ex -s") 3740 if (silent_mode) 3741 return dfltbutton; // return default option 3742 #endif 3743 3744 #ifdef FEAT_GUI_DIALOG 3745 // When GUI is running and 'c' not in 'guioptions', use the GUI dialog 3746 if (gui.in_use && vim_strchr(p_go, GO_CONDIALOG) == NULL) 3747 { 3748 c = gui_mch_dialog(type, title, message, buttons, dfltbutton, 3749 textfield, ex_cmd); 3750 // avoid a hit-enter prompt without clearing the cmdline 3751 need_wait_return = FALSE; 3752 emsg_on_display = FALSE; 3753 cmdline_row = msg_row; 3754 3755 // Flush output to avoid that further messages and redrawing is done 3756 // in the wrong order. 3757 out_flush(); 3758 gui_mch_update(); 3759 3760 return c; 3761 } 3762 #endif 3763 3764 oldState = State; 3765 State = CONFIRM; 3766 setmouse(); 3767 3768 // Ensure raw mode here. 3769 save_tmode = cur_tmode; 3770 settmode(TMODE_RAW); 3771 3772 /* 3773 * Since we wait for a keypress, don't make the 3774 * user press RETURN as well afterwards. 3775 */ 3776 ++no_wait_return; 3777 hotkeys = msg_show_console_dialog(message, buttons, dfltbutton); 3778 3779 if (hotkeys != NULL) 3780 { 3781 for (;;) 3782 { 3783 // Get a typed character directly from the user. 3784 c = get_keystroke(); 3785 switch (c) 3786 { 3787 case CAR: // User accepts default option 3788 case NL: 3789 retval = dfltbutton; 3790 break; 3791 case Ctrl_C: // User aborts/cancels 3792 case ESC: 3793 retval = 0; 3794 break; 3795 default: // Could be a hotkey? 3796 if (c < 0) // special keys are ignored here 3797 continue; 3798 if (c == ':' && ex_cmd) 3799 { 3800 retval = dfltbutton; 3801 ins_char_typebuf(':', 0); 3802 break; 3803 } 3804 3805 // Make the character lowercase, as chars in "hotkeys" are. 3806 c = MB_TOLOWER(c); 3807 retval = 1; 3808 for (i = 0; hotkeys[i]; ++i) 3809 { 3810 if (has_mbyte) 3811 { 3812 if ((*mb_ptr2char)(hotkeys + i) == c) 3813 break; 3814 i += (*mb_ptr2len)(hotkeys + i) - 1; 3815 } 3816 else 3817 if (hotkeys[i] == c) 3818 break; 3819 ++retval; 3820 } 3821 if (hotkeys[i]) 3822 break; 3823 // No hotkey match, so keep waiting 3824 continue; 3825 } 3826 break; 3827 } 3828 3829 vim_free(hotkeys); 3830 } 3831 3832 settmode(save_tmode); 3833 State = oldState; 3834 setmouse(); 3835 --no_wait_return; 3836 msg_end_prompt(); 3837 3838 return retval; 3839 } 3840 3841 /* 3842 * Copy one character from "*from" to "*to", taking care of multi-byte 3843 * characters. Return the length of the character in bytes. 3844 */ 3845 static int 3846 copy_char( 3847 char_u *from, 3848 char_u *to, 3849 int lowercase) // make character lower case 3850 { 3851 int len; 3852 int c; 3853 3854 if (has_mbyte) 3855 { 3856 if (lowercase) 3857 { 3858 c = MB_TOLOWER((*mb_ptr2char)(from)); 3859 return (*mb_char2bytes)(c, to); 3860 } 3861 else 3862 { 3863 len = (*mb_ptr2len)(from); 3864 mch_memmove(to, from, (size_t)len); 3865 return len; 3866 } 3867 } 3868 else 3869 { 3870 if (lowercase) 3871 *to = (char_u)TOLOWER_LOC(*from); 3872 else 3873 *to = *from; 3874 return 1; 3875 } 3876 } 3877 3878 /* 3879 * Format the dialog string, and display it at the bottom of 3880 * the screen. Return a string of hotkey chars (if defined) for 3881 * each 'button'. If a button has no hotkey defined, the first character of 3882 * the button is used. 3883 * The hotkeys can be multi-byte characters, but without combining chars. 3884 * 3885 * Returns an allocated string with hotkeys, or NULL for error. 3886 */ 3887 static char_u * 3888 msg_show_console_dialog( 3889 char_u *message, 3890 char_u *buttons, 3891 int dfltbutton) 3892 { 3893 int len = 0; 3894 #define HOTK_LEN (has_mbyte ? MB_MAXBYTES : 1) 3895 int lenhotkey = HOTK_LEN; // count first button 3896 char_u *hotk = NULL; 3897 char_u *msgp = NULL; 3898 char_u *hotkp = NULL; 3899 char_u *r; 3900 int copy; 3901 #define HAS_HOTKEY_LEN 30 3902 char_u has_hotkey[HAS_HOTKEY_LEN]; 3903 int first_hotkey = FALSE; // first char of button is hotkey 3904 int idx; 3905 3906 has_hotkey[0] = FALSE; 3907 3908 /* 3909 * First loop: compute the size of memory to allocate. 3910 * Second loop: copy to the allocated memory. 3911 */ 3912 for (copy = 0; copy <= 1; ++copy) 3913 { 3914 r = buttons; 3915 idx = 0; 3916 while (*r) 3917 { 3918 if (*r == DLG_BUTTON_SEP) 3919 { 3920 if (copy) 3921 { 3922 *msgp++ = ','; 3923 *msgp++ = ' '; // '\n' -> ', ' 3924 3925 // advance to next hotkey and set default hotkey 3926 if (has_mbyte) 3927 hotkp += STRLEN(hotkp); 3928 else 3929 ++hotkp; 3930 hotkp[copy_char(r + 1, hotkp, TRUE)] = NUL; 3931 if (dfltbutton) 3932 --dfltbutton; 3933 3934 // If no hotkey is specified first char is used. 3935 if (idx < HAS_HOTKEY_LEN - 1 && !has_hotkey[++idx]) 3936 first_hotkey = TRUE; 3937 } 3938 else 3939 { 3940 len += 3; // '\n' -> ', '; 'x' -> '(x)' 3941 lenhotkey += HOTK_LEN; // each button needs a hotkey 3942 if (idx < HAS_HOTKEY_LEN - 1) 3943 has_hotkey[++idx] = FALSE; 3944 } 3945 } 3946 else if (*r == DLG_HOTKEY_CHAR || first_hotkey) 3947 { 3948 if (*r == DLG_HOTKEY_CHAR) 3949 ++r; 3950 first_hotkey = FALSE; 3951 if (copy) 3952 { 3953 if (*r == DLG_HOTKEY_CHAR) // '&&a' -> '&a' 3954 *msgp++ = *r; 3955 else 3956 { 3957 // '&a' -> '[a]' 3958 *msgp++ = (dfltbutton == 1) ? '[' : '('; 3959 msgp += copy_char(r, msgp, FALSE); 3960 *msgp++ = (dfltbutton == 1) ? ']' : ')'; 3961 3962 // redefine hotkey 3963 hotkp[copy_char(r, hotkp, TRUE)] = NUL; 3964 } 3965 } 3966 else 3967 { 3968 ++len; // '&a' -> '[a]' 3969 if (idx < HAS_HOTKEY_LEN - 1) 3970 has_hotkey[idx] = TRUE; 3971 } 3972 } 3973 else 3974 { 3975 // everything else copy literally 3976 if (copy) 3977 msgp += copy_char(r, msgp, FALSE); 3978 } 3979 3980 // advance to the next character 3981 MB_PTR_ADV(r); 3982 } 3983 3984 if (copy) 3985 { 3986 *msgp++ = ':'; 3987 *msgp++ = ' '; 3988 *msgp = NUL; 3989 } 3990 else 3991 { 3992 len += (int)(STRLEN(message) 3993 + 2 // for the NL's 3994 + STRLEN(buttons) 3995 + 3); // for the ": " and NUL 3996 lenhotkey++; // for the NUL 3997 3998 // If no hotkey is specified first char is used. 3999 if (!has_hotkey[0]) 4000 { 4001 first_hotkey = TRUE; 4002 len += 2; // "x" -> "[x]" 4003 } 4004 4005 /* 4006 * Now allocate and load the strings 4007 */ 4008 vim_free(confirm_msg); 4009 confirm_msg = alloc(len); 4010 if (confirm_msg == NULL) 4011 return NULL; 4012 *confirm_msg = NUL; 4013 hotk = alloc(lenhotkey); 4014 if (hotk == NULL) 4015 return NULL; 4016 4017 *confirm_msg = '\n'; 4018 STRCPY(confirm_msg + 1, message); 4019 4020 msgp = confirm_msg + 1 + STRLEN(message); 4021 hotkp = hotk; 4022 4023 // Define first default hotkey. Keep the hotkey string NUL 4024 // terminated to avoid reading past the end. 4025 hotkp[copy_char(buttons, hotkp, TRUE)] = NUL; 4026 4027 // Remember where the choices start, displaying starts here when 4028 // "hotkp" typed at the more prompt. 4029 confirm_msg_tail = msgp; 4030 *msgp++ = '\n'; 4031 } 4032 } 4033 4034 display_confirm_msg(); 4035 return hotk; 4036 } 4037 4038 /* 4039 * Display the ":confirm" message. Also called when screen resized. 4040 */ 4041 static void 4042 display_confirm_msg(void) 4043 { 4044 // avoid that 'q' at the more prompt truncates the message here 4045 ++confirm_msg_used; 4046 if (confirm_msg != NULL) 4047 msg_puts_attr((char *)confirm_msg, HL_ATTR(HLF_M)); 4048 --confirm_msg_used; 4049 } 4050 4051 #endif // FEAT_CON_DIALOG 4052 4053 #if defined(FEAT_CON_DIALOG) || defined(FEAT_GUI_DIALOG) 4054 4055 int 4056 vim_dialog_yesno( 4057 int type, 4058 char_u *title, 4059 char_u *message, 4060 int dflt) 4061 { 4062 if (do_dialog(type, 4063 title == NULL ? (char_u *)_("Question") : title, 4064 message, 4065 (char_u *)_("&Yes\n&No"), dflt, NULL, FALSE) == 1) 4066 return VIM_YES; 4067 return VIM_NO; 4068 } 4069 4070 int 4071 vim_dialog_yesnocancel( 4072 int type, 4073 char_u *title, 4074 char_u *message, 4075 int dflt) 4076 { 4077 switch (do_dialog(type, 4078 title == NULL ? (char_u *)_("Question") : title, 4079 message, 4080 (char_u *)_("&Yes\n&No\n&Cancel"), dflt, NULL, FALSE)) 4081 { 4082 case 1: return VIM_YES; 4083 case 2: return VIM_NO; 4084 } 4085 return VIM_CANCEL; 4086 } 4087 4088 int 4089 vim_dialog_yesnoallcancel( 4090 int type, 4091 char_u *title, 4092 char_u *message, 4093 int dflt) 4094 { 4095 switch (do_dialog(type, 4096 title == NULL ? (char_u *)"Question" : title, 4097 message, 4098 (char_u *)_("&Yes\n&No\nSave &All\n&Discard All\n&Cancel"), 4099 dflt, NULL, FALSE)) 4100 { 4101 case 1: return VIM_YES; 4102 case 2: return VIM_NO; 4103 case 3: return VIM_ALL; 4104 case 4: return VIM_DISCARDALL; 4105 } 4106 return VIM_CANCEL; 4107 } 4108 4109 #endif // FEAT_GUI_DIALOG || FEAT_CON_DIALOG 4110