diff options
Diffstat (limited to 'src/ui.c')
-rw-r--r-- | src/ui.c | 1885 |
1 files changed, 1 insertions, 1884 deletions
@@ -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 -} |