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

编辑器/阅读器

开发平台:

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.  * ui.c: functions that handle the user interface.
  10.  * 1. Keyboard input stuff, and a bit of windowing stuff.  These are called
  11.  *    before the machine specific stuff (mch_*) so that we can call the GUI
  12.  *    stuff instead if the GUI is running.
  13.  * 2. Clipboard stuff.
  14.  * 3. Input buffer stuff.
  15.  */
  16. #include "vim.h"
  17.     void
  18. ui_write(s, len)
  19.     char_u  *s;
  20.     int     len;
  21. {
  22. #ifdef USE_GUI
  23.     if (gui.in_use && !gui.dying)
  24.     {
  25. gui_write(s, len);
  26. if (p_wd)
  27.     gui_wait_for_chars(p_wd);
  28. return;
  29.     }
  30. #endif
  31. #ifndef NO_CONSOLE
  32.     /* Don't output anything in silent mode ("ex -s") */
  33.     if (!silent_mode)
  34. mch_write(s, len);
  35. #endif
  36. }
  37. /*
  38.  * ui_inchar(): low level input funcion.
  39.  * Get a characters from the keyboard.
  40.  * Return the number of characters that are available.
  41.  * If wtime == 0 do not wait for characters.
  42.  * If wtime == -1 wait forever for characters.
  43.  * If wtime > 0 wait wtime milliseconds for a character.
  44.  */
  45.     int
  46. ui_inchar(buf, maxlen, wtime)
  47.     char_u  *buf;
  48.     int     maxlen;
  49.     long    wtime;     /* don't use "time", MIPS cannot handle it */
  50. {
  51. #ifdef NO_CONSOLE
  52.     /* Don't wait for character input when the window hasn't been opened yet.
  53.      * Must return something, otherwise we'll loop forever.  */
  54.     if (!gui.in_use || gui.starting)
  55.     {
  56. buf[0] = CR;
  57. return 1;
  58.     }
  59. #endif
  60. #ifdef USE_GUI
  61.     if (gui.in_use)
  62.     {
  63. if (!gui_wait_for_chars(wtime))
  64.     return 0;
  65. return read_from_input_buf(buf, (long)maxlen);
  66.     }
  67. #endif
  68. #ifndef NO_CONSOLE
  69.     return mch_inchar(buf, maxlen, wtime);
  70. #endif
  71. }
  72. /*
  73.  * return non-zero if a character is available
  74.  */
  75.     int
  76. ui_char_avail()
  77. {
  78. #ifdef USE_GUI
  79.     if (gui.in_use)
  80.     {
  81. gui_mch_update();
  82. return !vim_is_input_buf_empty();
  83.     }
  84. #endif
  85. #ifndef NO_CONSOLE
  86.     return mch_char_avail();
  87. #else
  88.     return 0;
  89. #endif
  90. }
  91. /*
  92.  * Delay for the given number of milliseconds. If ignoreinput is FALSE then we
  93.  * cancel the delay if a key is hit.
  94.  */
  95.     void
  96. ui_delay(msec, ignoreinput)
  97.     long msec;
  98.     int ignoreinput;
  99. {
  100. #ifdef USE_GUI
  101.     if (gui.in_use && !ignoreinput)
  102. gui_wait_for_chars(msec);
  103.     else
  104. #endif
  105. mch_delay(msec, ignoreinput);
  106. }
  107. /*
  108.  * If the machine has job control, use it to suspend the program,
  109.  * otherwise fake it by starting a new shell.
  110.  * When running the GUI iconify the window.
  111.  */
  112.     void
  113. ui_suspend()
  114. {
  115. #ifdef USE_GUI
  116.     if (gui.in_use)
  117.     {
  118. gui_mch_iconify();
  119. return;
  120.     }
  121. #endif
  122.     mch_suspend();
  123. }
  124. /*
  125.  * When the OS can't really suspend, call this function to start a shell.
  126.  */
  127.     void
  128. suspend_shell()
  129. {
  130.     MSG_PUTS("new shell startedn");
  131.     (void)mch_call_shell(NULL, SHELL_COOKED);
  132.     need_check_timestamps = TRUE;
  133. }
  134.     int
  135. ui_can_restore_title()
  136. {
  137. #ifdef USE_GUI
  138.     /*
  139.      * If GUI is (going to be) used, we can always set the window title.
  140.      * Saves a bit of time, because the X11 display server does not need to be
  141.      * contacted.
  142.      */
  143.     if (gui.starting || gui.in_use)
  144. return TRUE;
  145. #endif
  146.     return mch_can_restore_title();
  147. }
  148.     int
  149. ui_can_restore_icon()
  150. {
  151. #ifdef USE_GUI
  152.     /*
  153.      * If GUI is (going to be) used, we can always set the icon name.
  154.      * Saves a bit of time, because the X11 display server does not need to be
  155.      * contacted.
  156.      */
  157.     if (gui.starting || gui.in_use)
  158. return TRUE;
  159. #endif
  160.     return mch_can_restore_icon();
  161. }
  162. /*
  163.  * Try to get the current window size. Put the result in Rows and Columns.
  164.  * Return OK when size could be determined, FAIL otherwise.
  165.  */
  166.     int
  167. ui_get_winsize()
  168. {
  169.     int     retval;
  170. #ifdef USE_GUI
  171.     if (gui.in_use)
  172. retval = gui_get_winsize();
  173.     else
  174. #endif
  175. retval = mch_get_winsize();
  176.     /* adjust the default for 'lines' and 'columns' */
  177.     if (retval == OK)
  178.     {
  179. set_number_default("lines", Rows);
  180. set_number_default("columns", Columns);
  181.     }
  182.     return retval;
  183. }
  184. /*
  185.  * Set the size of the window according to Rows and Columns, if possible.
  186.  */
  187.     void
  188. ui_set_winsize()
  189. {
  190. #ifdef USE_GUI
  191.     if (gui.in_use)
  192. gui_set_winsize(
  193. #ifdef WIN32
  194. TRUE
  195. #else
  196. FALSE
  197. #endif
  198. );
  199.     else
  200. #endif
  201. mch_set_winsize();
  202. }
  203.     void
  204. ui_breakcheck()
  205. {
  206. #ifdef USE_GUI
  207.     if (gui.in_use)
  208. gui_mch_update();
  209.     else
  210. #endif /* USE_GUI */
  211. mch_breakcheck();
  212. }
  213. /*****************************************************************************
  214.  * Functions for copying and pasting text between applications.
  215.  * This is always included in a GUI version, but may also be included when the
  216.  * clipboard and mouse is available to a terminal version such as xterm.
  217.  * Note: there are some more functions in ops.c that handle selection stuff.
  218.  */
  219. #ifdef USE_CLIPBOARD
  220. static void clip_invert_area __ARGS((int, int, int, int));
  221. static void clip_yank_non_visual_selection __ARGS((int, int, int, int));
  222. static void clip_get_word_boundaries __ARGS((VimClipboard *, int, int));
  223. static int  clip_get_line_end __ARGS((int));
  224. static void clip_update_non_visual_selection __ARGS((VimClipboard *, int, int,
  225.     int, int));
  226. #define char_class(c) (c <= ' ' ? ' ' : vim_iswordc(c))
  227. /*
  228.  * Selection stuff using Visual mode, for cutting and pasting text to other
  229.  * windows.
  230.  */
  231. /*
  232.  * Call this to initialise the clipboard.  Pass it FALSE if the clipboard code
  233.  * is included, but the clipboard can not be used, or TRUE if the clipboard can
  234.  * be used.  Eg unix may call this with FALSE, then call it again with TRUE if
  235.  * the GUI starts.
  236.  */
  237.     void
  238. clip_init(can_use)
  239.     int     can_use;
  240. {
  241.     clipboard.available = can_use;
  242.     clipboard.owned = FALSE;
  243.     clipboard.start.lnum = 0;
  244.     clipboard.start.col = 0;
  245.     clipboard.end.lnum = 0;
  246.     clipboard.end.col = 0;
  247.     clipboard.state = SELECT_CLEARED;
  248. }
  249. /*
  250.  * Check whether the VIsual area has changed, and if so try to become the owner
  251.  * of the selection, and free any old converted selection we may still have
  252.  * lying around.  If the VIsual mode has ended, make a copy of what was
  253.  * selected so we can still give it to others. Will probably have to make sure
  254.  * this is called whenever VIsual mode is ended.
  255.  */
  256.     void
  257. clip_update_selection()
  258. {
  259.     FPOS    start, end;
  260.     /* If visual mode is only due to a redo command ("."), then ignore it */
  261.     if (!redo_VIsual_busy && VIsual_active)
  262.     {
  263. if (lt(VIsual, curwin->w_cursor))
  264. {
  265.     start = VIsual;
  266.     end = curwin->w_cursor;
  267. }
  268. else
  269. {
  270.     start = curwin->w_cursor;
  271.     end = VIsual;
  272. }
  273. if (!equal(clipboard.start, start) || !equal(clipboard.end, end)
  274.     || clipboard.vmode != VIsual_mode)
  275. {
  276.     clip_clear_selection();
  277.     clipboard.start = start;
  278.     clipboard.end = end;
  279.     clipboard.vmode = VIsual_mode;
  280.     clip_free_selection();
  281.     clip_own_selection();
  282.     clip_mch_set_selection();
  283. }
  284.     }
  285. }
  286.     void
  287. clip_own_selection()
  288. {
  289.     /*
  290.      * Also want to check somehow that we are reading from the keyboard rather
  291.      * than a mapping etc.
  292.      */
  293.     if (!clipboard.owned)
  294. clipboard.owned = (clip_mch_own_selection() == OK);
  295. }
  296.     void
  297. clip_lose_selection()
  298. {
  299.     clip_free_selection();
  300.     clipboard.owned = FALSE;
  301.     clip_clear_selection();
  302.     clip_mch_lose_selection();
  303. }
  304.     void
  305. clip_copy_selection()
  306. {
  307.     if (VIsual_active)
  308.     {
  309. if (vim_strchr(p_guioptions, GO_ASEL) == NULL)
  310.     clip_update_selection();
  311. clip_free_selection();
  312. clip_own_selection();
  313. if (clipboard.owned)
  314.     clip_get_selection();
  315. clip_mch_set_selection();
  316.     }
  317. }
  318.     void
  319. clip_auto_select()
  320. {
  321.     if (vim_strchr(p_guioptions, GO_ASEL) != NULL)
  322. clip_copy_selection();
  323. }
  324. #ifdef USE_GUI
  325. /*
  326.  * Stuff for general mouse selection, without using Visual mode.
  327.  */
  328. static int clip_compare_pos __ARGS((int row1, int col1, int row2, int col2));
  329. /*
  330.  * Compare two screen positions ala strcmp()
  331.  */
  332.     static int
  333. clip_compare_pos(row1, col1, row2, col2)
  334.     int     row1;
  335.     int     col1;
  336.     int     row2;
  337.     int     col2;
  338. {
  339.     if (row1 > row2) return( 1);
  340.     if (row1 < row2) return(-1);
  341.     if (col1 > col2) return( 1);
  342.     if (col1 < col2) return(-1);
  343.      return( 0);
  344. }
  345. /*
  346.  * Start out the selection
  347.  */
  348. /* ARGSUSED */
  349.     void
  350. clip_start_selection(button, x, y, repeated_click, modifiers)
  351.     int     button;
  352.     int     x;
  353.     int     y;
  354.     int     repeated_click;
  355.     int_u   modifiers;
  356. {
  357.     VimClipboard    *cb = &clipboard;
  358.     if (cb->state == SELECT_DONE)
  359. clip_clear_selection();
  360.     cb->start.lnum  = check_row(Y_2_ROW(y));
  361.     cb->start.col   = check_col(X_2_COL(x));
  362.     cb->end     = cb->start;
  363.     cb->origin_row  = (short_u)cb->start.lnum;
  364.     cb->state     = SELECT_IN_PROGRESS;
  365.     if (repeated_click)
  366.     {
  367. if (++(cb->mode) > SELECT_MODE_LINE)
  368.     cb->mode = SELECT_MODE_CHAR;
  369.     }
  370.     else
  371. cb->mode = SELECT_MODE_CHAR;
  372. #ifdef USE_GUI
  373.     /* clear the cursor until the selection is made */
  374.     gui_undraw_cursor();
  375. #endif
  376.     switch (cb->mode)
  377.     {
  378. case SELECT_MODE_CHAR:
  379.     cb->origin_start_col = cb->start.col;
  380.     cb->word_end_col = clip_get_line_end((int)cb->start.lnum);
  381.     break;
  382. case SELECT_MODE_WORD:
  383.     clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col);
  384.     cb->origin_start_col = cb->word_start_col;
  385.     cb->origin_end_col  = cb->word_end_col;
  386.     clip_invert_area((int)cb->start.lnum, cb->word_start_col,
  387.     (int)cb->end.lnum, cb->word_end_col);
  388.     cb->start.col = cb->word_start_col;
  389.     cb->end.col   = cb->word_end_col;
  390.     break;
  391. case SELECT_MODE_LINE:
  392.     clip_invert_area((int)cb->start.lnum, 0, (int)cb->start.lnum,
  393.     (int)Columns);
  394.     cb->start.col = 0;
  395.     cb->end.col   = Columns;
  396.     break;
  397.     }
  398.     cb->prev = cb->start;
  399. #ifdef DEBUG_SELECTION
  400.     printf("Selection started at (%u,%u)n", cb->start.lnum, cb->start.col);
  401. #endif
  402. }
  403. /*
  404.  * Continue processing the selection
  405.  */
  406. /* ARGSUSED */
  407.     void
  408. clip_process_selection(button, x, y, repeated_click, modifiers)
  409.     int     button;
  410.     int     x;
  411.     int     y;
  412.     int     repeated_click;
  413.     int_u   modifiers;
  414. {
  415.     VimClipboard    *cb = &clipboard;
  416.     int     row;
  417.     int_u     col;
  418.     int     diff;
  419.     if (button == MOUSE_RELEASE)
  420.     {
  421. /* Check to make sure we have something selected */
  422. if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
  423. {
  424. #ifdef USE_GUI
  425.     if (gui.in_use)
  426. gui_update_cursor(FALSE, FALSE);
  427. #endif
  428.     cb->state = SELECT_CLEARED;
  429.     return;
  430. }
  431. #ifdef DEBUG_SELECTION
  432. printf("Selection ended: (%u,%u) to (%u,%u)n", cb->start.lnum,
  433. cb->start.col, cb->end.lnum, cb->end.col);
  434. #endif
  435. clip_free_selection();
  436. clip_own_selection();
  437. clip_yank_non_visual_selection((int)cb->start.lnum, cb->start.col,
  438.       (int)cb->end.lnum, cb->end.col);
  439. clip_mch_set_selection();
  440. #ifdef USE_GUI
  441. if (gui.in_use)
  442.     gui_update_cursor(FALSE, FALSE);
  443. #endif
  444. cb->state = SELECT_DONE;
  445. return;
  446.     }
  447.     row = check_row(Y_2_ROW(y));
  448.     col = check_col(X_2_COL(x));
  449.     if (col == cb->prev.col && row == cb->prev.lnum)
  450. return;
  451.     /*
  452.      * When extending the selection with the right mouse button, swap the
  453.      * start and end if the position is before half the selection
  454.      */
  455.     if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
  456.     {
  457. /*
  458.  * If the click is before the start, or the click is inside the
  459.  * selection and the start is the closest side, set the origin to the
  460.  * end of the selection.
  461.  */
  462. if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0
  463. || (clip_compare_pos(row, col,
  464.    (int)cb->end.lnum, cb->end.col) < 0
  465.     && (((cb->start.lnum == cb->end.lnum
  466.     && cb->end.col - col > col - cb->start.col))
  467. || ((diff = (cb->end.lnum - row) -
  468.    (row - cb->start.lnum)) > 0
  469.     || (diff == 0 && col < (cb->start.col +
  470.  cb->end.col) / 2)))))
  471. {
  472.     cb->origin_row = (short_u)cb->end.lnum;
  473.     cb->origin_start_col = cb->end.col - 1;
  474.     cb->origin_end_col = cb->end.col;
  475. }
  476. else
  477. {
  478.     cb->origin_row = (short_u)cb->start.lnum;
  479.     cb->origin_start_col = cb->start.col;
  480.     cb->origin_end_col = cb->start.col;
  481. }
  482. if (cb->mode == SELECT_MODE_WORD)
  483. {
  484.     clip_get_word_boundaries(cb, cb->origin_row, cb->origin_start_col);
  485.     cb->origin_start_col = cb->word_start_col;
  486.     cb->origin_end_col  = cb->word_end_col;
  487. }
  488.     }
  489.     /* set state, for when using the right mouse button */
  490.     cb->state = SELECT_IN_PROGRESS;
  491. #ifdef DEBUG_SELECTION
  492.     printf("Selection extending to (%d,%d)n", row, col);
  493. #endif
  494.     switch (cb->mode)
  495.     {
  496. case SELECT_MODE_CHAR:
  497.     /* If we're on a different line, find where the line ends */
  498.     if (row != cb->prev.lnum)
  499. cb->word_end_col = clip_get_line_end(row);
  500.     /* See if we are before or after the origin of the selection */
  501.     if (clip_compare_pos(row, col, cb->origin_row,
  502.    cb->origin_start_col) >= 0)
  503.     {
  504. if (col >= (int)cb->word_end_col)
  505.     clip_update_non_visual_selection(cb, cb->origin_row,
  506.     cb->origin_start_col, row, (int)Columns);
  507. else
  508.     clip_update_non_visual_selection(cb, cb->origin_row,
  509.     cb->origin_start_col, row, col + 1);
  510.     }
  511.     else
  512.     {
  513. if (col >= (int)cb->word_end_col)
  514.     clip_update_non_visual_selection(cb, row, cb->word_end_col,
  515.     cb->origin_row, cb->origin_start_col + 1);
  516. else
  517.     clip_update_non_visual_selection(cb, row, col,
  518.     cb->origin_row, cb->origin_start_col + 1);
  519.     }
  520.     break;
  521. case SELECT_MODE_WORD:
  522.     /* If we are still within the same word, do nothing */
  523.     if (row == cb->prev.lnum && col >= (int)cb->word_start_col
  524.     && col < (int)cb->word_end_col)
  525. return;
  526.     /* Get new word boundaries */
  527.     clip_get_word_boundaries(cb, row, col);
  528.     /* Handle being after the origin point of selection */
  529.     if (clip_compare_pos(row, col, cb->origin_row,
  530.     cb->origin_start_col) >= 0)
  531. clip_update_non_visual_selection(cb, cb->origin_row,
  532. cb->origin_start_col, row, cb->word_end_col);
  533.     else
  534. clip_update_non_visual_selection(cb, row, cb->word_start_col,
  535. cb->origin_row, cb->origin_end_col);
  536.     break;
  537. case SELECT_MODE_LINE:
  538.     if (row == cb->prev.lnum)
  539. return;
  540.     if (clip_compare_pos(row, col, cb->origin_row,
  541.     cb->origin_start_col) >= 0)
  542. clip_update_non_visual_selection(cb, cb->origin_row, 0, row,
  543. (int)Columns);
  544.     else
  545. clip_update_non_visual_selection(cb, row, 0, cb->origin_row,
  546. (int)Columns);
  547.     break;
  548.     }
  549.     cb->prev.lnum = row;
  550.     cb->prev.col  = col;
  551. #ifdef DEBUG_SELECTION
  552. printf("Selection is: (%u,%u) to (%u,%u)n", cb->start.lnum,
  553. cb->start.col, cb->end.lnum, cb->end.col);
  554. #endif
  555. }
  556. /*
  557.  * Called after an Expose event to redraw the selection
  558.  */
  559.     void
  560. clip_redraw_selection(x, y, w, h)
  561.     int     x;
  562.     int     y;
  563.     int     w;
  564.     int     h;
  565. {
  566.     VimClipboard    *cb = &clipboard;
  567.     int     row1, col1, row2, col2;
  568.     int     row;
  569.     int     start;
  570.     int     end;
  571.     if (cb->state == SELECT_CLEARED)
  572. return;
  573. #ifdef USE_GUI     /* TODO: how do we invert for non-GUI versions? */
  574.     row1 = check_row(Y_2_ROW(y));
  575.     col1 = check_col(X_2_COL(x));
  576.     row2 = check_row(Y_2_ROW(y + h - 1));
  577.     col2 = check_col(X_2_COL(x + w - 1));
  578.     /* Limit the rows that need to be re-drawn */
  579.     if (cb->start.lnum > row1)
  580. row1 = cb->start.lnum;
  581.     if (cb->end.lnum < row2)
  582. row2 = cb->end.lnum;
  583.     /* Look at each row that might need to be re-drawn */
  584.     for (row = row1; row <= row2; row++)
  585.     {
  586. /* For the first selection row, use the starting selection column */
  587. if (row == cb->start.lnum)
  588.     start = cb->start.col;
  589. else
  590.     start = 0;
  591. /* For the last selection row, use the ending selection column */
  592. if (row == cb->end.lnum)
  593.     end = cb->end.col;
  594. else
  595.     end = Columns;
  596. if (col1 > start)
  597.     start = col1;
  598. if (col2 < end)
  599.     end = col2 + 1;
  600. if (end > start)
  601.     gui_mch_invert_rectangle(row, start, 1, end - start);
  602.     }
  603. #endif
  604. }
  605. /*
  606.  * Redraw the selection if character at "row,col" is inside of it.
  607.  */
  608.     void
  609. clip_may_redraw_selection(row, col)
  610.     int row, col;
  611. {
  612.     if (clipboard.state != SELECT_CLEARED
  613.     && ((row == clipboard.start.lnum
  614.     && col >= (int)clipboard.start.col)
  615. || row > clipboard.start.lnum)
  616.     && ((row == clipboard.end.lnum
  617.     && col < (int)clipboard.end.col)
  618. || row < clipboard.end.lnum))
  619. clip_invert_area(row, col, row, col + 1);
  620. }
  621. /*
  622.  * Called from outside to clear selected region from the display
  623.  */
  624.     void
  625. clip_clear_selection()
  626. {
  627.     VimClipboard    *cb = &clipboard;
  628.     if (cb->state == SELECT_CLEARED)
  629. return;
  630.     clip_invert_area((int)cb->start.lnum, cb->start.col, (int)cb->end.lnum,
  631.     cb->end.col);
  632.     cb->state = SELECT_CLEARED;
  633. }
  634. /*
  635.  * Clear the selection if any lines from "row1" to "row2" are inside of it.
  636.  */
  637.     void
  638. clip_may_clear_selection(row1, row2)
  639.     int row1, row2;
  640. {
  641.     if (clipboard.state == SELECT_DONE
  642.     && row2 >= clipboard.start.lnum
  643.     && row1 <= clipboard.end.lnum)
  644. clip_clear_selection();
  645. }
  646. /*
  647.  * Called before the screen is scrolled up or down.  Adjusts the line numbers
  648.  * of the selection.  Call with big number when clearing the screen.
  649.  */
  650.     void
  651. clip_scroll_selection(rows)
  652.     int     rows; /* negative for scroll down */
  653. {
  654.     int     lnum;
  655.     if (clipboard.state == SELECT_CLEARED)
  656. return;
  657.     lnum = clipboard.start.lnum - rows;
  658.     if (lnum <= 0)
  659. clipboard.start.lnum = 0;
  660.     else if (lnum >= screen_Rows) /* scrolled off of the screen */
  661. clipboard.state = SELECT_CLEARED;
  662.     else
  663. clipboard.start.lnum = lnum;
  664.     lnum = clipboard.end.lnum - rows;
  665.     if (lnum < 0) /* scrolled off of the screen */
  666. clipboard.state = SELECT_CLEARED;
  667.     else if (lnum >= screen_Rows)
  668. clipboard.end.lnum = screen_Rows - 1;
  669.     else
  670. clipboard.end.lnum = lnum;
  671. }
  672. /*
  673.  * Invert a region of the display between a starting and ending row and column
  674.  */
  675.     static void
  676. clip_invert_area(row1, col1, row2, col2)
  677.     int     row1;
  678.     int     col1;
  679.     int     row2;
  680.     int     col2;
  681. {
  682. #ifdef USE_GUI     /* TODO: how do we invert for non-GUI versions? */
  683.     /* Swap the from and to positions so the from is always before */
  684.     if (clip_compare_pos(row1, col1, row2, col2) > 0)
  685.     {
  686. int tmp_row, tmp_col;
  687. tmp_row = row1;
  688. tmp_col = col1;
  689. row1 = row2;
  690. col1 = col2;
  691. row2 = tmp_row;
  692. col2 = tmp_col;
  693.     }
  694.     /* If all on the same line, do it the easy way */
  695.     if (row1 == row2)
  696.     {
  697. gui_mch_invert_rectangle(row1, col1, 1, col2 - col1);
  698. return;
  699.     }
  700.     /* Handle a piece of the first line */
  701.     if (col1 > 0)
  702.     {
  703. gui_mch_invert_rectangle(row1, col1, 1, (int)Columns - col1);
  704. row1++;
  705.     }
  706.     /* Handle a piece of the last line */
  707.     if (col2 < Columns - 1)
  708.     {
  709. gui_mch_invert_rectangle(row2, 0, 1, col2);
  710. row2--;
  711.     }
  712.     /* Handle the rectangle thats left */
  713.     if (row2 >= row1)
  714. gui_mch_invert_rectangle(row1, 0, row2 - row1 + 1, (int)Columns);
  715. #endif
  716. }
  717. /*
  718.  * Yank the currently selected area into the special selection buffer so it
  719.  * will be available for pasting.
  720.  */
  721.     static void
  722. clip_yank_non_visual_selection(row1, col1, row2, col2)
  723.     int     row1;
  724.     int     col1;
  725.     int     row2;
  726.     int     col2;
  727. {
  728.     char_u  *buffer;
  729.     char_u  *bufp;
  730.     int     row;
  731.     int     start_col;
  732.     int     end_col;
  733.     int     line_end_col;
  734.     int     add_newline_flag = FALSE;
  735.     /*
  736.      * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
  737.      */
  738.     if (row1 > row2)
  739.     {
  740. row = row1; row1 = row2; row2 = row;
  741. row = col1; col1 = col2; col2 = row;
  742.     }
  743.     else if (row1 == row2 && col1 > col2)
  744.     {
  745. row = col1; col1 = col2; col2 = row;
  746.     }
  747.     /* Create a temporary buffer for storing the text */
  748.     buffer = lalloc((row2 - row1 + 1) * Columns + 1, TRUE);
  749.     if (buffer == NULL)     /* out of memory */
  750. return;
  751.     /* Process each row in the selection */
  752.     for (bufp = buffer, row = row1; row <= row2; row++)
  753.     {
  754. if (row == row1)
  755.     start_col = col1;
  756. else
  757.     start_col = 0;
  758. if (row == row2)
  759.     end_col = col2;
  760. else
  761.     end_col = Columns;
  762. line_end_col = clip_get_line_end(row);
  763. /* See if we need to nuke some trailing whitespace */
  764. if (end_col >= Columns && (row < row2 || end_col > line_end_col))
  765. {
  766.     /* Get rid of trailing whitespace */
  767.     end_col = line_end_col;
  768.     if (end_col < start_col)
  769. end_col = start_col;
  770.     /* If the last line extended to the end, add an extra newline */
  771.     if (row == row2)
  772. add_newline_flag = TRUE;
  773. }
  774. /* If after the first row, we need to always add a newline */
  775. if (row > row1)
  776.     *bufp++ = NL;
  777. if (row < screen_Rows && end_col <= screen_Columns)
  778. {
  779.     STRNCPY(bufp, &LinePointers[row][start_col], end_col - start_col);
  780.     bufp += end_col - start_col;
  781. }
  782.     }
  783.     /* Add a newline at the end if the selection ended there */
  784.     if (add_newline_flag)
  785. *bufp++ = NL;
  786.     clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer));
  787.     vim_free(buffer);
  788. }
  789. /*
  790.  * Find the starting and ending positions of the word at the given row and
  791.  * column.
  792.  */
  793.     static void
  794. clip_get_word_boundaries(cb, row, col)
  795.     VimClipboard    *cb;
  796.     int     row;
  797.     int     col;
  798. {
  799.     char    start_class;
  800.     int     temp_col;
  801.     if (row >= screen_Rows || col >= screen_Columns)
  802. return;
  803.     start_class = char_class(LinePointers[row][col]);
  804.     temp_col = col;
  805.     for ( ; temp_col > 0; temp_col--)
  806. if (char_class(LinePointers[row][temp_col - 1]) != start_class)
  807.     break;
  808.     cb->word_start_col = temp_col;
  809.     temp_col = col;
  810.     for ( ; temp_col < screen_Columns; temp_col++)
  811. if (char_class(LinePointers[row][temp_col]) != start_class)
  812.     break;
  813.     cb->word_end_col = temp_col;
  814. #ifdef DEBUG_SELECTION
  815.     printf("Current word: col %u to %un", cb->word_start_col,
  816.     cb->word_end_col);
  817. #endif
  818. }
  819. /*
  820.  * Find the column position for the last non-whitespace character on the given
  821.  * line.
  822.  */
  823.     static int
  824. clip_get_line_end(row)
  825.     int row;
  826. {
  827.     int     i;
  828.     if (row >= screen_Rows)
  829. return 0;
  830.     for (i = screen_Columns; i > 0; i--)
  831. if (LinePointers[row][i - 1] != ' ')
  832.     break;
  833.     return i;
  834. }
  835. /*
  836.  * Update the currently selected region by adding and/or subtracting from the
  837.  * beginning or end and inverting the changed area(s).
  838.  */
  839.     static void
  840. clip_update_non_visual_selection(cb, row1, col1, row2, col2)
  841.     VimClipboard    *cb;
  842.     int     row1;
  843.     int     col1;
  844.     int     row2;
  845.     int     col2;
  846. {
  847.     /* See if we changed at the beginning of the selection */
  848.     if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
  849.     {
  850. clip_invert_area(row1, col1, (int)cb->start.lnum, cb->start.col);
  851. cb->start.lnum = row1;
  852. cb->start.col  = col1;
  853.     }
  854.     /* See if we changed at the end of the selection */
  855.     if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
  856.     {
  857. clip_invert_area(row2, col2, (int)cb->end.lnum, cb->end.col);
  858. cb->end.lnum = row2;
  859. cb->end.col  = col2;
  860.     }
  861. }
  862. #else /* If USE_GUI not defined */
  863. /*
  864.  * Called from outside to clear selected region from the display
  865.  */
  866.     void
  867. clip_clear_selection()
  868. {
  869.     /*
  870.      * Dummy version for now... the point of this code is to set the selected
  871.      * area back to "normal" colour if we are clearing the selection. As we
  872.      * don't have GUI-style mouse selection, we can ignore this for now.
  873.      * Eventually we could actually invert the area in a terminal by redrawing
  874.      * in reverse mode, but we don't do that yet.
  875.      */
  876.     clipboard.state = SELECT_CLEARED;
  877. }
  878. #endif /* USE_GUI */
  879. #endif /* USE_CLIPBOARD */
  880. /*****************************************************************************
  881.  * Functions that handle the input buffer.
  882.  * This is used for any GUI version, and the unix terminal version.
  883.  *
  884.  * For Unix, the input characters are buffered to be able to check for a
  885.  * CTRL-C.  This should be done with signals, but I don't know how to do that
  886.  * in a portable way for a tty in RAW mode.
  887.  */
  888. #if defined(UNIX) || defined(USE_GUI) || defined(OS2) || defined(VMS)
  889. /*
  890.  * Internal typeahead buffer.  Includes extra space for long key code
  891.  * descriptions which would otherwise overflow.  The buffer is considered full
  892.  * when only this extra space (or part of it) remains.
  893.  */
  894. #define INBUFLEN 250
  895. static char_u inbuf[INBUFLEN + MAX_KEY_CODE_LEN];
  896. static int inbufcount = 0;     /* number of chars in inbuf[] */
  897. /*
  898.  * vim_is_input_buf_full(), vim_is_input_buf_empty(), add_to_input_buf(), and
  899.  * trash_input_buf() are functions for manipulating the input buffer.  These
  900.  * are used by the gui_* calls when a GUI is used to handle keyboard input.
  901.  */
  902.     int
  903. vim_is_input_buf_full()
  904. {
  905.     return (inbufcount >= INBUFLEN);
  906. }
  907.     int
  908. vim_is_input_buf_empty()
  909. {
  910.     return (inbufcount == 0);
  911. }
  912.     int
  913. vim_free_in_input_buf()
  914. {
  915.     return (INBUFLEN - inbufcount);
  916. }
  917. /* Add the given bytes to the input buffer */
  918.     void
  919. add_to_input_buf(s, len)
  920.     char_u  *s;
  921.     int     len;
  922. {
  923.     if (inbufcount + len > INBUFLEN + MAX_KEY_CODE_LEN)
  924. return;     /* Shouldn't ever happen! */
  925.     while (len--)
  926. inbuf[inbufcount++] = *s++;
  927. }
  928. /* Remove everything from the input buffer.  Called when ^C is found */
  929.     void
  930. trash_input_buf()
  931. {
  932.     inbufcount = 0;
  933. }
  934. /*
  935.  * Read as much data from the input buffer as possible up to maxlen, and store
  936.  * it in buf.
  937.  * Note: this function used to be Read() in unix.c
  938.  */
  939.     int
  940. read_from_input_buf(buf, maxlen)
  941.     char_u  *buf;
  942.     long    maxlen;
  943. {
  944.     if (inbufcount == 0) /* if the buffer is empty, fill it */
  945. fill_input_buf(TRUE);
  946.     if (maxlen > inbufcount)
  947. maxlen = inbufcount;
  948.     mch_memmove(buf, inbuf, (size_t)maxlen);
  949.     inbufcount -= maxlen;
  950.     if (inbufcount)
  951. mch_memmove(inbuf, inbuf + maxlen, (size_t)inbufcount);
  952.     return (int)maxlen;
  953. }
  954.     void
  955. fill_input_buf(exit_on_error)
  956.     int exit_on_error;
  957. {
  958. #if defined(UNIX) || defined(OS2) || defined(VMS)
  959.     int len;
  960.     int try;
  961.     static int did_read_something = FALSE;
  962. #endif
  963. #ifdef VMS
  964.     extern char ibuf[];
  965. #endif
  966. #ifdef USE_GUI
  967.     if (gui.in_use)
  968.     {
  969. gui_mch_update();
  970. return;
  971.     }
  972. #endif
  973. #if defined(UNIX) || defined(OS2) || defined(VMS)
  974.     if (vim_is_input_buf_full())
  975. return;
  976.     /*
  977.      * Fill_input_buf() is only called when we really need a character.
  978.      * If we can't get any, but there is some in the buffer, just return.
  979.      * If we can't get any, and there isn't any in the buffer, we give up and
  980.      * exit Vim.
  981.      */
  982. # ifdef __BEOS__
  983.     /*
  984.      * On the BeBox version (for now), all input is secretly performed within
  985.      * beos_select() which is called from RealWaitForChar().
  986.      */
  987.     while (!vim_is_input_buf_full() && RealWaitForChar(read_cmd_fd, 0))
  988.     ;
  989.     len = inbufcount;
  990.     inbufcount = 0;
  991. # else
  992. #ifdef USE_SNIFF
  993.     if (sniff_request_waiting)
  994.     {
  995. add_to_input_buf((char_u *)"233sniff",6); /* results in K_SNIFF */
  996. sniff_request_waiting = 0;
  997. want_sniff_request = 0;
  998. return;
  999.     }
  1000. #endif
  1001. #  ifdef VMS
  1002.     while (!vim_is_input_buf_full() && RealWaitForChar(0, 0L))
  1003.     {
  1004. add_to_input_buf((char_u *)ibuf, 1);
  1005.     }
  1006.     if (inbufcount < 1 && !exit_on_error)
  1007. return;
  1008.     len = inbufcount;
  1009.     inbufcount = 0;
  1010. #  else
  1011.     for (try = 0; try < 100; ++try)
  1012.     {
  1013. len = read(read_cmd_fd, (char *)inbuf + inbufcount,
  1014.      (size_t)(INBUFLEN - inbufcount));
  1015. if (len > 0 || got_int)
  1016.     break;
  1017. /*
  1018.  * If reading stdin results in an error, continue reading stderr.
  1019.  * This helps when using "foo | xargs vim".
  1020.  */
  1021. if (!did_read_something && !isatty(read_cmd_fd) && read_cmd_fd == 0)
  1022.     read_cmd_fd = 2;
  1023. if (!exit_on_error)
  1024.     return;
  1025.     }
  1026. #  endif /* VMS */
  1027. # endif
  1028.     if (len <= 0 && !got_int)
  1029. read_error_exit();
  1030.     did_read_something = TRUE;
  1031.     if (got_int)
  1032.     {
  1033. inbuf[inbufcount] = 3;
  1034. inbufcount = 1;
  1035.     }
  1036.     else
  1037. while (len-- > 0)
  1038. {
  1039.     /*
  1040.      * if a CTRL-C was typed, remove it from the buffer and set got_int
  1041.      */
  1042.     if (inbuf[inbufcount] == 3)
  1043.     {
  1044. /* remove everything typed before the CTRL-C */
  1045. mch_memmove(inbuf, inbuf + inbufcount, (size_t)(len + 1));
  1046. inbufcount = 0;
  1047. got_int = TRUE;
  1048.     }
  1049.     ++inbufcount;
  1050. }
  1051. #endif /* UNIX or OS2 or VMS*/
  1052. }
  1053. #endif /* defined(UNIX) || defined(USE_GUI) || defined(OS2)  || defined(VMS) */
  1054. /*
  1055.  * Exit because of an input read error.
  1056.  */
  1057.     void
  1058. read_error_exit()
  1059. {
  1060.     if (silent_mode) /* Normal way to exit for "ex -s" */
  1061. getout(0);
  1062.     STRCPY(IObuff, "Vim: Error reading input, exiting...n");
  1063.     preserve_exit();
  1064. }
  1065. #if defined(CURSOR_SHAPE) || defined(PROTO)
  1066. /*
  1067.  * May update the shape of the cursor.
  1068.  */
  1069.     void
  1070. ui_cursor_shape()
  1071. {
  1072. #ifdef USE_GUI
  1073.     if (gui.in_use)
  1074. gui_upd_cursor_shape();
  1075. #endif
  1076. #if defined(MSDOS) || (defined(WIN32) && !defined(USE_GUI_WIN32))
  1077.     mch_update_cursor();
  1078. #endif
  1079. }
  1080. #endif