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.