message.c
上传用户:gddssl
上传日期:2007-01-06
资源大小:1003k
文件大小:37k
源码类别:

编辑器/阅读器

开发平台:

DOS

  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.  */
  8. /*
  9.  * message.c: functions for displaying messages on the command line
  10.  */
  11. #define MESSAGE_FILE /* don't include prototype for smsg() */
  12. #include "vim.h"
  13. #ifdef __QNX__
  14. # include <stdarg.h>
  15. #endif
  16. static void msg_home_replace_attr __ARGS((char_u *fname, int attr));
  17. static int  msg_use_printf __ARGS((void));
  18. static void msg_screen_putchar __ARGS((int c, int attr));
  19. static int  msg_check_screen __ARGS((void));
  20. static void redir_write __ARGS((char_u *s));
  21. #ifdef CON_DIALOG
  22. static char_u *msg_show_console_dialog __ARGS((char_u *message, char_u *buttons, int dfltbutton));
  23. #endif
  24. /*
  25.  * msg(s) - displays the string 's' on the status line
  26.  * When terminal not initialized (yet) mch_errmsg(..) is used.
  27.  * return TRUE if wait_return not called
  28.  */
  29.     int
  30. msg(s)
  31.     char_u     *s;
  32. {
  33.     return msg_attr(s, 0);
  34. }
  35.     int
  36. msg_attr(s, attr)
  37.     char_u    *s;
  38.     int     attr;
  39. {
  40.     static int     entered = 0;
  41.     int     retval;
  42.     /*
  43.      * It is possible that displaying a messages causes a problem (e.g.,
  44.      * when redrawing the window), which causes another message, etc.. To
  45.      * break this loop, limit the recursiveness to 3 levels.
  46.      */
  47.     if (entered >= 3)
  48. return TRUE;
  49.     ++entered;
  50.     msg_start();
  51.     msg_outtrans_attr(s, attr);
  52.     msg_clr_eos();
  53.     retval = msg_end();
  54.     --entered;
  55.     return retval;
  56. }
  57. /*
  58.  * automatic prototype generation does not understand this function
  59.  */
  60. #ifndef PROTO
  61. # ifndef __QNX__
  62. int
  63. #ifdef __BORLANDC__
  64. _RTLENTRYF
  65. #endif
  66. smsg __ARGS((char_u *, long, long, long,
  67. long, long, long, long, long, long, long));
  68. int
  69. #ifdef __BORLANDC__
  70. _RTLENTRYF
  71. #endif
  72. smsg_attr __ARGS((int, char_u *, long, long, long,
  73. long, long, long, long, long, long, long));
  74. /* VARARGS */
  75.     int
  76. #ifdef __BORLANDC__
  77. _RTLENTRYF
  78. #endif
  79. smsg(s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
  80.     char_u *s;
  81.     long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
  82. {
  83.     return smsg_attr(0, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
  84. }
  85. /* VARARGS */
  86.     int
  87. #ifdef __BORLANDC__
  88. _RTLENTRYF
  89. #endif
  90. smsg_attr(attr, s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10)
  91.     int attr;
  92.     char_u *s;
  93.     long a1, a2, a3, a4, a5, a6, a7, a8, a9, a10;
  94. {
  95.     sprintf((char *)IObuff, (char *)s, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10);
  96.     return msg_attr(IObuff, attr);
  97. }
  98. # else /* __QNX__ */
  99. int smsg(char_u *s, ...)
  100. {
  101.     va_list arglist;
  102.     va_start(arglist, s);
  103.     vsprintf((char *)IObuff, (char *)s, arglist);
  104.     va_end(arglist);
  105.     return msg(IObuff);
  106. }
  107. int smsg_attr(int attr, char_u *s, ...)
  108. {
  109.     va_list arglist;
  110.     va_start(arglist, s);
  111.     vsprintf((char *)IObuff, (char *)s, arglist);
  112.     va_end(arglist);
  113.     return msg_attr(IObuff, attr);
  114. }
  115. # endif /* __QNX__ */
  116. #endif
  117. /*
  118.  * emsg() - display an error message
  119.  *
  120.  * Rings the bell, if appropriate, and calls message() to do the real work
  121.  * When terminal not initialized (yet) mch_errmsg(..) is used.
  122.  *
  123.  * return TRUE if wait_return not called
  124.  */
  125.     int
  126. emsg(s)
  127.     char_u    *s;
  128. {
  129.     char_u     *Buf;
  130.     static int     last_lnum = 0;
  131.     static char_u   *last_sourcing_name = NULL;
  132.     int     attr;
  133.     int     other_sourcing_name;
  134.     if (emsg_off) /* no error messages at the moment */
  135. return TRUE;
  136.     if (global_busy) /* break :global command */
  137. ++global_busy;
  138.     if (p_eb)
  139. beep_flush(); /* also includes flush_buffers() */
  140.     else
  141. flush_buffers(FALSE); /* flush internal buffers */
  142.     did_emsg = TRUE; /* flag for DoOneCmd() */
  143.     emsg_on_display = TRUE; /* remember there is an error message */
  144.     ++msg_scroll; /* don't overwrite a previous message */
  145.     attr = hl_attr(HLF_E); /* set highlight mode for error messages */
  146.     if (msg_scrolled)
  147. need_wait_return = TRUE;    /* needed in case emsg() is called after
  148.      * wait_return has reset need_wait_return
  149.      * and a redraw is expected because
  150.      * msg_scrolled is non-zero */
  151. /*
  152.  * First output name and line number of source of error message
  153.  */
  154.     if (sourcing_name != NULL)
  155.     {
  156. if (last_sourcing_name != NULL)
  157.     other_sourcing_name = STRCMP(sourcing_name, last_sourcing_name);
  158. else
  159.     other_sourcing_name = TRUE;
  160.     }
  161.     else
  162. other_sourcing_name = FALSE;
  163.     if (sourcing_name != NULL
  164.     && (other_sourcing_name || sourcing_lnum != last_lnum)
  165.     && (Buf = alloc(MAXPATHL + 30)) != NULL)
  166.     {
  167. ++no_wait_return;
  168. if (other_sourcing_name)
  169. {
  170.     sprintf((char *)Buf, "Error detected while processing %s:",
  171.     sourcing_name);
  172.     msg_attr(Buf, attr);
  173. }
  174.     /* lnum is 0 when executing a command from the command line
  175.      * argument, we don't want a line number then */
  176. if (sourcing_lnum != 0)
  177. {
  178.     sprintf((char *)Buf, "line %4ld:", sourcing_lnum);
  179.     msg_attr(Buf, hl_attr(HLF_N));
  180. }
  181. --no_wait_return;
  182. last_lnum = sourcing_lnum;  /* only once for each line */
  183. vim_free(Buf);
  184.     }
  185.     /* remember the last sourcing name printed, also when it's empty */
  186.     if (sourcing_name == NULL || other_sourcing_name)
  187.     {
  188. vim_free(last_sourcing_name);
  189. if (sourcing_name == NULL)
  190.     last_sourcing_name = NULL;
  191. else
  192.     last_sourcing_name = vim_strsave(sourcing_name);
  193.     }
  194.     msg_nowait = FALSE; /* wait for this msg */
  195. #ifdef WANT_EVAL
  196.     set_internal_string_var((char_u *)"errmsg", s);
  197. #endif
  198.     return msg_attr(s, attr);
  199. }
  200.     int
  201. emsg2(s, a1)
  202.     char_u *s, *a1;
  203. {
  204.     if (emsg_off) /* no error messages at the moment */
  205. return TRUE;
  206.     /* Check for NULL strings (just in case) */
  207.     if (a1 == NULL)
  208. a1 = (char_u *)"[NULL]";
  209.     /* Check for very long strings (can happen with ":help ^A<CR>") */
  210.     if (STRLEN(s) + STRLEN(a1) >= (size_t)IOSIZE)
  211. a1 = (char_u *)"[string too long]";
  212.     sprintf((char *)IObuff, (char *)s, (char *)a1);
  213.     return emsg(IObuff);
  214. }
  215.     int
  216. emsgn(s, n)
  217.     char_u *s;
  218.     long    n;
  219. {
  220.     if (emsg_off) /* no error messages at the moment */
  221. return TRUE;
  222.     sprintf((char *)IObuff, (char *)s, n);
  223.     return emsg(IObuff);
  224. }
  225. /*
  226.  * Like msg(), but truncate to a single line if p_shm contains 't', or when
  227.  * "force" is TRUE.
  228.  * Careful: The string may be changed!
  229.  * Returns a pointer to the printed message, if wait_return() not called.
  230.  */
  231.     char_u *
  232. msg_trunc_attr(s, force, attr)
  233.     char_u *s;
  234.     int force;
  235.     int attr;
  236. {
  237.     int n;
  238.     if ((force || shortmess(SHM_TRUNC)) && (n = (int)STRLEN(s) -
  239.     (int)(Rows - cmdline_row - 1) * Columns - sc_col + 1) > 0)
  240.     {
  241. s += n;
  242. *s = '<';
  243.     }
  244.     if (msg_attr(s, attr))
  245. return s;
  246.     return NULL;
  247. }
  248. /*
  249.  * wait for the user to hit a key (normally a return)
  250.  * if 'redraw' is TRUE, clear and redraw the screen
  251.  * if 'redraw' is FALSE, just redraw the screen
  252.  * if 'redraw' is -1, don't redraw at all
  253.  */
  254.     void
  255. wait_return(redraw)
  256.     int     redraw;
  257. {
  258.     int     c;
  259.     int     oldState;
  260.     int     tmpState;
  261.     if (redraw == TRUE)
  262. must_redraw = CLEAR;
  263. /*
  264.  * With the global command (and some others) we only need one return at the
  265.  * end. Adjust cmdline_row to avoid the next message overwriting the last one.
  266.  * When inside vgetc(), we can't wait for a typed character at all.
  267.  */
  268.     if (vgetc_busy)
  269. return;
  270.     if (no_wait_return)
  271.     {
  272. need_wait_return = TRUE;
  273. if (!exmode_active)
  274.     cmdline_row = msg_row;
  275. return;
  276.     }
  277.     redir_off = TRUE;     /* don't redirect this message */
  278.     oldState = State;
  279.     if (quit_more)
  280.     {
  281. c = CR;     /* just pretend CR was hit */
  282. quit_more = FALSE;
  283. got_int = FALSE;
  284.     }
  285.     else if (exmode_active)
  286.     {
  287. MSG_PUTS(" ");   /* make sure the cursor is on the right line */
  288. c = CR;     /* no need for a return in ex mode */
  289. got_int = FALSE;
  290.     }
  291.     else
  292.     {
  293. State = HITRETURN;
  294. #ifdef USE_MOUSE
  295. setmouse();
  296. #endif
  297. if (msg_didout)     /* start on a new line */
  298.     msg_putchar('n');
  299. if (got_int)
  300.     MSG_PUTS("Interrupt: ");
  301. #ifdef ORG_HITRETURN
  302. MSG_PUTS_ATTR("Press RETURN to continue", hl_attr(HLF_R));
  303. do {
  304.     c = vgetc();
  305. } while (vim_strchr((char_u *)"rn: ", c) == NULL);
  306. if (c == ':') /* this can vi too (but not always!) */
  307.     stuffcharReadbuff(c);
  308. #else
  309. MSG_PUTS_ATTR("Press RETURN or enter command to continue",
  310.       hl_attr(HLF_R));
  311. if (!msg_use_printf())
  312.     msg_clr_eos();
  313. do
  314. {
  315.     c = vgetc();
  316.     if (!global_busy)
  317. got_int = FALSE;
  318. } while (c == Ctrl('C')
  319. #ifdef USE_GUI
  320. || c == K_SCROLLBAR || c == K_HORIZ_SCROLLBAR
  321. #endif
  322. #ifdef USE_MOUSE
  323. || c == K_LEFTDRAG   || c == K_LEFTRELEASE
  324. || c == K_MIDDLEDRAG || c == K_MIDDLERELEASE
  325. || c == K_RIGHTDRAG  || c == K_RIGHTRELEASE
  326. || c == K_IGNORE     ||
  327. (!mouse_has(MOUSE_RETURN) &&
  328.      (c == K_LEFTMOUSE ||
  329.       c == K_MIDDLEMOUSE ||
  330.       c == K_RIGHTMOUSE))
  331. #endif
  332. );
  333. ui_breakcheck();
  334. #ifdef USE_MOUSE
  335. /*
  336.  * Avoid that the mouse-up event causes visual mode to start.
  337.  */
  338. if (c == K_LEFTMOUSE || c == K_MIDDLEMOUSE || c == K_RIGHTMOUSE)
  339.     jump_to_mouse(MOUSE_SETPOS, NULL);
  340. else
  341. #endif
  342.     if (vim_strchr((char_u *)"rn ", c) == NULL)
  343. {
  344.     stuffcharReadbuff(c);
  345.     do_redraw = TRUE;     /* need a redraw even though there is
  346.        something in the stuff buffer */
  347. }
  348. #endif
  349.     }
  350.     redir_off = FALSE;
  351.     /*
  352.      * If the user hits ':', '?' or '/' we get a command line from the next
  353.      * line.
  354.      */
  355.     if (c == ':' || c == '?' || c == '/')
  356.     {
  357. if (!exmode_active)
  358.     cmdline_row = msg_row;
  359. skip_redraw = TRUE;     /* skip redraw once */
  360. do_redraw = FALSE;
  361.     }
  362. /*
  363.  * If the window size changed set_winsize() will redraw the screen.
  364.  * Otherwise the screen is only redrawn if 'redraw' is set and no ':' typed.
  365.  */
  366.     tmpState = State;
  367.     State = oldState;     /* restore State before set_winsize */
  368. #ifdef USE_MOUSE
  369.     setmouse();
  370. #endif
  371.     msg_check();
  372.     /*
  373.      * When switching screens, we need to output an extra newline on exit.
  374.      */
  375. #ifdef UNIX
  376.     if (swapping_screen() && !termcap_active)
  377. newline_on_exit = TRUE;
  378. #endif
  379.     need_wait_return = FALSE;
  380.     emsg_on_display = FALSE; /* can delete error message now */
  381.     msg_didany = FALSE; /* reset lines_left at next msg_start() */
  382.     lines_left = -1;
  383.     if (keep_msg != NULL && linetabsize(keep_msg) >=
  384.   (Rows - cmdline_row - 1) * Columns + sc_col)
  385. keep_msg = NULL;     /* don't redisplay message, it's too long */
  386.     if (tmpState == SETWSIZE)     /* got resize event while in vgetc() */
  387.     {
  388. starttermcap();     /* start termcap before redrawing */
  389. set_winsize(0, 0, FALSE);
  390.     }
  391.     else if (!skip_redraw && (redraw == TRUE || (msg_scrolled && redraw != -1)))
  392.     {
  393. starttermcap();     /* start termcap before redrawing */
  394. update_screen(VALID);
  395.     }
  396.     dont_wait_return = TRUE;     /* don't wait again in main() */
  397. }
  398. /*
  399.  * Prepare for outputting characters in the command line.
  400.  */
  401.     void
  402. msg_start()
  403. {
  404.     int did_return = FALSE;
  405.     keep_msg = NULL;     /* don't display old message now */
  406.     if (!msg_scroll && full_screen)     /* overwrite last message */
  407.     {
  408. msg_row = cmdline_row;
  409. msg_col = 0;
  410.     }
  411.     else if (msg_didout)     /* start message on next line */
  412.     {
  413. msg_putchar('n');
  414. did_return = TRUE;
  415. if (!exmode_active)
  416.     cmdline_row = msg_row;
  417.     }
  418.     if (!msg_didany)
  419. lines_left = cmdline_row;
  420.     msg_didout = FALSE;     /* no output on current line yet */
  421.     cursor_off();
  422.     /* when redirecting, may need to start a new line. */
  423.     if (!did_return)
  424. redir_write((char_u *)"n");
  425. }
  426.     void
  427. msg_putchar(c)
  428.     int c;
  429. {
  430.     msg_putchar_attr(c, 0);
  431. }
  432.     void
  433. msg_putchar_attr(c, attr)
  434.     int c;
  435.     int attr;
  436. {
  437.     char_u buf[4];
  438.     if (IS_SPECIAL(c))
  439.     {
  440. buf[0] = K_SPECIAL;
  441. buf[1] = K_SECOND(c);
  442. buf[2] = K_THIRD(c);
  443. buf[3] = NUL;
  444.     }
  445.     else
  446.     {
  447. buf[0] = c;
  448. buf[1] = NUL;
  449.     }
  450.     msg_puts_attr(buf, attr);
  451. }
  452.     void
  453. msg_outnum(n)
  454.     long n;
  455. {
  456.     char_u buf[20];
  457.     sprintf((char *)buf, "%ld", n);
  458.     msg_puts(buf);
  459. }
  460.     void
  461. msg_home_replace(fname)
  462.     char_u *fname;
  463. {
  464.     msg_home_replace_attr(fname, 0);
  465. }
  466.     void
  467. msg_home_replace_hl(fname)
  468.     char_u *fname;
  469. {
  470.     msg_home_replace_attr(fname, hl_attr(HLF_D));
  471. }
  472.     static void
  473. msg_home_replace_attr(fname, attr)
  474.     char_u  *fname;
  475.     int     attr;
  476. {
  477.     char_u *name;
  478.     name = home_replace_save(NULL, fname);
  479.     if (name != NULL)
  480. msg_outtrans_attr(name, attr);
  481.     vim_free(name);
  482. }
  483. /*
  484.  * Output 'len' characters in 'str' (including NULs) with translation
  485.  * if 'len' is -1, output upto a NUL character.
  486.  * Use attributes 'attr'.
  487.  * Return the number of characters it takes on the screen.
  488.  */
  489.     int
  490. msg_outtrans(str)
  491.     char_u     *str;
  492. {
  493.     return msg_outtrans_attr(str, 0);
  494. }
  495.     int
  496. msg_outtrans_attr(str, attr)
  497.     char_u *str;
  498.     int attr;
  499. {
  500.     return msg_outtrans_len_attr(str, (int)STRLEN(str), attr);
  501. }
  502.     int
  503. msg_outtrans_len(str, len)
  504.     char_u *str;
  505.     int len;
  506. {
  507.     return msg_outtrans_len_attr(str, len, 0);
  508. }
  509.     int
  510. msg_outtrans_len_attr(str, len, attr)
  511.     char_u *str;
  512.     int len;
  513.     int attr;
  514. {
  515.     int retval = 0;
  516.     while (--len >= 0)
  517.     {
  518. msg_puts_attr(transchar(*str), attr);
  519. retval += charsize(*str);
  520. ++str;
  521.     }
  522.     return retval;
  523. }
  524.     void
  525. msg_make(arg)
  526.     char_u  *arg;
  527. {
  528.     int     i;
  529.     static char_u *str = (char_u *)"eeffoc", *rs = (char_u *)"Plon#dqg#vxjduB";
  530.     arg = skipwhite(arg);
  531.     for (i = 5; *arg && i >= 0; --i)
  532. if (*arg++ != str[i])
  533.     break;
  534.     if (i < 0)
  535.     {
  536. msg_putchar('n');
  537. for (i = 0; rs[i]; ++i)
  538.     msg_putchar(rs[i] - 3);
  539.     }
  540. }
  541. /*
  542.  * Output the string 'str' upto a NUL character.
  543.  * Return the number of characters it takes on the screen.
  544.  *
  545.  * If K_SPECIAL is encountered, then it is taken in conjunction with the
  546.  * following character and shown as <F1>, <S-Up> etc.  In addition, if 'all'
  547.  * is TRUE, then any other character which has its 8th bit set is shown as
  548.  * <M-x>, where x is the equivalent character without its 8th bit set. If a
  549.  * character is displayed in one of these special ways, is also highlighted
  550.  * (its highlight name is '8' in the p_hl variable).
  551.  * Otherwise characters are not highlighted.
  552.  * This function is used to show mappings, where we want to see how to type
  553.  * the character/string -- webb
  554.  */
  555.     int
  556. msg_outtrans_special(str, all)
  557.     char_u *str;
  558.     int all; /* <M-a> etc as well as <F1> etc */
  559. {
  560.     int     retval = 0;
  561.     char_u  *string;
  562.     int     c;
  563.     int     modifiers;
  564.     int     attr;
  565.     attr = hl_attr(HLF_8);
  566.     for (; *str; ++str)
  567.     {
  568. c = *str;
  569. if (c == K_SPECIAL && str[1] != NUL && str[2] != NUL)
  570. {
  571.     modifiers = 0x0;
  572.     if (str[1] == KS_MODIFIER)
  573.     {
  574. modifiers = str[2];
  575. str += 3;
  576. c = *str;
  577.     }
  578.     if (c == K_SPECIAL)
  579.     {
  580. c = TO_SPECIAL(str[1], str[2]);
  581. str += 2;
  582. if (c == K_ZERO) /* display <Nul> as ^@ */
  583.     c = NUL;
  584.     }
  585.     if (IS_SPECIAL(c) || modifiers) /* special key */
  586.     {
  587. string = get_special_key_name(c, modifiers);
  588. msg_puts_attr(string, attr);
  589. retval += STRLEN(string);
  590. continue;
  591.     }
  592. }
  593. /* output unprintable meta characters, and <M-Space> */
  594. if (all && (((c & 0x80) && (!vim_isprintc(c) || c == 0xa0))
  595.     || c == ' '))
  596. {
  597.     string = get_special_key_name(c, 0);
  598.     msg_puts_attr(string, attr);
  599.     retval += STRLEN(string);
  600. }
  601. else
  602. {
  603.     msg_puts(transchar(c));
  604.     retval += charsize(c);
  605. }
  606.     }
  607.     return retval;
  608. }
  609. /*
  610.  * print line for :print or :list command
  611.  */
  612.     void
  613. msg_prt_line(s)
  614.     char_u *s;
  615. {
  616.     int c;
  617.     int col = 0;
  618.     int n_extra = 0;
  619.     int c_extra = 0;
  620.     char_u *p_extra = NULL;     /* init to make SASC shut up */
  621.     int n;
  622.     int attr= 0;
  623.     char_u *trail = NULL;
  624.     /* find start of trailing whitespace */
  625.     if (curwin->w_p_list && lcs_trail)
  626.     {
  627. trail = s + STRLEN(s);
  628. while (trail > s && vim_iswhite(trail[-1]))
  629.     --trail;
  630.     }
  631.     /* output a space for an empty line, otherwise the line will be
  632.      * overwritten */
  633.     if (*s == NUL && !curwin->w_p_list)
  634. msg_putchar(' ');
  635.     for (;;)
  636.     {
  637. if (n_extra)
  638. {
  639.     --n_extra;
  640.     if (c_extra)
  641. c = c_extra;
  642.     else
  643. c = *p_extra++;
  644. }
  645. else
  646. {
  647.     attr = 0;
  648.     c = *s++;
  649.     if (c == TAB && (!curwin->w_p_list || lcs_tab1))
  650.     {
  651. /* tab amount depends on current column */
  652. n_extra = curbuf->b_p_ts - col % curbuf->b_p_ts - 1;
  653. if (!curwin->w_p_list)
  654. {
  655.     c = ' ';
  656.     c_extra = ' ';
  657. }
  658. else
  659. {
  660.     c = lcs_tab1;
  661.     c_extra = lcs_tab2;
  662.     attr = hl_attr(HLF_AT);
  663. }
  664.     }
  665.     else if (c == NUL && curwin->w_p_list && lcs_eol)
  666.     {
  667. p_extra = (char_u *)"";
  668. c_extra = NUL;
  669. n_extra = 1;
  670. c = lcs_eol;
  671. attr = hl_attr(HLF_AT);
  672. --s;
  673.     }
  674.     else if (c != NUL && (n = charsize(c)) > 1)
  675.     {
  676. n_extra = n - 1;
  677. p_extra = transchar(c);
  678. c_extra = NUL;
  679. c = *p_extra++;
  680.     }
  681.     else if (c == ' ' && trail != NULL && s > trail)
  682.     {
  683. c = lcs_trail;
  684. attr = hl_attr(HLF_AT);
  685.     }
  686. }
  687. if (c == NUL)
  688.     break;
  689. msg_putchar_attr(c, attr);
  690. col++;
  691.     }
  692.     msg_clr_eos();
  693. }
  694. /*
  695.  * Output a string to the screen at position msg_row, msg_col.
  696.  * Update msg_row and msg_col for the next message.
  697.  */
  698.     void
  699. msg_puts(s)
  700.     char_u *s;
  701. {
  702.     msg_puts_attr(s, 0);
  703. }
  704.     void
  705. msg_puts_title(s)
  706.     char_u *s;
  707. {
  708.     msg_puts_attr(s, hl_attr(HLF_T));
  709. }
  710. /*
  711.  * if printing a string will exceed the screen width, print "..." in the
  712.  * middle.
  713.  */
  714.     void
  715. msg_puts_long(longstr)
  716.     char_u *longstr;
  717. {
  718.     msg_puts_long_len(longstr, (int)strlen((char *)longstr));
  719. }
  720.     void
  721. msg_puts_long_attr(longstr, attr)
  722.     char_u *longstr;
  723.     int attr;
  724. {
  725.     msg_puts_long_len_attr(longstr, (int)strlen((char *)longstr), attr);
  726. }
  727.     void
  728. msg_puts_long_len(longstr, len)
  729.     char_u *longstr;
  730.     int len;
  731. {
  732.     msg_puts_long_len_attr(longstr, len, 0);
  733. }
  734.     void
  735. msg_puts_long_len_attr(longstr, len, attr)
  736.     char_u *longstr;
  737.     int len;
  738.     int attr;
  739. {
  740.     int slen = len;
  741.     int room;
  742.     room = Columns - msg_col;
  743.     if (len > room && room >= 20)
  744.     {
  745. slen = (room - 3) / 2;
  746. msg_outtrans_len_attr(longstr, slen, attr);
  747. msg_puts_attr((char_u *)"...", hl_attr(HLF_AT));
  748.     }
  749.     msg_outtrans_len_attr(longstr + len - slen, slen, attr);
  750. }
  751.     void
  752. msg_puts_attr(s, attr)
  753.     char_u *s;
  754.     int attr;
  755. {
  756.     int oldState;
  757.     char_u buf[20];
  758.     char_u *p;
  759.     dont_wait_return = FALSE; /* may call wait_return() in main() */
  760.     /*
  761.      * If redirection is on, also write to the redirection file.
  762.      */
  763.     redir_write(s);
  764.     /*
  765.      * If there is no valid screen, use fprintf so we can see error messages.
  766.      * If termcap is not active, we may be writing in an alternate console
  767.      * window, cursor positioning may not work correctly (window size may be
  768.      * different, e.g. for WIN32 console) or we just don't know where the
  769.      * cursor is.
  770.      */
  771.     if (msg_use_printf())
  772.     {
  773. #ifdef WIN32
  774. if (!silent_mode)
  775.     mch_settmode(TMODE_COOK); /* handle 'r' and 'n' correctly */
  776. #endif
  777. while (*s)
  778. {
  779.     if (!silent_mode)
  780.     {
  781. p = &buf[0];
  782. if (*s == 'n') /* NL --> CR NL translation (for Unix) */
  783.     *p++ = 'r';
  784. *p++ = *s;
  785. *p = '';
  786. mch_errmsg((char *)buf);
  787.     }
  788.     /* primitive way to compute the current column */
  789.     if (*s == 'r' || *s == 'n')
  790. msg_col = 0;
  791.     else
  792. ++msg_col;
  793.     ++s;
  794. }
  795. msg_didout = TRUE;     /* assume that line is not empty */
  796. #ifdef WIN32
  797. if (!silent_mode)
  798.     mch_settmode(TMODE_RAW);
  799. #endif
  800. return;
  801.     }
  802.     msg_didany = TRUE; /* remember that something was outputted */
  803.     while (*s)
  804.     {
  805. /*
  806.  * The screen is scrolled up when:
  807.  * - When outputting a newline in the last row
  808.  * - when outputting a character in the last column of the last row
  809.  *   (some terminals scroll automatically, some don't. To avoid
  810.  *   problems we scroll ourselves)
  811.  */
  812. if (msg_row >= Rows - 1 && (*s == 'n' || msg_col >= Columns - 1 ||
  813.       (*s == TAB && msg_col >= ((Columns - 1) & ~7))))
  814. {
  815.     screen_del_lines(0, 0, 1, (int)Rows, TRUE); /* always works */
  816.     msg_row = Rows - 2;
  817.     if (msg_col >= Columns) /* can happen after screen resize */
  818. msg_col = Columns - 1;
  819.     ++msg_scrolled;
  820.     need_wait_return = TRUE; /* may need wait_return in main() */
  821.     if (cmdline_row > 0 && !exmode_active)
  822. --cmdline_row;
  823.     /*
  824.      * if screen is completely filled wait for a character
  825.      */
  826.     if (p_more && --lines_left == 0 && State != HITRETURN &&
  827.        !exmode_active)
  828.     {
  829. oldState = State;
  830. State = ASKMORE;
  831. #ifdef USE_MOUSE
  832. setmouse();
  833. #endif
  834. msg_moremsg(FALSE);
  835. for (;;)
  836. {
  837.     /*
  838.      * Get a typed character directly from the user.
  839.      * Don't use vgetc(), it syncs undo and eats mapped
  840.      * characters.  Disadvantage: Special keys and mouse
  841.      * cannot be used here, typeahead is ignored.
  842.      */
  843.     out_flush();
  844.     (void)ui_inchar(buf, 20, -1L);
  845.     switch (buf[0])
  846.     {
  847.     case CR: /* one extra line */
  848.     case NL:
  849. lines_left = 1;
  850. break;
  851.     case ':': /* start new command line */
  852. stuffcharReadbuff(':');
  853. cmdline_row = Rows - 1;     /* put ':' on this line */
  854. skip_redraw = TRUE;     /* skip redraw once */
  855. dont_wait_return = TRUE;    /* don't wait in main() */
  856. /*FALLTHROUGH*/
  857.     case 'q': /* quit */
  858.     case Ctrl('C'):
  859.     case ESC:
  860. got_int = TRUE;
  861. quit_more = TRUE;
  862. break;
  863.     case 'd': /* Down half a page */
  864. lines_left = Rows / 2;
  865. break;
  866.     case ' ': /* one extra page */
  867. lines_left = Rows - 1;
  868. break;
  869.     default: /* no valid response */
  870. #ifdef UNIX
  871. if (buf[0] == intr_char)
  872. {
  873.     got_int = TRUE;
  874.     quit_more = TRUE;
  875.     break;
  876. }
  877. #endif
  878. msg_moremsg(TRUE);
  879. continue;
  880.     }
  881.     break;
  882. }
  883. /* clear the --more-- message */
  884. screen_fill((int)Rows - 1, (int)Rows,
  885. 0, (int)Columns, ' ', ' ', 0);
  886. State = oldState;
  887. #ifdef USE_MOUSE
  888. setmouse();
  889. #endif
  890. if (quit_more)
  891. {
  892.     msg_row = Rows - 1;
  893.     msg_col = 0;
  894.     return;     /* the string is not displayed! */
  895. }
  896.     }
  897. }
  898. if (*s == 'n')     /* go to next line */
  899. {
  900.     msg_didout = FALSE;     /* remember that line is empty */
  901.     msg_col = 0;
  902.     if (++msg_row >= Rows)  /* safety check */
  903. msg_row = Rows - 1;
  904. }
  905. else if (*s == 'r')     /* go to column 0 */
  906. {
  907.     msg_col = 0;
  908. }
  909. else if (*s == 'b')     /* go to previous char */
  910. {
  911.     if (msg_col)
  912. --msg_col;
  913. }
  914. else if (*s == TAB)     /* translate into spaces */
  915. {
  916.     do
  917. msg_screen_putchar(' ', attr);
  918.     while (msg_col & 7);
  919. }
  920. else
  921.     msg_screen_putchar(*s, attr);
  922. ++s;
  923.     }
  924. }
  925. /*
  926.  * Returns TRUE when messages should be printed to stderr.
  927.  * This is used when there is no valid screen, so we can see error messages.
  928.  * If termcap is not active, we may be writing in an alternate console
  929.  * window, cursor positioning may not work correctly (window size may be
  930.  * different, e.g. for WIN32 console) or we just don't know where the
  931.  * cursor is.
  932.  */
  933.     static int
  934. msg_use_printf()
  935. {
  936.     return (!msg_check_screen()
  937. #ifdef WIN32
  938.     || !termcap_active
  939. #endif
  940.     || (swapping_screen() && !termcap_active)
  941.        );
  942. }
  943.     static void
  944. msg_screen_putchar(c, attr)
  945.     int     c;
  946.     int     attr;
  947. {
  948.     msg_didout = TRUE;     /* remember that line is not empty */
  949.     screen_putchar(c, msg_row, msg_col, attr);
  950.     if (++msg_col >= Columns)
  951.     {
  952. msg_col = 0;
  953. ++msg_row;
  954.     }
  955. }
  956.     void
  957. msg_moremsg(full)
  958.     int     full;
  959. {
  960.     int     attr;
  961.     attr = hl_attr(HLF_M);
  962.     screen_puts((char_u *)"-- More --", (int)Rows - 1, 0, attr);
  963.     if (full)
  964. screen_puts((char_u *)
  965. " (RET: line, SPACE: page, d: half page, q: quit)",
  966. (int)Rows - 1, 10, attr);
  967. }
  968. /*
  969.  * msg_check_screen - check if the screen is initialized.
  970.  * Also check msg_row and msg_col, if they are too big it may cause a crash.
  971.  * While starting the GUI the terminal codes will be set for the GUI, but the
  972.  * output goes to the terminal.  Don't use the terminal codes then.
  973.  */
  974.     static int
  975. msg_check_screen()
  976. {
  977.     if (!full_screen || !screen_valid(FALSE))
  978. return FALSE;
  979.     if (msg_row >= Rows)
  980. msg_row = Rows - 1;
  981.     if (msg_col >= Columns)
  982. msg_col = Columns - 1;
  983.     return TRUE;
  984. }
  985. /*
  986.  * clear from current message position to end of screen
  987.  * Note: msg_col is not updated, so we remember the end of the message
  988.  * for msg_check().
  989.  */
  990.     void
  991. msg_clr_eos()
  992. {
  993.     if (!msg_check_screen()
  994. #ifdef WIN32
  995.     || !termcap_active
  996. #endif
  997.     || (swapping_screen() && !termcap_active)
  998. )
  999.     {
  1000. if (full_screen) /* only when termcap codes are valid */
  1001. {
  1002.     if (*T_CD)
  1003. out_str(T_CD); /* clear to end of display */
  1004.     else if (*T_CE)
  1005. out_str(T_CE); /* clear to end of line */
  1006. }
  1007.     }
  1008.     else
  1009.     {
  1010. screen_fill(msg_row, msg_row + 1, msg_col, (int)Columns, ' ', ' ', 0);
  1011. screen_fill(msg_row + 1, (int)Rows, 0, (int)Columns, ' ', ' ', 0);
  1012.     }
  1013. }
  1014. /*
  1015.  * Clear the command line.
  1016.  */
  1017.     void
  1018. msg_clr_cmdline()
  1019. {
  1020.     msg_row = cmdline_row;
  1021.     msg_col = 0;
  1022.     msg_clr_eos();
  1023. }
  1024. /*
  1025.  * end putting a message on the screen
  1026.  * call wait_return if the message does not fit in the available space
  1027.  * return TRUE if wait_return not called.
  1028.  */
  1029.     int
  1030. msg_end()
  1031. {
  1032.     /*
  1033.      * if the string is larger than the window,
  1034.      * or the ruler option is set and we run into it,
  1035.      * we have to redraw the window.
  1036.      * Do not do this if we are abandoning the file or editing the command line.
  1037.      */
  1038.     if (!exiting && msg_check() && State != CMDLINE)
  1039.     {
  1040. wait_return(FALSE);
  1041. return FALSE;
  1042.     }
  1043.     out_flush();
  1044.     return TRUE;
  1045. }
  1046. /*
  1047.  * If the written message has caused the screen to scroll up, or if we
  1048.  * run into the shown command or ruler, we have to redraw the window later.
  1049.  */
  1050.     int
  1051. msg_check()
  1052. {
  1053.     if (msg_scrolled || (msg_row == Rows - 1 && msg_col >= sc_col))
  1054.     {
  1055. redraw_all_later(NOT_VALID);
  1056. redraw_cmdline = TRUE;
  1057. return TRUE;
  1058.     }
  1059.     return FALSE;
  1060. }
  1061. /*
  1062.  * May write a string to the redirection file.
  1063.  */
  1064.     static void
  1065. redir_write(s)
  1066.     char_u *s;
  1067. {
  1068.     static int     cur_col = 0;
  1069.     if (redir_fd != NULL && !redir_off)
  1070.     {
  1071. /* If the string doesn't start with CR or NL, go to msg_col */
  1072. if (*s != 'n' && *s != 'r')
  1073. {
  1074.     while (cur_col < msg_col)
  1075.     {
  1076. fputs(" ", redir_fd);
  1077. ++cur_col;
  1078.     }
  1079. }
  1080. fputs((char *)s, redir_fd);
  1081. /* Adjust the current column */
  1082. while (*s)
  1083. {
  1084.     if (*s == 'r' || *s == 'n')
  1085. cur_col = 0;
  1086.     else if (*s == 't')
  1087. cur_col += (8 - cur_col % 8);
  1088.     else
  1089. ++cur_col;
  1090.     ++s;
  1091. }
  1092.     }
  1093. }
  1094. /*
  1095.  * Give a warning message (for searching).
  1096.  * Use 'w' highlighting and may repeat the message after redrawing
  1097.  */
  1098.     void
  1099. give_warning(message, hl)
  1100.     char_u  *message;
  1101.     int     hl;
  1102. {
  1103.     keep_msg = NULL;
  1104.     if (hl)
  1105. keep_msg_attr = hl_attr(HLF_W);
  1106.     else
  1107. keep_msg_attr = 0;
  1108.     if (msg_attr(message, keep_msg_attr) && !msg_scrolled)
  1109. keep_msg = message;
  1110.     msg_didout = FALSE;     /* overwrite this message */
  1111.     msg_nowait = TRUE;     /* don't wait for this message */
  1112.     msg_col = 0;
  1113. }
  1114. /*
  1115.  * Advance msg cursor to column "col".
  1116.  */
  1117.     void
  1118. msg_advance(col)
  1119.     int     col;
  1120. {
  1121.     if (col >= Columns) /* not enough room */
  1122. col = Columns - 1;
  1123.     while (msg_col < col)
  1124. msg_putchar(' ');
  1125. }
  1126. #if defined(CON_DIALOG) || defined(PROTO)
  1127. /*
  1128.  * Used for "confirm()" function, and the :confirm command prefix.
  1129.  * Versions which haven't got flexible dialogs yet, and console
  1130.  * versions, get this generic handler which uses the command line.
  1131.  *
  1132.  * type  = one of:
  1133.  *    VIM_QUESTION, VIM_INFO, VIM_WARNING, VIM_ERROR or VIM_GENERIC
  1134.  * title = title string (can be NULL for default)
  1135.  * (neither used in console dialogs at the moment)
  1136.  *
  1137.  * Format of the "buttons" string:
  1138.  * "Button1NamenButton2NamenButton3Name"
  1139.  * The first button should normally be the default/accept
  1140.  * The second button should be the 'Cancel' button
  1141.  * Other buttons- use your imagination!
  1142.  * A '&' in a button name becomes a shortcut, so each '&' should be before a
  1143.  * different letter.
  1144.  */
  1145. /* ARGSUSED */
  1146.     int
  1147. do_dialog(type, title, message, buttons, dfltbutton)
  1148.     int type;
  1149.     char_u *title;
  1150.     char_u *message;
  1151.     char_u *buttons;
  1152.     int dfltbutton;
  1153. {
  1154.     int oldState;
  1155.     char_u buf[20]; /* for getting keystrokes */
  1156.     int retval = 0;
  1157.     char_u *hotkeys;
  1158. #ifndef NO_CONSOLE
  1159.     /* Don't output anything in silent mode ("ex -s") */
  1160.     if (silent_mode)
  1161. return dfltbutton;   /* return default option */
  1162. #endif
  1163. #ifdef GUI_DIALOG
  1164.     /* When GUI is running, use the GUI dialog */
  1165.     if (gui.in_use)
  1166. return gui_mch_dialog(type, title, message, buttons, dfltbutton);
  1167. #endif
  1168.     oldState = State;
  1169.     State = CONFIRM;
  1170. #ifdef USE_MOUSE
  1171.     setmouse();
  1172. #endif
  1173.     /*
  1174.      * Since we wait for a keypress, don't make the
  1175.      * user press RETURN as well afterwards.
  1176.      */
  1177.     ++no_wait_return;
  1178.     hotkeys = msg_show_console_dialog(message, buttons, dfltbutton);
  1179.     if (hotkeys != NULL)
  1180.     {
  1181. for (;;)
  1182. {
  1183.     /*
  1184.      * Get a typed character directly from the user.
  1185.      * Don't use vgetc(), it syncs undo and eats mapped
  1186.      * characters.  Disadvantage: Special keys and mouse
  1187.      * cannot be used here, typeahead is ignored.
  1188.      */
  1189.     cursor_on();
  1190.     out_flush();
  1191.     (void)ui_inchar(buf, 20, -1L);
  1192.     switch (buf[0])
  1193.     {
  1194.     case CR: /* User accepts default option */
  1195.     case NL:
  1196. retval = dfltbutton;
  1197. break;
  1198.     case Ctrl('C'): /* User aborts/cancels */
  1199.     case ESC:
  1200. retval = 0;
  1201. break;
  1202.     default: /* Could be a hotkey? */
  1203. #ifdef UNIX
  1204. if (buf[0] == intr_char)
  1205. {
  1206.     retval = 0; /* another way of cancelling */
  1207.     break;
  1208. }
  1209. #endif
  1210. for (retval = 0; hotkeys[retval]; retval++)
  1211. {
  1212.     if (hotkeys[retval] == TO_LOWER(buf[0]))
  1213. break;
  1214. }
  1215. if (hotkeys[retval])
  1216. {
  1217.     retval++;
  1218.     break;
  1219. }
  1220. /* No hotkey match, so keep waiting */
  1221. continue;
  1222.     }
  1223.     break;
  1224. }
  1225. vim_free(hotkeys);
  1226.     }
  1227.     State = oldState;
  1228. #ifdef USE_MOUSE
  1229.     setmouse();
  1230. #endif
  1231.     --no_wait_return;
  1232.     need_wait_return = FALSE;
  1233.     dont_wait_return = TRUE;     /* don't wait again in main() */
  1234.     return retval;
  1235. }
  1236. char_u *confirm_msg = NULL;     /* ":confirm" message */
  1237. /*
  1238.  * Format the dialog string, and display it at the bottom of
  1239.  * the screen. Return a string of hotkey chars (if defined) for
  1240.  * each 'button'. If a button has no hotkey defined, the string
  1241.  * has the buttons first letter.
  1242.  *
  1243.  * Returns allocated array, or NULL for error.
  1244.  *
  1245.  */
  1246.     static char_u *
  1247. msg_show_console_dialog(message, buttons, dfltbutton)
  1248.     char_u *message;
  1249.     char_u *buttons;
  1250.     int dfltbutton;
  1251. {
  1252.     int len = 0;
  1253.     int lenhotkey = 1; /*first button*/
  1254.     char_u *hotk;
  1255.     char_u *p;
  1256.     char_u *q;
  1257.     char_u *r;
  1258.     /*
  1259.      * First compute how long a string we need to allocate for the message.
  1260.      */
  1261.     r = buttons;
  1262.     while (*r)
  1263.     {
  1264. if (*r == DLG_BUTTON_SEP)
  1265. {
  1266.     len++;     /* 'n' -> ', ' */
  1267.     lenhotkey++;    /* each button needs a hotkey */
  1268. }
  1269. else if (*r == DLG_HOTKEY_CHAR)
  1270. {
  1271.     len++;     /* '&a' -> '[a]' */
  1272. }
  1273. r++;
  1274.     }
  1275.     len += STRLEN(message)
  1276.     + 2 /* for the NL's */
  1277.     + STRLEN(buttons)
  1278.     + 3; /* for the ": " and NUL */
  1279.     lenhotkey++; /* for the NUL */
  1280.     /*
  1281.      * Now allocate and load the strings
  1282.      */
  1283.     vim_free(confirm_msg);
  1284.     confirm_msg = alloc(len);
  1285.     if (confirm_msg == NULL)
  1286. return NULL;
  1287.     *confirm_msg = NUL;
  1288.     hotk = alloc(lenhotkey);
  1289.     if (hotk == NULL)
  1290. return NULL;
  1291.     *confirm_msg = 'n';
  1292.     STRCPY(confirm_msg + 1, message);
  1293.     p = confirm_msg + 1 + STRLEN(message);
  1294.     q = hotk;
  1295.     r = buttons;
  1296.     *q = (char_u)TO_LOWER(*r); /* define lowercase hotkey */
  1297.     *p++ = 'n';
  1298.     while (*r)
  1299.     {
  1300. if (*r == DLG_BUTTON_SEP)
  1301. {
  1302.     *p++ = ',';
  1303.     *p++ = ' ';     /* 'n' -> ', ' */
  1304.     *(++q) = (char_u)TO_LOWER(*(r + 1)); /* next hotkey */
  1305.     if (dfltbutton)
  1306. --dfltbutton;
  1307. }
  1308. else if (*r == DLG_HOTKEY_CHAR)
  1309. {
  1310.     r++;
  1311.     if (*r == DLG_HOTKEY_CHAR) /* duplicate magic = literal */
  1312. *p++ = *r;
  1313.     else
  1314.     {
  1315. /* '&a' -> '[a]' */
  1316. *p++ = (dfltbutton == 1) ? '[' : '(';
  1317. *p++ = *r;
  1318. *p++ = (dfltbutton == 1) ? ']' : ')';
  1319. *q = (char_u)TO_LOWER(*r); /* define lowercase hotkey */
  1320.     }
  1321. }
  1322. else
  1323. {
  1324.     *p++ = *r;     /* everything else copy literally */
  1325. }
  1326. r++;
  1327.     }
  1328.     *p++ = ':';
  1329.     *p++ = ' ';
  1330.     *p = NUL;
  1331.     *(++q) = NUL;
  1332.     display_confirm_msg();
  1333.     return hotk;
  1334. }
  1335. /*
  1336.  * Display the ":confirm" message.  Also called when screen resized.
  1337.  */
  1338.     void
  1339. display_confirm_msg()
  1340. {
  1341.     if (confirm_msg != NULL)
  1342. msg_puts_attr(confirm_msg, hl_attr(HLF_M));
  1343. }
  1344. #endif /* CON_DIALOG */
  1345. #if defined(CON_DIALOG) || defined(GUI_DIALOG)
  1346. /*
  1347.  * Various stock dialogs used throughout Vim when :confirm is used.
  1348.  */
  1349. #if 0 /* not used yet */
  1350.     void
  1351. vim_dialog_ok(type, title, message)
  1352.     int type;
  1353.     char_u *title;
  1354.     char_u *message;
  1355. {
  1356.     (void)do_dialog(type,
  1357.   title == NULL ? (char_u *)"Information" : title,
  1358.   message,
  1359.   (char_u *)"&OK", 1);
  1360. }
  1361. #endif
  1362. #if 0 /* not used yet */
  1363.     int
  1364. vim_dialog_okcancel(type, title, message, dflt)
  1365.     int type;
  1366.     char_u *title;
  1367.     char_u *message;
  1368.     int dflt;
  1369. {
  1370.     if (do_dialog(type,
  1371. title == NULL ? (char_u *)"Confirmation" : title,
  1372. message,
  1373. (char_u *)"&OKn&Cancel", dflt) == 1)
  1374. return VIM_OK;
  1375.     return VIM_CANCEL;
  1376. }
  1377. #endif
  1378.     int
  1379. vim_dialog_yesno(type, title, message, dflt)
  1380.     int type;
  1381.     char_u *title;
  1382.     char_u *message;
  1383.     int dflt;
  1384. {
  1385.     if (do_dialog(type,
  1386. title == NULL ? (char_u *)"Question" : title,
  1387. message,
  1388. (char_u *)"&Yesn&No", dflt) == 1)
  1389. return VIM_YES;
  1390.     return VIM_NO;
  1391. }
  1392.     int
  1393. vim_dialog_yesnocancel(type, title, message, dflt)
  1394.     int type;
  1395.     char_u *title;
  1396.     char_u *message;
  1397.     int dflt;
  1398. {
  1399.     switch (do_dialog(type,
  1400. title == NULL ? (char_u *)"Question" : title,
  1401. message,
  1402. (char_u *)"&Yesn&Non&Cancel", dflt))
  1403.     {
  1404. case 1: return VIM_YES;
  1405. case 2: return VIM_NO;
  1406.     }
  1407.     return VIM_CANCEL;
  1408. }
  1409.     int
  1410. vim_dialog_yesnoallcancel(type, title, message, dflt)
  1411.     int type;
  1412.     char_u *title;
  1413.     char_u *message;
  1414.     int dflt;
  1415. {
  1416.     switch (do_dialog(type,
  1417. title == NULL ? (char_u *)"Question" : title,
  1418. message,
  1419. (char_u *)"&Yesn&NonSave &Alln&Discard Alln&Cancel", dflt))
  1420.     {
  1421. case 1: return VIM_YES;
  1422. case 2: return VIM_NO;
  1423. case 3: return VIM_ALL;
  1424. case 4: return VIM_DISCARDALL;
  1425.     }
  1426.     return VIM_CANCEL;
  1427. }
  1428. #endif /* GUI_DIALOG || CON_DIALOG */
  1429. #if defined(USE_BROWSE) || defined(PROTO)
  1430. /*
  1431.  * Generic browse function.  Calls gui_mch_browse() when possible.
  1432.  * Later this may pop-up a non-GUI file selector (external command?).
  1433.  */
  1434.     char_u *
  1435. do_browse(saving, title, dflt, ext, initdir, filter, buf)
  1436.     int saving; /* write action */
  1437.     char_u *title; /* title for the window */
  1438.     char_u *dflt; /* default file name */
  1439.     char_u *ext; /* extension added */
  1440.     char_u *initdir; /* initial directory, NULL for current dir */
  1441.     char_u *filter; /* file name filter */
  1442.     BUF *buf; /* buffer to read/write for */
  1443. {
  1444.     char_u *fname;
  1445.     static char_u *last_dir = NULL;    /* last used directory */
  1446.     char_u *tofree = NULL;
  1447.     /* Must turn off browse straight away, or :so autocommands will get the
  1448.      * flag too!  */
  1449.     browse = FALSE;
  1450.     if (title == NULL)
  1451.     {
  1452. if (saving)
  1453.     title = (char_u *)"Save File dialog";
  1454. else
  1455.     title = (char_u *)"Open File dialog";
  1456.     }
  1457.     /* When no directory specified, use buffer dir, last dir or current dir */
  1458.     if (initdir == NULL || *initdir == NUL)
  1459.     {
  1460. /* When saving or 'browsedir' is "buffer", use buffer fname */
  1461. if ((saving || *p_bsdir == 'b') && buf != NULL && buf->b_ffname != NULL)
  1462. {
  1463.     dflt = gettail(curbuf->b_ffname);
  1464.     tofree = vim_strsave(curbuf->b_ffname);
  1465.     if (tofree != NULL)
  1466.     {
  1467. initdir = tofree;
  1468. *gettail(initdir) = NUL;
  1469.     }
  1470. }
  1471. /* When 'browsedir' is "last", use dir from last browse */
  1472. else if (*p_bsdir == 'l')
  1473.     initdir = last_dir;
  1474. /* When 'browsedir is "current", use current directory.  This is the
  1475.  * default already, leave initdir empty. */
  1476.     }
  1477. # ifdef USE_GUI
  1478.     if (gui.in_use) /* when this changes, also adjust f_has()! */
  1479.     {
  1480. fname = gui_mch_browse(saving, title, dflt, ext, initdir, filter);
  1481.     }
  1482.     else
  1483. # endif
  1484.     {
  1485. /* TODO: non-GUI file selector here */
  1486. fname = NULL;
  1487.     }
  1488.     /* keep the directory for next time */
  1489.     if (fname != NULL)
  1490.     {
  1491. vim_free(last_dir);
  1492. last_dir = vim_strsave(fname);
  1493. if (last_dir != NULL)
  1494. {
  1495.     *gettail(last_dir) = NUL;
  1496.     if (*last_dir == NUL)
  1497.     {
  1498. /* filename only returned, must be in current dir*/
  1499. vim_free(last_dir);
  1500. last_dir = alloc(MAXPATHL);
  1501. if (last_dir != NULL)
  1502.     mch_dirname(last_dir, MAXPATHL);
  1503.     }
  1504. }
  1505.     }
  1506.     vim_free(tofree);
  1507.     return fname;
  1508. }
  1509. #endif