]> granicus.if.org Git - vim/commitdiff
patch 8.1.1534: modeless selection in popup window selects too much v8.1.1534
authorBram Moolenaar <Bram@vim.org>
Fri, 14 Jun 2019 21:41:55 +0000 (23:41 +0200)
committerBram Moolenaar <Bram@vim.org>
Fri, 14 Jun 2019 21:41:55 +0000 (23:41 +0200)
Problem:    Modeless selection in popup window selects too much.
Solution:   Restrict the selection to insde of the popup window.

src/testdir/dumps/Test_popupwin_select_01.dump [new file with mode: 0644]
src/testdir/dumps/Test_popupwin_select_02.dump [new file with mode: 0644]
src/testdir/test_popupwin.vim
src/ui.c
src/version.c
src/vim.h

diff --git a/src/testdir/dumps/Test_popupwin_select_01.dump b/src/testdir/dumps/Test_popupwin_select_01.dump
new file mode 100644 (file)
index 0000000..779047d
--- /dev/null
@@ -0,0 +1,10 @@
+>1+0&#ffffff0| @73
+|2| @73
+|3| @7|╔+0#0000001#ffd7ff255|═@17|╗| +0#0000000#ffffff0@45
+|4| @7|║+0#0000001#ffd7ff255|t|h|e| |w+1#0000000#ffffff0|o|r|d| @9|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@45
+|5| @7|║+0#0000001#ffd7ff255|s+1#0000000#ffffff0|o|m|e| |m|o|r|e| @8|║+0#0000001#ffd7ff255| +0#0000000#ffffff0@45
+|6| @7|║+0#0000001#ffd7ff255|s+1#0000000#ffffff0|e|v|e|r|a|l| |w|o|r|d|s| +0#0000001#ffd7ff255|h|e|r|e|║| +0#0000000#ffffff0@45
+|7| @7|╚+0#0000001#ffd7ff255|═@17|╝| +0#0000000#ffffff0@45
+|8| @73
+|9| @73
+|:|c|a|l@1| |S|e|l|e|c|t|1|(|)| @41|1|,|1| @10|T|o|p| 
diff --git a/src/testdir/dumps/Test_popupwin_select_02.dump b/src/testdir/dumps/Test_popupwin_select_02.dump
new file mode 100644 (file)
index 0000000..550e0db
--- /dev/null
@@ -0,0 +1,10 @@
+|1+0&#ffffff0>w|o|r|d| @69
+|s|o|m|e| |m|o|r|e| @65
+|s|e|v|e|r|a|l| |w|o|r|d|s| @61
+|2| @73
+|3| @73
+|4| @73
+|5| @73
+|6| @73
+|7| @73
+@57|1|,|2| @10|T|o|p| 
index c084c7ccf1741192b5684eecb81880a0535c40b0..6e11bba73a452c49620d69cb9dc68d4a341a8939 100644 (file)
@@ -319,6 +319,39 @@ func Test_popup_drag()
   call delete('XtestPopupDrag')
 endfunc
 
+func Test_popup_select()
+  if !CanRunVimInTerminal()
+    throw 'Skipped: cannot make screendumps'
+  endif
+  " create a popup with some text to be selected
+  let lines =<< trim END
+    call setline(1, range(1, 20))
+    let winid = popup_create(['the word', 'some more', 'several words here'], {
+         \ 'drag': 1,
+         \ 'border': [],
+         \ 'line': 3,
+         \ 'col': 10,
+         \ })
+    func Select1()
+      call feedkeys("\<F3>\<LeftMouse>\<F4>\<LeftDrag>\<LeftRelease>", "xt")
+    endfunc
+    map <silent> <F3> :call test_setmouse(4, 15)<CR>
+    map <silent> <F4> :call test_setmouse(6, 23)<CR>
+  END
+  call writefile(lines, 'XtestPopupSelect')
+  let buf = RunVimInTerminal('-S XtestPopupSelect', {'rows': 10})
+  call term_sendkeys(buf, ":call Select1()\<CR>")
+  call VerifyScreenDump(buf, 'Test_popupwin_select_01', {})
+
+  call term_sendkeys(buf, ":call popup_close(winid)\<CR>")
+  call term_sendkeys(buf, "\"*p")
+  call VerifyScreenDump(buf, 'Test_popupwin_select_02', {})
+
+  " clean up
+  call StopVimInTerminal(buf)
+  call delete('XtestPopupSelect')
+endfunc
+
 func Test_popup_in_tab()
   " default popup is local to tab, not visible when in other tab
   let winid = popup_create("text", {})
index 2748da403bb6bc4fc991c8a4eb446d7ce8203aa3..9e387b4ceaf4574bbf6af55c66a100e54f024191 100644 (file)
--- a/src/ui.c
+++ b/src/ui.c
@@ -988,13 +988,13 @@ clip_isautosel_plus(void)
  * Stuff for general mouse selection, without using Visual mode.
  */
 
-static void clip_invert_area(int, int, int, int, int how);
-static void clip_invert_rectangle(int row, int col, int height, int width, int invert);
+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(int);
+static int  clip_get_line_end(Clipboard_T *, int);
 static void clip_update_modeless_selection(Clipboard_T *, int, int, int, int);
 
-/* flags for clip_invert_area() */
+// "how" flags for clip_invert_area()
 #define CLIP_CLEAR     1
 #define CLIP_SET       2
 #define CLIP_TOGGLE    3
@@ -1071,6 +1071,33 @@ clip_start_selection(int col, int row, int repeated_click)
     cb->end        = cb->start;
     cb->origin_row  = (short_u)cb->start.lnum;
     cb->state      = SELECT_IN_PROGRESS;
+#ifdef FEAT_TEXT_PROP
+    {
+       win_T       *wp;
+       int         row_cp = row;
+       int         col_cp = col;
+
+       wp = mouse_find_win(&row_cp, &col_cp, FIND_POPUP);
+       if (wp != NULL && bt_popup(wp->w_buffer))
+       {
+           // 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) - 1
+                                                      - wp->w_popup_border[1];
+           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)
     {
@@ -1090,7 +1117,7 @@ clip_start_selection(int col, int row, int repeated_click)
     {
        case SELECT_MODE_CHAR:
            cb->origin_start_col = cb->start.col;
-           cb->word_end_col = clip_get_line_end((int)cb->start.lnum);
+           cb->word_end_col = clip_get_line_end(cb, (int)cb->start.lnum);
            break;
 
        case SELECT_MODE_WORD:
@@ -1098,14 +1125,14 @@ clip_start_selection(int col, int row, int repeated_click)
            cb->origin_start_col = cb->word_start_col;
            cb->origin_end_col   = cb->word_end_col;
 
-           clip_invert_area((int)cb->start.lnum, cb->word_start_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((int)cb->start.lnum, 0, (int)cb->start.lnum,
+           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;
@@ -1223,7 +1250,7 @@ clip_process_selection(
        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(row);
+               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,
@@ -1316,7 +1343,7 @@ clip_may_redraw_selection(int row, int col, int len)
        if (row == clip_star.end.lnum && end > (int)clip_star.end.col)
            end = clip_star.end.col;
        if (end > start)
-           clip_invert_area(row, start, row, end, 0);
+           clip_invert_area(&clip_star, row, start, row, end, 0);
     }
 }
 # endif
@@ -1331,8 +1358,8 @@ clip_clear_selection(Clipboard_T *cbd)
     if (cbd->state == SELECT_CLEARED)
        return;
 
-    clip_invert_area((int)cbd->start.lnum, cbd->start.col, (int)cbd->end.lnum,
-                                                    cbd->end.col, CLIP_CLEAR);
+    clip_invert_area(cbd, (int)cbd->start.lnum, cbd->start.col,
+                                (int)cbd->end.lnum, cbd->end.col, CLIP_CLEAR);
     cbd->state = SELECT_CLEARED;
 }
 
@@ -1388,13 +1415,21 @@ clip_scroll_selection(
  */
     static void
 clip_invert_area(
-    int                row1,
-    int                col1,
-    int                row2,
-    int                col2,
-    int                how)
+       Clipboard_T     *cbd,
+       int             row1,
+       int             col1,
+       int             row2,
+       int             col2,
+       int             how)
 {
     int                invert = FALSE;
+    int                max_col;
+
+#ifdef FEAT_TEXT_PROP
+    max_col = cbd->max_col;
+#else
+    max_col = Columns - 1;
+#endif
 
     if (how == CLIP_SET)
        invert = TRUE;
@@ -1417,28 +1452,29 @@ clip_invert_area(
     /* If all on the same line, do it the easy way */
     if (row1 == row2)
     {
-       clip_invert_rectangle(row1, col1, 1, col2 - col1, invert);
+       clip_invert_rectangle(cbd, row1, col1, 1, col2 - col1, invert);
     }
     else
     {
        /* Handle a piece of the first line */
        if (col1 > 0)
        {
-           clip_invert_rectangle(row1, col1, 1, (int)Columns - col1, invert);
+           clip_invert_rectangle(cbd, row1, col1, 1,
+                                                 (int)Columns - col1, invert);
            row1++;
        }
 
        /* Handle a piece of the last line */
-       if (col2 < Columns - 1)
+       if (col2 < max_col)
        {
-           clip_invert_rectangle(row2, 0, 1, col2, invert);
+           clip_invert_rectangle(cbd, row2, 0, 1, col2, invert);
            row2--;
        }
 
        /* Handle the rectangle thats left */
        if (row2 >= row1)
-           clip_invert_rectangle(row1, 0, row2 - row1 + 1, (int)Columns,
-                                                                     invert);
+           clip_invert_rectangle(cbd, row1, 0, row2 - row1 + 1,
+                                                        (int)Columns, invert);
     }
 }
 
@@ -1448,15 +1484,36 @@ clip_invert_area(
  */
     static void
 clip_invert_rectangle(
-    int                row,
-    int                col,
-    int                height,
-    int                width,
-    int                invert)
-{
+       Clipboard_T     *cbd,
+       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_TEXT_PROP
     // this goes on top of all popup windows
     screen_zindex = 32000;
+
+    if (col < cbd->min_col)
+    {
+       width -= cbd->min_col - col;
+       col = cbd->min_col;
+    }
+    if (width > cbd->max_col - col + 1)
+       width = cbd->max_col - col + 1;
+    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)
@@ -1507,6 +1564,16 @@ clip_copy_modeless_selection(int both UNUSED)
     {
        row = col1; col1 = col2; col2 = row;
     }
+#ifdef FEAT_TEXT_PROP
+    if (col1 < clip_star.min_col)
+       col1 = clip_star.min_col;
+    if (col2 > clip_star.max_col + 1)
+       col2 = clip_star.max_col + 1;
+    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)
@@ -1530,17 +1597,31 @@ clip_copy_modeless_selection(int both UNUSED)
        if (row == row1)
            start_col = col1;
        else
+#ifdef FEAT_TEXT_PROP
+           start_col = clip_star.min_col;
+#else
            start_col = 0;
+#endif
 
        if (row == row2)
            end_col = col2;
        else
+#ifdef FEAT_TEXT_PROP
+           end_col = clip_star.max_col + 1;
+#else
            end_col = Columns;
+#endif
 
-       line_end_col = clip_get_line_end(row);
+       line_end_col = clip_get_line_end(&clip_star, row);
 
        /* See if we need to nuke some trailing whitespace */
-       if (end_col >= Columns && (row < row2 || end_col > line_end_col))
+       if (end_col >=
+#ifdef FEAT_TEXT_PROP
+               clip_star.max_col + 1
+#else
+               Columns
+#endif
+                   && (row < row2 || end_col > line_end_col))
        {
            /* Get rid of trailing whitespace */
            end_col = line_end_col;
@@ -1556,6 +1637,7 @@ clip_copy_modeless_selection(int both UNUSED)
        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)
@@ -1690,16 +1772,22 @@ clip_get_word_boundaries(Clipboard_T *cb, int row, int col)
 
 /*
  * Find the column position for the last non-whitespace character on the given
- * line.
+ * line at or before start_col.
  */
     static int
-clip_get_line_end(int row)
+clip_get_line_end(Clipboard_T *cbd UNUSED, int row)
 {
     int            i;
 
     if (row >= screen_Rows || ScreenLines == NULL)
        return 0;
-    for (i = screen_Columns; i > 0; i--)
+    for (i =
+#ifdef FEAT_TEXT_PROP
+           cbd->max_col + 1;
+#else
+           screen_Columns;
+#endif
+                           i > 0; i--)
        if (ScreenLines[LineOffset[row] + i - 1] != ' ')
            break;
     return i;
@@ -1720,7 +1808,7 @@ clip_update_modeless_selection(
     /* See if we changed at the beginning of the selection */
     if (row1 != cb->start.lnum || col1 != (int)cb->start.col)
     {
-       clip_invert_area(row1, col1, (int)cb->start.lnum, 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;
@@ -1729,7 +1817,7 @@ clip_update_modeless_selection(
     /* See if we changed at the end of the selection */
     if (row2 != cb->end.lnum || col2 != (int)cb->end.col)
     {
-       clip_invert_area((int)cb->end.lnum, cb->end.col, row2, col2,
+       clip_invert_area(cb, (int)cb->end.lnum, cb->end.col, row2, col2,
                                                                 CLIP_TOGGLE);
        cb->end.lnum = row2;
        cb->end.col  = col2;
index 18ef97e5bc582bcee87a4f5732820b116a438e82..851cd5fa1c392426d0be6a8307603dd5b12e56f8 100644 (file)
@@ -777,6 +777,8 @@ static char *(features[]) =
 
 static int included_patches[] =
 {   /* Add new patch number below this line */
+/**/
+    1534,
 /**/
     1533,
 /**/
index a44fb58142f95a409e836df6882ad22d6a6b4c11..d6bc6c3714c7007e24db6c6f4a182fab8ca08718 100644 (file)
--- a/src/vim.h
+++ b/src/vim.h
@@ -2008,34 +2008,41 @@ typedef int sock_T;
 /* Info about selected text */
 typedef struct
 {
-    int                available;      /* Is clipboard available? */
-    int                owned;          /* Flag: do we own the selection? */
-    pos_T      start;          /* Start of selected area */
-    pos_T      end;            /* End of selected area */
-    int                vmode;          /* Visual mode character */
+    int                available;      // Is clipboard available?
+    int                owned;          // Flag: do we own the selection?
+    pos_T      start;          // Start of selected area
+    pos_T      end;            // End of selected area
+    int                vmode;          // Visual mode character
 
-    /* Fields for selection that doesn't use Visual mode */
+    // Fields for selection that doesn't use Visual mode
     short_u    origin_row;
     short_u    origin_start_col;
     short_u    origin_end_col;
     short_u    word_start_col;
     short_u    word_end_col;
+#ifdef FEAT_TEXT_PROP
+    // limits for selection inside a popup window
+    short_u    min_col;
+    short_u    max_col;
+    short_u    min_row;
+    short_u    max_row;
+#endif
 
-    pos_T      prev;           /* Previous position */
-    short_u    state;          /* Current selection state */
-    short_u    mode;           /* Select by char, word, or line. */
+    pos_T      prev;           // Previous position
+    short_u    state;          // Current selection state
+    short_u    mode;           // Select by char, word, or line.
 
 # if defined(FEAT_GUI_X11) || defined(FEAT_XCLIPBOARD)
-    Atom       sel_atom;       /* PRIMARY/CLIPBOARD selection ID */
+    Atom       sel_atom;       // PRIMARY/CLIPBOARD selection ID
 # endif
 
 # ifdef FEAT_GUI_GTK
-    GdkAtom     gtk_sel_atom;  /* PRIMARY/CLIPBOARD selection ID */
+    GdkAtom     gtk_sel_atom;  // PRIMARY/CLIPBOARD selection ID
 # endif
 
 # if defined(MSWIN) || defined(FEAT_CYGWIN_WIN32_CLIPBOARD)
-    int_u      format;         /* Vim's own special clipboard format */
-    int_u      format_raw;     /* Vim's raw text clipboard format */
+    int_u      format;         // Vim's own special clipboard format
+    int_u      format_raw;     // Vim's raw text clipboard format
 # endif
 } Clipboard_T;
 #else