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