Patch 8.1.1534
Problem:    Modeless selection in popup window selects too much.
Solution:   Restrict the selection to insde of the popup window.
Files:      src/vim.h, src/ui.c, src/testdir/test_popupwin.vim,
            src/testdir/dumps/Test_popupwin_select_01.dump,
            src/testdir/dumps/Test_popupwin_select_02.dump


*** ../vim-8.1.1533/src/vim.h   2019-06-14 23:14:41.936219907 +0200
--- src/vim.h   2019-06-14 23:36:54.345446982 +0200
***************
*** 2008,2041 ****
  /* 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 */
  
!     /* 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;
  
!     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 */
  # endif
  
  # ifdef FEAT_GUI_GTK
!     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 */
  # endif
  } Clipboard_T;
  #else
--- 2008,2048 ----
  /* 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
  
!     // 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.
  
  # if defined(FEAT_GUI_X11) || defined(FEAT_XCLIPBOARD)
!     Atom      sel_atom;       // PRIMARY/CLIPBOARD selection ID
  # endif
  
  # ifdef FEAT_GUI_GTK
!     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
  # endif
  } Clipboard_T;
  #else
*** ../vim-8.1.1533/src/ui.c    2019-06-14 21:36:51.018437479 +0200
--- src/ui.c    2019-06-14 23:09:19.161413017 +0200
***************
*** 988,1000 ****
   * 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_get_word_boundaries(Clipboard_T *, int, int);
! static int  clip_get_line_end(int);
  static void clip_update_modeless_selection(Clipboard_T *, int, int, int, int);
  
! /* flags for clip_invert_area() */
  #define CLIP_CLEAR    1
  #define CLIP_SET      2
  #define CLIP_TOGGLE   3
--- 988,1000 ----
   * 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
***************
*** 1071,1076 ****
--- 1071,1103 ----
      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,1096 ****
      {
        case SELECT_MODE_CHAR:
            cb->origin_start_col = cb->start.col;
!           cb->word_end_col = clip_get_line_end((int)cb->start.lnum);
            break;
  
        case SELECT_MODE_WORD:
--- 1117,1123 ----
      {
        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:
***************
*** 1098,1111 ****
            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,
                            (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,
                            (int)Columns, CLIP_SET);
            cb->start.col = 0;
            cb->end.col   = Columns;
--- 1125,1138 ----
            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;
***************
*** 1223,1229 ****
        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);
  
            /* See if we are before or after the origin of the selection */
            if (clip_compare_pos(row, col, cb->origin_row,
--- 1250,1256 ----
        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,
***************
*** 1316,1322 ****
        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);
      }
  }
  # endif
--- 1343,1349 ----
        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
***************
*** 1331,1338 ****
      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);
      cbd->state = SELECT_CLEARED;
  }
  
--- 1358,1365 ----
      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;
  }
  
***************
*** 1388,1400 ****
   */
      static void
  clip_invert_area(
!     int               row1,
!     int               col1,
!     int               row2,
!     int               col2,
!     int               how)
  {
      int               invert = FALSE;
  
      if (how == CLIP_SET)
        invert = TRUE;
--- 1415,1435 ----
   */
      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_TEXT_PROP
+     max_col = cbd->max_col;
+ #else
+     max_col = Columns - 1;
+ #endif
  
      if (how == CLIP_SET)
        invert = TRUE;
***************
*** 1417,1444 ****
      /* If all on the same line, do it the easy way */
      if (row1 == row2)
      {
!       clip_invert_rectangle(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);
            row1++;
        }
  
        /* Handle a piece of the last line */
!       if (col2 < Columns - 1)
        {
!           clip_invert_rectangle(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);
      }
  }
  
--- 1452,1480 ----
      /* 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 thats left */
        if (row2 >= row1)
!           clip_invert_rectangle(cbd, row1, 0, row2 - row1 + 1,
!                                                        (int)Columns, invert);
      }
  }
  
***************
*** 1448,1462 ****
   */
      static void
  clip_invert_rectangle(
!     int               row,
!     int               col,
!     int               height,
!     int               width,
!     int               invert)
! {
  #ifdef FEAT_TEXT_PROP
      // this goes on top of all popup windows
      screen_zindex = 32000;
  #endif
  #ifdef FEAT_GUI
      if (gui.in_use)
--- 1484,1519 ----
   */
      static void
  clip_invert_rectangle(
!       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,1512 ****
--- 1564,1579 ----
      {
        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,1546 ****
        if (row == row1)
            start_col = col1;
        else
            start_col = 0;
  
        if (row == row2)
            end_col = col2;
        else
            end_col = Columns;
  
!       line_end_col = clip_get_line_end(row);
  
        /* See if we need to nuke some trailing whitespace */
!       if (end_col >= Columns && (row < row2 || end_col > line_end_col))
        {
            /* Get rid of trailing whitespace */
            end_col = line_end_col;
--- 1597,1627 ----
        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(&clip_star, row);
  
        /* See if we need to nuke some trailing whitespace */
!       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,1561 ****
--- 1637,1643 ----
        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,1705 ****
  
  /*
   * Find the column position for the last non-whitespace character on the given
!  * line.
   */
      static int
! clip_get_line_end(int row)
  {
      int           i;
  
      if (row >= screen_Rows || ScreenLines == NULL)
        return 0;
!     for (i = screen_Columns; i > 0; i--)
        if (ScreenLines[LineOffset[row] + i - 1] != ' ')
            break;
      return i;
--- 1772,1793 ----
  
  /*
   * 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_TEXT_PROP
!           cbd->max_col + 1;
! #else
!           screen_Columns;
! #endif
!                           i > 0; i--)
        if (ScreenLines[LineOffset[row] + i - 1] != ' ')
            break;
      return i;
***************
*** 1720,1726 ****
      /* 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_TOGGLE);
        cb->start.lnum = row1;
        cb->start.col  = col1;
--- 1808,1814 ----
      /* 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;
***************
*** 1729,1735 ****
      /* 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_TOGGLE);
        cb->end.lnum = row2;
        cb->end.col  = col2;
--- 1817,1823 ----
      /* 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;
*** ../vim-8.1.1533/src/testdir/test_popupwin.vim       2019-06-14 
19:23:35.502289836 +0200
--- src/testdir/test_popupwin.vim       2019-06-14 23:11:23.872960635 +0200
***************
*** 319,324 ****
--- 319,357 ----
    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", {})
*** ../vim-8.1.1533/src/testdir/dumps/Test_popupwin_select_01.dump      
2019-06-14 23:36:26.653637674 +0200
--- src/testdir/dumps/Test_popupwin_select_01.dump      2019-06-14 
23:10:20.829190935 +0200
***************
*** 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| 
*** ../vim-8.1.1533/src/testdir/dumps/Test_popupwin_select_02.dump      
2019-06-14 23:36:26.657637645 +0200
--- src/testdir/dumps/Test_popupwin_select_02.dump      2019-06-14 
22:40:51.239667179 +0200
***************
*** 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| 
*** ../vim-8.1.1533/src/version.c       2019-06-14 23:27:24.553231791 +0200
--- src/version.c       2019-06-14 23:35:07.838200123 +0200
***************
*** 779,780 ****
--- 779,782 ----
  {   /* Add new patch number below this line */
+ /**/
+     1534,
  /**/

-- 
hundred-and-one symptoms of being an internet addict:
179. You wonder why your household garbage can doesn't have an
     "empty recycle bin" button.

 /// Bram Moolenaar -- [email protected] -- http://www.Moolenaar.net   \\\
///        sponsor Vim, vote for features -- http://www.Vim.org/sponsor/ \\\
\\\  an exciting new programming language -- http://www.Zimbu.org        ///
 \\\            help me help AIDS victims -- http://ICCF-Holland.org    ///

-- 
-- 
You received this message from the "vim_dev" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/vim_dev/201906142142.x5ELgEEg029669%40masaka.moolenaar.net.
For more options, visit https://groups.google.com/d/optout.

Raspunde prin e-mail lui