summaryrefslogtreecommitdiffstats
path: root/src/ui.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ui.c')
-rw-r--r--src/ui.c1885
1 files changed, 1 insertions, 1884 deletions
diff --git a/src/ui.c b/src/ui.c
index 6df1485498..050b1620ac 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -12,18 +12,11 @@
* 1. Keyboard input stuff, and a bit of windowing stuff. These are called
* before the machine specific stuff (mch_*) so that we can call the GUI
* stuff instead if the GUI is running.
- * 2. Clipboard stuff.
- * 3. Input buffer stuff.
+ * 2. Input buffer stuff.
*/
#include "vim.h"
-#ifdef FEAT_CYGWIN_WIN32_CLIPBOARD
-# define WIN32_LEAN_AND_MEAN
-# include <windows.h>
-# include "winclip.pro"
-#endif
-
void
ui_write(char_u *s, int len)
{
@@ -712,1331 +705,6 @@ ui_breakcheck_force(int force)
}
//////////////////////////////////////////////////////////////////////////////
-// Functions for copying and pasting text between applications.
-// This is always included in a GUI version, but may also be included when the
-// clipboard and mouse is available to a terminal version such as xterm.
-// Note: there are some more functions in ops.c that handle selection stuff.
-//
-// Also note that the majority of functions here deal with the X 'primary'
-// (visible - for Visual mode use) selection, and only that. There are no
-// versions of these for the 'clipboard' selection, as Visual mode has no use
-// for them.
-
-#if defined(FEAT_CLIPBOARD) || defined(PROTO)
-
-static void clip_gen_lose_selection(Clipboard_T *cbd);
-static int clip_gen_own_selection(Clipboard_T *cbd);
-#if defined(FEAT_X11) && defined(FEAT_XCLIPBOARD) && defined(USE_SYSTEM)
-static int clip_x11_owner_exists(Clipboard_T *cbd);
-#endif
-
-/*
- * Selection stuff using Visual mode, for cutting and pasting text to other
- * windows.
- */
-
-/*
- * Call this to initialise the clipboard. Pass it FALSE if the clipboard code
- * is included, but the clipboard can not be used, or TRUE if the clipboard can
- * be used. Eg unix may call this with FALSE, then call it again with TRUE if
- * the GUI starts.
- */
- void
-clip_init(int can_use)
-{
- Clipboard_T *cb;
-
- cb = &clip_star;
- for (;;)
- {
- cb->available = can_use;
- cb->owned = FALSE;
- cb->start.lnum = 0;
- cb->start.col = 0;
- cb->end.lnum = 0;
- cb->end.col = 0;
- cb->state = SELECT_CLEARED;
-
- if (cb == &clip_plus)
- break;
- cb = &clip_plus;
- }
-}
-
-/*
- * Check whether the VIsual area has changed, and if so try to become the owner
- * of the selection, and free any old converted selection we may still have
- * lying around. If the VIsual mode has ended, make a copy of what was
- * selected so we can still give it to others. Will probably have to make sure
- * this is called whenever VIsual mode is ended.
- */
- void
-clip_update_selection(Clipboard_T *clip)
-{
- pos_T start, end;
-
- // If visual mode is only due to a redo command ("."), then ignore it
- if (!redo_VIsual_busy && VIsual_active && (State & NORMAL))
- {
- if (LT_POS(VIsual, curwin->w_cursor))
- {
- start = VIsual;
- end = curwin->w_cursor;
- if (has_mbyte)
- end.col += (*mb_ptr2len)(ml_get_cursor()) - 1;
- }
- else
- {
- start = curwin->w_cursor;
- end = VIsual;
- }
- if (!EQUAL_POS(clip->start, start)
- || !EQUAL_POS(clip->end, end)
- || clip->vmode != VIsual_mode)
- {
- clip_clear_selection(clip);
- clip->start = start;
- clip->end = end;
- clip->vmode = VIsual_mode;
- clip_free_selection(clip);
- clip_own_selection(clip);
- clip_gen_set_selection(clip);
- }
- }
-}
-
- void
-clip_own_selection(Clipboard_T *cbd)
-{
- /*
- * Also want to check somehow that we are reading from the keyboard rather
- * than a mapping etc.
- */
-#ifdef FEAT_X11
- // Always own the selection, we might have lost it without being
- // notified, e.g. during a ":sh" command.
- if (cbd->available)
- {
- int was_owned = cbd->owned;
-
- cbd->owned = (clip_gen_own_selection(cbd) == OK);
- if (!was_owned && (cbd == &clip_star || cbd == &clip_plus))
- {
- // May have to show a different kind of highlighting for the
- // selected area. There is no specific redraw command for this,
- // just redraw all windows on the current buffer.
- if (cbd->owned
- && (get_real_state() == VISUAL
- || get_real_state() == SELECTMODE)
- && (cbd == &clip_star ? clip_isautosel_star()
- : clip_isautosel_plus())
- && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC))
- redraw_curbuf_later(INVERTED_ALL);
- }
- }
-#else
- // Only own the clipboard when we didn't own it yet.
- if (!cbd->owned && cbd->available)
- cbd->owned = (clip_gen_own_selection(cbd) == OK);
-#endif
-}
-
- void
-clip_lose_selection(Clipboard_T *cbd)
-{
-#ifdef FEAT_X11
- int was_owned = cbd->owned;
-#endif
- int visual_selection = FALSE;
-
- if (cbd == &clip_star || cbd == &clip_plus)
- visual_selection = TRUE;
-
- clip_free_selection(cbd);
- cbd->owned = FALSE;
- if (visual_selection)
- clip_clear_selection(cbd);
- clip_gen_lose_selection(cbd);
-#ifdef FEAT_X11
- if (visual_selection)
- {
- // May have to show a different kind of highlighting for the selected
- // area. There is no specific redraw command for this, just redraw all
- // windows on the current buffer.
- if (was_owned
- && (get_real_state() == VISUAL
- || get_real_state() == SELECTMODE)
- && (cbd == &clip_star ?
- clip_isautosel_star() : clip_isautosel_plus())
- && HL_ATTR(HLF_V) != HL_ATTR(HLF_VNC))
- {
- update_curbuf(INVERTED_ALL);
- setcursor();
- cursor_on();
- out_flush_cursor(TRUE, FALSE);
- }
- }
-#endif
-}
-
- static void
-clip_copy_selection(Clipboard_T *clip)
-{
- if (VIsual_active && (State & NORMAL) && clip->available)
- {
- clip_update_selection(clip);
- clip_free_selection(clip);
- clip_own_selection(clip);
- if (clip->owned)
- clip_get_selection(clip);
- clip_gen_set_selection(clip);
- }
-}
-
-/*
- * Save and restore clip_unnamed before doing possibly many changes. This
- * prevents accessing the clipboard very often which might slow down Vim
- * considerably.
- */
-static int global_change_count = 0; // if set, inside a start_global_changes
-static int clipboard_needs_update = FALSE; // clipboard needs to be updated
-static int clip_did_set_selection = TRUE;
-
-/*
- * Save clip_unnamed and reset it.
- */
- void
-start_global_changes(void)
-{
- if (++global_change_count > 1)
- return;
- clip_unnamed_saved = clip_unnamed;
- clipboard_needs_update = FALSE;
-
- if (clip_did_set_selection)
- {
- clip_unnamed = 0;
- clip_did_set_selection = FALSE;
- }
-}
-
-/*
- * Return TRUE if setting the clipboard was postponed, it already contains the
- * right text.
- */
- int
-is_clipboard_needs_update()
-{
- return clipboard_needs_update;
-}
-
-/*
- * Restore clip_unnamed and set the selection when needed.
- */
- void
-end_global_changes(void)
-{
- if (--global_change_count > 0)
- // recursive
- return;
- if (!clip_did_set_selection)
- {
- clip_did_set_selection = TRUE;
- clip_unnamed = clip_unnamed_saved;
- clip_unnamed_saved = 0;
- if (clipboard_needs_update)
- {
- // only store something in the clipboard,
- // if we have yanked anything to it
- if (clip_unnamed & CLIP_UNNAMED)
- {
- clip_own_selection(&clip_star);
- clip_gen_set_selection(&clip_star);
- }
- if (clip_unnamed & CLIP_UNNAMED_PLUS)
- {
- clip_own_selection(&clip_plus);
- clip_gen_set_selection(&clip_plus);
- }
- }
- }
- clipboard_needs_update = FALSE;
-}
-
-/*
- * Called when Visual mode is ended: update the selection.
- */
- void
-clip_auto_select(void)
-{
- if (clip_isautosel_star())
- clip_copy_selection(&clip_star);
- if (clip_isautosel_plus())
- clip_copy_selection(&clip_plus);
-}
-
-/*
- * Return TRUE if automatic selection of Visual area is desired for the *
- * register.
- */
- int
-clip_isautosel_star(void)
-{
- return (
-#ifdef FEAT_GUI
- gui.in_use ? (vim_strchr(p_go, GO_ASEL) != NULL) :
-#endif
- clip_autoselect_star);
-}
-
-/*
- * Return TRUE if automatic selection of Visual area is desired for the +
- * register.
- */
- int
-clip_isautosel_plus(void)
-{
- return (
-#ifdef FEAT_GUI
- gui.in_use ? (vim_strchr(p_go, GO_ASELPLUS) != NULL) :
-#endif
- clip_autoselect_plus);
-}
-
-
-/*
- * Stuff for general mouse selection, without using Visual mode.
- */
-
-static void clip_invert_area(Clipboard_T *, int, int, int, int, int how);
-static void clip_invert_rectangle(Clipboard_T *, int row, int col, int height, int width, int invert);
-static void clip_get_word_boundaries(Clipboard_T *, int, int);
-static int clip_get_line_end(Clipboard_T *, int);
-static void clip_update_modeless_selection(Clipboard_T *, int, int, int, int);
-
-// "how" flags for clip_invert_area()
-#define CLIP_CLEAR 1
-#define CLIP_SET 2
-#define CLIP_TOGGLE 3
-
-/*
- * Start, continue or end a modeless selection. Used when editing the
- * command-line, in the cmdline window and when the mouse is in a popup window.
- */
- void
-clip_modeless(int button, int is_click, int is_drag)
-{
- int repeat;
-
- repeat = ((clip_star.mode == SELECT_MODE_CHAR
- || clip_star.mode == SELECT_MODE_LINE)
- && (mod_mask & MOD_MASK_2CLICK))
- || (clip_star.mode == SELECT_MODE_WORD
- && (mod_mask & MOD_MASK_3CLICK));
- if (is_click && button == MOUSE_RIGHT)
- {
- // Right mouse button: If there was no selection, start one.
- // Otherwise extend the existing selection.
- if (clip_star.state == SELECT_CLEARED)
- clip_start_selection(mouse_col, mouse_row, FALSE);
- clip_process_selection(button, mouse_col, mouse_row, repeat);
- }
- else if (is_click)
- clip_start_selection(mouse_col, mouse_row, repeat);
- else if (is_drag)
- {
- // Don't try extending a selection if there isn't one. Happens when
- // button-down is in the cmdline and then moving mouse upwards.
- if (clip_star.state != SELECT_CLEARED)
- clip_process_selection(button, mouse_col, mouse_row, repeat);
- }
- else // release
- clip_process_selection(MOUSE_RELEASE, mouse_col, mouse_row, FALSE);
-}
-
-/*
- * Compare two screen positions ala strcmp()
- */
- static int
-clip_compare_pos(
- int row1,
- int col1,
- int row2,
- int col2)
-{
- if (row1 > row2) return(1);
- if (row1 < row2) return(-1);
- if (col1 > col2) return(1);
- if (col1 < col2) return(-1);
- return(0);
-}
-
-/*
- * Start the selection
- */
- void
-clip_start_selection(int col, int row, int repeated_click)
-{
- Clipboard_T *cb = &clip_star;
-#ifdef FEAT_PROP_POPUP
- win_T *wp;
- int row_cp = row;
- int col_cp = col;
-
- wp = mouse_find_win(&row_cp, &col_cp, FIND_POPUP);
- if (wp != NULL && WIN_IS_POPUP(wp)
- && popup_is_in_scrollbar(wp, row_cp, col_cp))
- // click or double click in scrollbar does not start a selection
- return;
-#endif
-
- if (cb->state == SELECT_DONE)
- clip_clear_selection(cb);
-
- row = check_row(row);
- col = check_col(col);
- col = mb_fix_col(col, row);
-
- cb->start.lnum = row;
- cb->start.col = col;
- cb->end = cb->start;
- cb->origin_row = (short_u)cb->start.lnum;
- cb->state = SELECT_IN_PROGRESS;
-#ifdef FEAT_PROP_POPUP
- if (wp != NULL && WIN_IS_POPUP(wp))
- {
- // Click in a popup window restricts selection to that window,
- // excluding the border.
- cb->min_col = wp->w_wincol + wp->w_popup_border[3];
- cb->max_col = wp->w_wincol + popup_width(wp)
- - wp->w_popup_border[1] - wp->w_has_scrollbar;
- if (cb->max_col > screen_Columns)
- cb->max_col = screen_Columns;
- cb->min_row = wp->w_winrow + wp->w_popup_border[0];
- cb->max_row = wp->w_winrow + popup_height(wp) - 1
- - wp->w_popup_border[2];
- }
- else
- {
- cb->min_col = 0;
- cb->max_col = screen_Columns;
- cb->min_row = 0;
- cb->max_row = screen_Rows;
- }
-#endif
-
- if (repeated_click)
- {
- if (++cb->mode > SELECT_MODE_LINE)
- cb->mode = SELECT_MODE_CHAR;
- }
- else
- cb->mode = SELECT_MODE_CHAR;
-
-#ifdef FEAT_GUI
- // clear the cursor until the selection is made
- if (gui.in_use)
- gui_undraw_cursor();
-#endif
-
- switch (cb->mode)
- {
- case SELECT_MODE_CHAR:
- cb->origin_start_col = cb->start.col;
- cb->word_end_col = clip_get_line_end(cb, (int)cb->start.lnum);
- break;
-
- case SELECT_MODE_WORD:
- clip_get_word_boundaries(cb, (int)cb->start.lnum, cb->start.col);
- cb->origin_start_col = cb->word_start_col;
- cb->origin_end_col = cb->word_end_col;
-
- clip_invert_area(cb, (int)cb->start.lnum, cb->word_start_col,
- (int)cb->end.lnum, cb->word_end_col, CLIP_SET);
- cb->start.col = cb->word_start_col;
- cb->end.col = cb->word_end_col;
- break;
-
- case SELECT_MODE_LINE:
- clip_invert_area(cb, (int)cb->start.lnum, 0, (int)cb->start.lnum,
- (int)Columns, CLIP_SET);
- cb->start.col = 0;
- cb->end.col = Columns;
- break;
- }
-
- cb->prev = cb->start;
-
-#ifdef DEBUG_SELECTION
- printf("Selection started at (%ld,%d)\n", cb->start.lnum, cb->start.col);
-#endif
-}
-
-/*
- * Continue processing the selection
- */
- void
-clip_process_selection(
- int button,
- int col,
- int row,
- int_u repeated_click)
-{
- Clipboard_T *cb = &clip_star;
- int diff;
- int slen = 1; // cursor shape width
-
- if (button == MOUSE_RELEASE)
- {
- if (cb->state != SELECT_IN_PROGRESS)
- return;
-
- // Check to make sure we have something selected
- if (cb->start.lnum == cb->end.lnum && cb->start.col == cb->end.col)
- {
-#ifdef FEAT_GUI
- if (gui.in_use)
- gui_update_cursor(FALSE, FALSE);
-#endif
- cb->state = SELECT_CLEARED;
- return;
- }
-
-#ifdef DEBUG_SELECTION
- printf("Selection ended: (%ld,%d) to (%ld,%d)\n", cb->start.lnum,
- cb->start.col, cb->end.lnum, cb->end.col);
-#endif
- if (clip_isautosel_star()
- || (
-#ifdef FEAT_GUI
- gui.in_use ? (vim_strchr(p_go, GO_ASELML) != NULL) :
-#endif
- clip_autoselectml))
- clip_copy_modeless_selection(FALSE);
-#ifdef FEAT_GUI
- if (gui.in_use)
- gui_update_cursor(FALSE, FALSE);
-#endif
-
- cb->state = SELECT_DONE;
- return;
- }
-
- row = check_row(row);
- col = check_col(col);
- col = mb_fix_col(col, row);
-
- if (col == (int)cb->prev.col && row == cb->prev.lnum && !repeated_click)
- return;
-
- /*
- * When extending the selection with the right mouse button, swap the
- * start and end if the position is before half the selection
- */
- if (cb->state == SELECT_DONE && button == MOUSE_RIGHT)
- {
- /*
- * If the click is before the start, or the click is inside the
- * selection and the start is the closest side, set the origin to the
- * end of the selection.
- */
- if (clip_compare_pos(row, col, (int)cb->start.lnum, cb->start.col) < 0
- || (clip_compare_pos(row, col,
- (int)cb->end.lnum, cb->end.col) < 0
- && (((cb->start.lnum == cb->end.lnum
- && cb->end.col - col > col - cb->start.col))
- || ((diff = (cb->end.lnum - row) -
- (row - cb->start.lnum)) > 0
- || (diff == 0 && col < (int)(cb->start.col +
- cb->end.col) / 2)))))
- {
- cb->origin_row = (short_u)cb->end.lnum;
- cb->origin_start_col = cb->end.col - 1;
- cb->origin_end_col = cb->end.col;
- }
- else
- {
- cb->origin_row = (short_u)cb->start.lnum;
- cb->origin_start_col = cb->start.col;
- cb->origin_end_col = cb->start.col;
- }
- if (cb->mode == SELECT_MODE_WORD && !repeated_click)
- cb->mode = SELECT_MODE_CHAR;
- }
-
- // set state, for when using the right mouse button
- cb->state = SELECT_IN_PROGRESS;
-
-#ifdef DEBUG_SELECTION
- printf("Selection extending to (%d,%d)\n", row, col);
-#endif
-
- if (repeated_click && ++cb->mode > SELECT_MODE_LINE)
- cb->mode = SELECT_MODE_CHAR;
-
- switch (cb->mode)
- {
- case SELECT_MODE_CHAR:
- // If we're on a different line, find where the line ends
- if (row != cb->prev.lnum)
- cb->word_end_col = clip_get_line_end(cb, row);
-
- // See if we are before or after the origin of the selection
- if (clip_compare_pos(row, col, cb->origin_row,
- cb->origin_start_col) >= 0)
- {
- if (col >= (int)cb->word_end_col)
- clip_update_modeless_selection(cb, cb->origin_row,
- cb->origin_start_col, row, (int)Columns);
- else
- {
- if (has_mbyte && mb_lefthalve(row, col))
- slen = 2;
- clip_update_modeless_selection(cb, cb->origin_row,
- cb->origin_start_col, row, col + slen);
- }
- }
- else
- {
- if (has_mbyte
- && mb_lefthalve(cb->origin_row, cb->origin_start_col))
- slen = 2;
- if (col >= (int)cb->word_end_col)
- clip_update_modeless_selection(cb, row, cb->word_end_col,
- cb->origin_row, cb->origin_start_col + slen);
- else
- clip_update_modeless_selection(cb, row, col,
- cb->origin_row, cb->origin_start_col + slen);
- }
- break;
-
- case SELECT_MODE_WORD:
- // If we are still within the same word, do nothing
- if (row == cb->prev.lnum && col >= (int)cb->word_start_col
- && col < (int)cb->word_end_col && !repeated_click)
- return;
-
- // Get new word boundaries
- clip_get_word_boundaries(cb, row, col);
-
- // Handle being after the origin point of selection
- if (clip_compare_pos(row, col, cb->origin_row,
- cb->origin_start_col) >= 0)
- clip_update_modeless_selection(cb, cb->origin_row,
- cb->origin_start_col, row, cb->word_end_col);
- else
- clip_update_modeless_selection(cb, row, cb->word_start_col,
- cb->origin_row, cb->origin_end_col);
- break;
-
- case SELECT_MODE_LINE:
- if (row == cb->prev.lnum && !repeated_click)
- return;
-
- if (clip_compare_pos(row, col, cb->origin_row,
- cb->origin_start_col) >= 0)
- clip_update_modeless_selection(cb, cb->origin_row, 0, row,
- (int)Columns);
- else
- clip_update_modeless_selection(cb, row, 0, cb->origin_row,
- (int)Columns);
- break;
- }
-
- cb->prev.lnum = row;
- cb->prev.col = col;
-
-#ifdef DEBUG_SELECTION
- printf("Selection is: (%ld,%d) to (%ld,%d)\n", cb->start.lnum,
- cb->start.col, cb->end.lnum, cb->end.col);
-#endif
-}
-
-# if defined(FEAT_GUI) || defined(PROTO)
-/*
- * Redraw part of the selection if character at "row,col" is inside of it.
- * Only used for the GUI.
- */
- void
-clip_may_redraw_selection(int row, int col, int len)
-{
- int start = col;
- int end = col + len;
-
- if (clip_star.state != SELECT_CLEARED
- && row >= clip_star.start.lnum
- && row <= clip_star.end.lnum)
- {
- if (row == clip_star.start.lnum && start < (int)clip_star.start.col)
- start = clip_star.start.col;
- if (row == clip_star.end.lnum && end > (int)clip_star.end.col)
- end = clip_star.end.col;
- if (end > start)
- clip_invert_area(&clip_star, row, start, row, end, 0);
- }
-}
-# endif
-
-/*
- * Called from outside to clear selected region from the display
- */
- void
-clip_clear_selection(Clipboard_T *cbd)
-{
-
- if (cbd->state == SELECT_CLEARED)
- return;
-
- clip_invert_area(cbd, (int)cbd->start.lnum, cbd->start.col,
- (int)cbd->end.lnum, cbd->end.col, CLIP_CLEAR);
- cbd->state = SELECT_CLEARED;
-}
-
-/*
- * Clear the selection if any lines from "row1" to "row2" are inside of it.
- */
- void
-clip_may_clear_selection(int row1, int row2)
-{
- if (clip_star.state == SELECT_DONE
- && row2 >= clip_star.start.lnum
- && row1 <= clip_star.end.lnum)
- clip_clear_selection(&clip_star);
-}
-
-/*
- * Called before the screen is scrolled up or down. Adjusts the line numbers
- * of the selection. Call with big number when clearing the screen.
- */
- void
-clip_scroll_selection(
- int rows) // negative for scroll down
-{
- int lnum;
-
- if (clip_star.state == SELECT_CLEARED)
- return;
-
- lnum = clip_star.start.lnum - rows;
- if (lnum <= 0)
- clip_star.start.lnum = 0;
- else if (lnum >= screen_Rows) // scrolled off of the screen
- clip_star.state = SELECT_CLEARED;
- else
- clip_star.start.lnum = lnum;
-
- lnum = clip_star.end.lnum - rows;
- if (lnum < 0) // scrolled off of the screen
- clip_star.state = SELECT_CLEARED;
- else if (lnum >= screen_Rows)
- clip_star.end.lnum = screen_Rows - 1;
- else
- clip_star.end.lnum = lnum;
-}
-
-/*
- * Invert a region of the display between a starting and ending row and column
- * Values for "how":
- * CLIP_CLEAR: undo inversion
- * CLIP_SET: set inversion
- * CLIP_TOGGLE: set inversion if pos1 < pos2, undo inversion otherwise.
- * 0: invert (GUI only).
- */
- static void
-clip_invert_area(
- Clipboard_T *cbd,
- int row1,
- int col1,
- int row2,
- int col2,
- int how)
-{
- int invert = FALSE;
- int max_col;
-
-#ifdef FEAT_PROP_POPUP
- max_col = cbd->max_col - 1;
-#else
- max_col = Columns - 1;
-#endif
-
- if (how == CLIP_SET)
- invert = TRUE;
-
- // Swap the from and to positions so the from is always before
- if (clip_compare_pos(row1, col1, row2, col2) > 0)
- {
- int tmp_row, tmp_col;
-
- tmp_row = row1;
- tmp_col = col1;
- row1 = row2;
- col1 = col2;
- row2 = tmp_row;
- col2 = tmp_col;
- }
- else if (how == CLIP_TOGGLE)
- invert = TRUE;
-
- // If all on the same line, do it the easy way
- if (row1 == row2)
- {
- clip_invert_rectangle(cbd, row1, col1, 1, col2 - col1, invert);
- }
- else
- {
- // Handle a piece of the first line
- if (col1 > 0)
- {
- clip_invert_rectangle(cbd, row1, col1, 1,
- (int)Columns - col1, invert);
- row1++;
- }
-
- // Handle a piece of the last line
- if (col2 < max_col)
- {
- clip_invert_rectangle(cbd, row2, 0, 1, col2, invert);
- row2--;
- }
-
- // Handle the rectangle that's left
- if (row2 >= row1)
- clip_invert_rectangle(cbd, row1, 0, row2 - row1 + 1,
- (int)Columns, invert);
- }
-}
-
-/*
- * Invert or un-invert a rectangle of the screen.
- * "invert" is true if the result is inverted.
- */
- static void
-clip_invert_rectangle(
- Clipboard_T *cbd UNUSED,
- int row_arg,
- int col_arg,
- int height_arg,
- int width_arg,
- int invert)
-{
- int row = row_arg;
- int col = col_arg;
- int height = height_arg;
- int width = width_arg;
-
-#ifdef FEAT_PROP_POPUP
- // this goes on top of all popup windows
- screen_zindex = CLIP_ZINDEX;
-
- if (col < cbd->min_col)
- {
- width -= cbd->min_col - col;
- col = cbd->min_col;
- }
- if (width > cbd->max_col - col)
- width = cbd->max_col - col;
- if (row < cbd->min_row)
- {
- height -= cbd->min_row - row;
- row = cbd->min_row;
- }
- if (height > cbd->max_row - row + 1)
- height = cbd->max_row - row + 1;
-#endif
-#ifdef FEAT_GUI
- if (gui.in_use)
- gui_mch_invert_rectangle(row, col, height, width);
- else
-#endif
- screen_draw_rectangle(row, col, height, width, invert);
-#ifdef FEAT_PROP_POPUP
- screen_zindex = 0;
-#endif
-}
-
-/*
- * Copy the currently selected area into the '*' register so it will be
- * available for pasting.
- * When "both" is TRUE also copy to the '+' register.
- */
- void
-clip_copy_modeless_selection(int both UNUSED)
-{
- char_u *buffer;
- char_u *bufp;
- int row;
- int start_col;
- int end_col;
- int line_end_col;
- int add_newline_flag = FALSE;
- int len;
- char_u *p;
- int row1 = clip_star.start.lnum;
- int col1 = clip_star.start.col;
- int row2 = clip_star.end.lnum;
- int col2 = clip_star.end.col;
-
- // Can't use ScreenLines unless initialized
- if (ScreenLines == NULL)
- return;
-
- /*
- * Make sure row1 <= row2, and if row1 == row2 that col1 <= col2.
- */
- if (row1 > row2)
- {
- row = row1; row1 = row2; row2 = row;
- row = col1; col1 = col2; col2 = row;
- }
- else if (row1 == row2 && col1 > col2)
- {
- row = col1; col1 = col2; col2 = row;
- }
-#ifdef FEAT_PROP_POPUP
- if (col1 < clip_star.min_col)
- col1 = clip_star.min_col;
- if (col2 > clip_star.max_col)
- col2 = clip_star.max_col;
- if (row1 > clip_star.max_row || row2 < clip_star.min_row)
- return;
- if (row1 < clip_star.min_row)
- row1 = clip_star.min_row;
- if (row2 > clip_star.max_row)
- row2 = clip_star.max_row;
-#endif
- // correct starting point for being on right halve of double-wide char
- p = ScreenLines + LineOffset[row1];
- if (enc_dbcs != 0)
- col1 -= (*mb_head_off)(p, p + col1);
- else if (enc_utf8 && p[col1] == 0)
- --col1;
-
- // Create a temporary buffer for storing the text
- len = (row2 - row1 + 1) * Columns + 1;
- if (enc_dbcs != 0)
- len *= 2; // max. 2 bytes per display cell
- else if (enc_utf8)
- len *= MB_MAXBYTES;
- buffer = alloc(len);
- if (buffer == NULL) // out of memory
- return;
-
- // Process each row in the selection
- for (bufp = buffer, row = row1; row <= row2; row++)
- {
- if (row == row1)
- start_col = col1;
- else
-#ifdef FEAT_PROP_POPUP
- start_col = clip_star.min_col;
-#else
- start_col = 0;
-#endif
-
- if (row == row2)
- end_col = col2;
- else
-#ifdef FEAT_PROP_POPUP
- end_col = clip_star.max_col;
-#else
- end_col = Columns;
-#endif
-
- line_end_col = clip_get_line_end(&clip_star, row);
-
- // See if we need to nuke some trailing whitespace
- if (end_col >=
-#ifdef FEAT_PROP_POPUP
- clip_star.max_col
-#else
- Columns
-#endif
- && (row < row2 || end_col > line_end_col))
- {
- // Get rid of trailing whitespace
- end_col = line_end_col;
- if (end_col < start_col)
- end_col = start_col;
-
- // If the last line extended to the end, add an extra newline
- if (row == row2)
- add_newline_flag = TRUE;
- }
-
- // If after the first row, we need to always add a newline
- if (row > row1 && !LineWraps[row - 1])
- *bufp++ = NL;
-
- // Safetey check for in case resizing went wrong
- if (row < screen_Rows && end_col <= screen_Columns)
- {
- if (enc_dbcs != 0)
- {
- int i;
-
- p = ScreenLines + LineOffset[row];
- for (i = start_col; i < end_col; ++i)
- if (enc_dbcs == DBCS_JPNU && p[i] == 0x8e)
- {
- // single-width double-byte char
- *bufp++ = 0x8e;
- *bufp++ = ScreenLines2[LineOffset[row] + i];
- }
- else
- {
- *bufp++ = p[i];
- if (MB_BYTE2LEN(p[i]) == 2)
- *bufp++ = p[++i];
- }
- }
- else if (enc_utf8)
- {
- int off;
- int i;
- int ci;
-
- off = LineOffset[row];
- for (i = start_col; i < end_col; ++i)
- {
- // The base character is either in ScreenLinesUC[] or
- // ScreenLines[].
- if (ScreenLinesUC[off + i] == 0)
- *bufp++ = ScreenLines[off + i];
- else
- {
- bufp += utf_char2bytes(ScreenLinesUC[off + i], bufp);
- for (ci = 0; ci < Screen_mco; ++ci)
- {
- // Add a composing character.
- if (ScreenLinesC[ci][off + i] == 0)
- break;
- bufp += utf_char2bytes(ScreenLinesC[ci][off + i],
- bufp);
- }
- }
- // Skip right halve of double-wide character.
- if (ScreenLines[off + i + 1] == 0)
- ++i;
- }
- }
- else
- {
- STRNCPY(bufp, ScreenLines + LineOffset[row] + start_col,
- end_col - start_col);
- bufp += end_col - start_col;
- }
- }
- }
-
- // Add a newline at the end if the selection ended there
- if (add_newline_flag)
- *bufp++ = NL;
-
- // First cleanup any old selection and become the owner.
- clip_free_selection(&clip_star);
- clip_own_selection(&clip_star);
-
- // Yank the text into the '*' register.
- clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_star);
-
- // Make the register contents available to the outside world.
- clip_gen_set_selection(&clip_star);
-
-#ifdef FEAT_X11
- if (both)
- {
- // Do the same for the '+' register.
- clip_free_selection(&clip_plus);
- clip_own_selection(&clip_plus);
- clip_yank_selection(MCHAR, buffer, (long)(bufp - buffer), &clip_plus);
- clip_gen_set_selection(&clip_plus);
- }
-#endif
- vim_free(buffer);
-}
-
-/*
- * Find the starting and ending positions of the word at the given row and
- * column. Only white-separated words are recognized here.
- */
-#define CHAR_CLASS(c) (c <= ' ' ? ' ' : vim_iswordc(c))
-
- static void
-clip_get_word_boundaries(Clipboard_T *cb, int row, int col)
-{
- int start_class;
- int temp_col;
- char_u *p;
- int mboff;
-
- if (row >= screen_Rows || col >= screen_Columns || ScreenLines == NULL)
- return;
-
- p = ScreenLines + LineOffset[row];
- // Correct for starting in the right halve of a double-wide char
- if (enc_dbcs != 0)
- col -= dbcs_screen_head_off(p, p + col);
- else if (enc_utf8 && p[col] == 0)
- --col;
- start_class = CHAR_CLASS(p[col]);
-
- temp_col = col;
- for ( ; temp_col > 0; temp_col--)
- if (enc_dbcs != 0
- && (mboff = dbcs_screen_head_off(p, p + temp_col - 1)) > 0)
- temp_col -= mboff;
- else if (CHAR_CLASS(p[temp_col - 1]) != start_class
- && !(enc_utf8 && p[temp_col - 1] == 0))
- break;
- cb->word_start_col = temp_col;
-
- temp_col = col;
- for ( ; temp_col < screen_Columns; temp_col++)
- if (enc_dbcs != 0 && dbcs_ptr2cells(p + temp_col) == 2)
- ++temp_col;
- else if (CHAR_CLASS(p[temp_col]) != start_class
- && !(enc_utf8 && p[temp_col] == 0))
- break;
- cb->word_end_col = temp_col;
-}
-
-/*
- * Find the column position for the last non-whitespace character on the given
- * line at or before start_col.
- */
- static int
-clip_get_line_end(Clipboard_T *cbd UNUSED, int row)
-{
- int i;
-
- if (row >= screen_Rows || ScreenLines == NULL)
- return 0;
- for (i =
-#ifdef FEAT_PROP_POPUP
- cbd->max_col;
-#else
- screen_Columns;
-#endif
- i > 0; i--)
- if (ScreenLines[LineOffset[row] + i - 1] != ' ')
- break;
- return i;
-}
-
-/*
- * Update the currently selected region by adding and/or subtracting from the
- * beginning or end and inverting the changed area(s).
- */
- static void
-clip_update_modeless_selection(
- Clipboard_T *cb,
- int row1,
- int col1,
- int row2,
- int col2)
-{
- // See if we changed at the beginning of the selection
- if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
- {
- clip_invert_area(cb, row1, col1, (int)cb->start.lnum, cb->start.col,
- CLIP_TOGGLE);
- cb->start.lnum = row1;
- cb->start.col = col1;
- }
-
- // See if we changed at the end of the selection
- if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
- {
- clip_invert_area(cb, (int)cb->end.lnum, cb->end.col, row2, col2,
- CLIP_TOGGLE);
- cb->end.lnum = row2;
- cb->end.col = col2;
- }
-}
-
- static int
-clip_gen_own_selection(Clipboard_T *cbd)
-{
-#ifdef FEAT_XCLIPBOARD
-# ifdef FEAT_GUI
- if (gui.in_use)
- return clip_mch_own_selection(cbd);
- else
-# endif
- return clip_xterm_own_selection(cbd);
-#else
- return clip_mch_own_selection(cbd);
-#endif
-}
-
- static void
-clip_gen_lose_selection(Clipboard_T *cbd)
-{
-#ifdef FEAT_XCLIPBOARD
-# ifdef FEAT_GUI
- if (gui.in_use)
- clip_mch_lose_selection(cbd);
- else
-# endif
- clip_xterm_lose_selection(cbd);
-#else
- clip_mch_lose_selection(cbd);
-#endif
-}
-
- void
-clip_gen_set_selection(Clipboard_T *cbd)
-{
- if (!clip_did_set_selection)
- {
- // Updating postponed, so that accessing the system clipboard won't
- // hang Vim when accessing it many times (e.g. on a :g command).
- if ((cbd == &clip_plus && (clip_unnamed_saved & CLIP_UNNAMED_PLUS))
- || (cbd == &clip_star && (clip_unnamed_saved & CLIP_UNNAMED)))
- {
- clipboard_needs_update = TRUE;
- return;
- }
- }
-#ifdef FEAT_XCLIPBOARD
-# ifdef FEAT_GUI
- if (gui.in_use)
- clip_mch_set_selection(cbd);
- else
-# endif
- clip_xterm_set_selection(cbd);
-#else
- clip_mch_set_selection(cbd);
-#endif
-}