patch 8.1.1612: cannot show an existing buffer in a popup window

Problem:    Cannot show an existing buffer in a popup window.
Solution:   Support buffer number argument in popup_create().
This commit is contained in:
Bram Moolenaar
2019-06-30 22:16:10 +02:00
parent 892ae723ab
commit 5b8cfedfbd
12 changed files with 143 additions and 79 deletions

View File

@@ -98,9 +98,6 @@ or by clicking anywhere inside the popup. This must be enabled with the
TODO: TODO:
- Currently 'buftype' is set to "popup", but all the specifics are on the
window. Can we use a "normal" buffer and put the type on the window? (#4595)
What if it's modified and the window closes?
- Add test for when popup with mask is off the left and off the right of the - Add test for when popup with mask is off the left and off the right of the
screen. screen.
- check padding/border when popup is off the left and right of the screen. - check padding/border when popup is off the left and right of the screen.
@@ -164,10 +161,10 @@ Other:
[functions help to be moved to eval.txt later] [functions help to be moved to eval.txt later]
popup_atcursor({text}, {options}) *popup_atcursor()* popup_atcursor({what}, {options}) *popup_atcursor()*
Show the {text} above the cursor, and close it when the cursor Show the {what} above the cursor, and close it when the cursor
moves. This works like: > moves. This works like: >
call popup_create({text}, { call popup_create({what}, {
\ 'pos': 'botleft', \ 'pos': 'botleft',
\ 'line': 'cursor-1', \ 'line': 'cursor-1',
\ 'col': 'cursor', \ 'col': 'cursor',
@@ -191,11 +188,15 @@ popup_close({id} [, {result}]) *popup_close()*
Otherwise zero is passed to the callback. Otherwise zero is passed to the callback.
popup_create({text}, {options}) *popup_create()* popup_create({what}, {options}) *popup_create()*
Open a popup window showing {text}, which is either: Open a popup window showing {what}, which is either:
- a buffer number
- a string - a string
- a list of strings - a list of strings
- a list of text lines with text properties - a list of text lines with text properties
When {what} is not a buffer number, a buffer is created with
'buftype' set to "popup". That buffer will be wiped out once
the popup closes.
{options} is a dictionary with many possible entries. {options} is a dictionary with many possible entries.
See |popup_create-usage| for details. See |popup_create-usage| for details.
@@ -209,9 +210,9 @@ popup_create({text}, {options}) *popup_create()*
< In case of failure zero is returned. < In case of failure zero is returned.
popup_dialog({text}, {options}) *popup_dialog()* popup_dialog({what}, {options}) *popup_dialog()*
Just like |popup_create()| but with these default options: > Just like |popup_create()| but with these default options: >
call popup_create({text}, { call popup_create({what}, {
\ 'pos': 'center', \ 'pos': 'center',
\ 'zindex': 200, \ 'zindex': 200,
\ 'drag': 1, \ 'drag': 1,
@@ -312,12 +313,12 @@ popup_hide({id}) *popup_hide()*
exists but is not a popup window an error is given. *E993* exists but is not a popup window an error is given. *E993*
popup_menu({text}, {options}) *popup_menu()* popup_menu({what}, {options}) *popup_menu()*
Show the {text} near the cursor, handle selecting one of the Show the {what} near the cursor, handle selecting one of the
items with cursorkeys, and close it an item is selected with items with cursorkeys, and close it an item is selected with
Space or Enter. {text} should have multiple lines to make this Space or Enter. {what} should have multiple lines to make this
useful. This works like: > useful. This works like: >
call popup_create({text}, { call popup_create({what}, {
\ 'pos': 'center', \ 'pos': 'center',
\ 'zindex': 200, \ 'zindex': 200,
\ 'drag': 1, \ 'drag': 1,
@@ -349,10 +350,10 @@ popup_move({id}, {options}) *popup_move()*
For other options see |popup_setoptions()|. For other options see |popup_setoptions()|.
popup_notification({text}, {options}) *popup_notification()* popup_notification({what}, {options}) *popup_notification()*
Show the {text} for 3 seconds at the top of the Vim window. Show the {what} for 3 seconds at the top of the Vim window.
This works like: > This works like: >
call popup_create({text}, { call popup_create({what}, {
\ 'line': 1, \ 'line': 1,
\ 'col': 10, \ 'col': 10,
\ 'minwidth': 20, \ 'minwidth': 20,
@@ -410,7 +411,8 @@ popup_setoptions({id}, {options}) *popup_setoptions()*
popup_settext({id}, {text}) *popup_settext()* popup_settext({id}, {text}) *popup_settext()*
Set the text of the buffer in poup win {id}. {text} is the Set the text of the buffer in poup win {id}. {text} is the
same as supplied to |popup_create()|. same as supplied to |popup_create()|, except that a buffer
number is not allowed.
Does not change the window size or position, other than caused Does not change the window size or position, other than caused
by the different text. by the different text.
@@ -450,7 +452,8 @@ POPUP_CREATE() ARGUMENTS *popup_create-usage*
The first argument of |popup_create()| (and the second argument to The first argument of |popup_create()| (and the second argument to
|popup_settext()|) specifies the text to be displayed, and optionally text |popup_settext()|) specifies the text to be displayed, and optionally text
properties. It is in one of three forms: properties. It is in one of four forms:
- a buffer number
- a string - a string
- a list of strings - a list of strings
- a list of dictionaries, where each dictionary has these entries: - a list of dictionaries, where each dictionary has these entries:

View File

@@ -121,6 +121,23 @@ read_buffer(
return retval; return retval;
} }
/*
* Ensure buffer "buf" is loaded. Does not trigger the swap-exists action.
*/
void
buffer_ensure_loaded(buf_T *buf)
{
if (buf->b_ml.ml_mfp == NULL)
{
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
swap_exists_action = SEA_NONE;
open_buffer(FALSE, NULL, 0);
aucmd_restbuf(&aco);
}
}
/* /*
* Open current buffer, that is: open the memfile and read the file into * Open current buffer, that is: open the memfile and read the file into
* memory. * memory.

View File

@@ -1963,15 +1963,8 @@ f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
{ {
buf_T *buf = get_buf_arg(&argvars[0]); buf_T *buf = get_buf_arg(&argvars[0]);
if (buf != NULL && buf->b_ml.ml_mfp == NULL) if (buf != NULL)
{ buffer_ensure_loaded(buf);
aco_save_T aco;
aucmd_prepbuf(&aco, buf);
swap_exists_action = SEA_NONE;
open_buffer(FALSE, NULL, 0);
aucmd_restbuf(&aco);
}
} }
/* /*
@@ -4905,7 +4898,7 @@ f_getchar(typval_T *argvars, typval_T *rettv)
return; return;
(void)mouse_comp_pos(win, &row, &col, &lnum); (void)mouse_comp_pos(win, &row, &col, &lnum);
# ifdef FEAT_TEXT_PROP # ifdef FEAT_TEXT_PROP
if (bt_popup(win->w_buffer)) if (WIN_IS_POPUP(win))
winnr = 0; winnr = 0;
else else
# endif # endif

View File

@@ -4525,7 +4525,7 @@ nv_mousescroll(cmdarg_T *cap)
if (wp == NULL) if (wp == NULL)
return; return;
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
if (bt_popup(wp->w_buffer) && !wp->w_has_scrollbar) if (WIN_IS_POPUP(wp) && !wp->w_has_scrollbar)
return; return;
#endif #endif
curwin = wp; curwin = wp;
@@ -4560,7 +4560,7 @@ nv_mousescroll(cmdarg_T *cap)
nv_scroll_line(cap); nv_scroll_line(cap);
} }
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
if (bt_popup(curwin->w_buffer)) if (WIN_IS_POPUP(curwin))
popup_set_firstline(curwin); popup_set_firstline(curwin);
#endif #endif
} }

View File

@@ -997,14 +997,26 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
win_T *wp; win_T *wp;
tabpage_T *tp = NULL; tabpage_T *tp = NULL;
int tabnr; int tabnr;
buf_T *buf; int new_buffer;
buf_T *buf = NULL;
dict_T *d; dict_T *d;
int nr; int nr;
int i; int i;
// Check arguments look OK. // Check arguments look OK.
if (!(argvars[0].v_type == VAR_STRING && argvars[0].vval.v_string != NULL) if (argvars[0].v_type == VAR_NUMBER)
&& !(argvars[0].v_type == VAR_LIST && argvars[0].vval.v_list != NULL)) {
buf = buflist_findnr( argvars[0].vval.v_number);
if (buf == NULL)
{
semsg(_(e_nobufnr), argvars[0].vval.v_number);
return NULL;
}
}
else if (!(argvars[0].v_type == VAR_STRING
&& argvars[0].vval.v_string != NULL)
&& !(argvars[0].v_type == VAR_LIST
&& argvars[0].vval.v_list != NULL))
{ {
emsg(_(e_listreq)); emsg(_(e_listreq));
return NULL; return NULL;
@@ -1038,8 +1050,22 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
return NULL; return NULL;
rettv->vval.v_number = wp->w_id; rettv->vval.v_number = wp->w_id;
wp->w_popup_pos = POPPOS_TOPLEFT; wp->w_popup_pos = POPPOS_TOPLEFT;
wp->w_popup_flags = POPF_IS_POPUP;
buf = buflist_new(NULL, NULL, (linenr_T)0, BLN_NEW|BLN_LISTED|BLN_DUMMY); if (buf != NULL)
{
// use existing buffer
new_buffer = FALSE;
wp->w_buffer = buf;
++buf->b_nwindows;
buffer_ensure_loaded(buf);
}
else
{
// create a new buffer associated with the popup
new_buffer = TRUE;
buf = buflist_new(NULL, NULL, (linenr_T)0,
BLN_NEW|BLN_LISTED|BLN_DUMMY);
if (buf == NULL) if (buf == NULL)
return NULL; return NULL;
ml_open(buf); ml_open(buf);
@@ -1059,6 +1085,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
// Avoid that 'buftype' is reset when this buffer is entered. // Avoid that 'buftype' is reset when this buffer is entered.
buf->b_p_initialized = TRUE; buf->b_p_initialized = TRUE;
}
if (tp != NULL) if (tp != NULL)
{ {
@@ -1088,6 +1115,7 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
} }
} }
if (new_buffer)
popup_set_buffer_text(buf, argvars[0]); popup_set_buffer_text(buf, argvars[0]);
if (type == TYPE_ATCURSOR) if (type == TYPE_ATCURSOR)
@@ -1456,7 +1484,7 @@ find_popup_win(int id)
{ {
win_T *wp = win_id2wp(id); win_T *wp = win_id2wp(id);
if (wp != NULL && !bt_popup(wp->w_buffer)) if (wp != NULL && !WIN_IS_POPUP(wp))
{ {
semsg(_("E993: window %d is not a popup window"), id); semsg(_("E993: window %d is not a popup window"), id);
return NULL; return NULL;
@@ -1523,10 +1551,15 @@ f_popup_settext(typval_T *argvars, typval_T *rettv UNUSED)
win_T *wp = find_popup_win(id); win_T *wp = find_popup_win(id);
if (wp != NULL) if (wp != NULL)
{
if (argvars[1].v_type != VAR_STRING && argvars[1].v_type != VAR_LIST)
semsg(_(e_invarg2), tv_get_string(&argvars[1]));
else
{ {
popup_set_buffer_text(wp->w_buffer, argvars[1]); popup_set_buffer_text(wp->w_buffer, argvars[1]);
popup_adjust_position(wp); popup_adjust_position(wp);
} }
}
} }
static void static void
@@ -1880,7 +1913,7 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv)
int int
error_if_popup_window() error_if_popup_window()
{ {
if (bt_popup(curwin->w_buffer)) if (WIN_IS_POPUP(curwin))
{ {
emsg(_("E994: Not allowed in a popup window")); emsg(_("E994: Not allowed in a popup window"));
return TRUE; return TRUE;

View File

@@ -1,4 +1,5 @@
/* buffer.c */ /* buffer.c */
void buffer_ensure_loaded(buf_T *buf);
int open_buffer(int read_stdin, exarg_T *eap, int flags); int open_buffer(int read_stdin, exarg_T *eap, int flags);
void set_bufref(bufref_T *bufref, buf_T *buf); void set_bufref(bufref_T *bufref, buf_T *buf);
int bufref_valid(bufref_T *bufref); int bufref_valid(bufref_T *bufref);

View File

@@ -1005,7 +1005,7 @@ get_wcr_attr(win_T *wp)
if (*wp->w_p_wcr != NUL) if (*wp->w_p_wcr != NUL)
wcr_attr = syn_name2attr(wp->w_p_wcr); wcr_attr = syn_name2attr(wp->w_p_wcr);
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
if (bt_popup(wp->w_buffer) && wcr_attr == 0) if (WIN_IS_POPUP(wp) && wcr_attr == 0)
wcr_attr = HL_ATTR(HLF_PNI); wcr_attr = HL_ATTR(HLF_PNI);
#endif #endif
return wcr_attr; return wcr_attr;
@@ -1555,11 +1555,7 @@ win_update(win_T *wp)
if (mid_start == 0) if (mid_start == 0)
{ {
mid_end = wp->w_height; mid_end = wp->w_height;
if (ONE_WINDOW if (ONE_WINDOW && !WIN_IS_POPUP(wp))
#ifdef FEAT_TEXT_PROP
&& !bt_popup(wp->w_buffer)
#endif
)
{ {
/* Clear the screen when it was not done by win_del_lines() or /* Clear the screen when it was not done by win_del_lines() or
* win_ins_lines() above, "screen_cleared" is FALSE or MAYBE * win_ins_lines() above, "screen_cleared" is FALSE or MAYBE
@@ -2085,9 +2081,7 @@ win_update(win_T *wp)
&& wp->w_lines[idx].wl_lnum == lnum && wp->w_lines[idx].wl_lnum == lnum
&& lnum > wp->w_topline && lnum > wp->w_topline
&& !(dy_flags & (DY_LASTLINE | DY_TRUNCATE)) && !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
#ifdef FEAT_TEXT_PROP && !WIN_IS_POPUP(wp)
&& !bt_popup(wp->w_buffer)
#endif
&& srow + wp->w_lines[idx].wl_size > wp->w_height && srow + wp->w_lines[idx].wl_size > wp->w_height
#ifdef FEAT_DIFF #ifdef FEAT_DIFF
&& diff_check_fill(wp, lnum) == 0 && diff_check_fill(wp, lnum) == 0
@@ -2244,7 +2238,7 @@ win_update(win_T *wp)
} }
#endif #endif
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
else if (bt_popup(wp->w_buffer)) else if (WIN_IS_POPUP(wp))
{ {
// popup line that doesn't fit is left as-is // popup line that doesn't fit is left as-is
wp->w_botline = lnum; wp->w_botline = lnum;
@@ -2310,11 +2304,8 @@ win_update(win_T *wp)
// Make sure the rest of the screen is blank // Make sure the rest of the screen is blank
// put '~'s on rows that aren't part of the file. // put '~'s on rows that aren't part of the file.
win_draw_end(wp, win_draw_end(wp, WIN_IS_POPUP(wp) ? ' ' : '~',
#ifdef FEAT_TEXT_PROP ' ', FALSE, row, wp->w_height, HLF_EOB);
bt_popup(wp->w_buffer) ? ' ' :
#endif
'~', ' ', FALSE, row, wp->w_height, HLF_EOB);
} }
#ifdef SYN_TIME_LIMIT #ifdef SYN_TIME_LIMIT
@@ -3673,7 +3664,7 @@ win_line(
area_highlighting = TRUE; area_highlighting = TRUE;
} }
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
if (bt_popup(wp->w_buffer)) if (WIN_IS_POPUP(wp))
screen_line_flags |= SLF_POPUP; screen_line_flags |= SLF_POPUP;
#endif #endif

View File

@@ -559,7 +559,7 @@ func Test_popup_valid_arguments()
endfunc endfunc
func Test_popup_invalid_arguments() func Test_popup_invalid_arguments()
call assert_fails('call popup_create(666, {})', 'E714:') call assert_fails('call popup_create(666, {})', 'E86:')
call popup_clear() call popup_clear()
call assert_fails('call popup_create("text", "none")', 'E715:') call assert_fails('call popup_create("text", "none")', 'E715:')
call popup_clear() call popup_clear()
@@ -1654,3 +1654,18 @@ func Test_popupwin_garbage_collect()
call popup_close(winid) call popup_close(winid)
delfunc MyPopupFilter delfunc MyPopupFilter
endfunc endfunc
func Test_popupwin_with_buffer()
call writefile(['some text', 'in a buffer'], 'XsomeFile')
let buf = bufadd('XsomeFile')
call assert_equal(0, bufloaded(buf))
let winid = popup_create(buf, {})
call assert_notequal(0, winid)
let pos = popup_getpos(winid)
call assert_equal(2, pos.height)
call assert_equal(1, bufloaded(buf))
call popup_close(winid)
call assert_equal({}, popup_getpos(winid))
call assert_equal(1, bufloaded(buf))
exe 'bwipe! ' .. buf
endfunc

View File

@@ -1078,7 +1078,7 @@ clip_start_selection(int col, int row, int repeated_click)
int col_cp = col; int col_cp = col;
wp = mouse_find_win(&row_cp, &col_cp, FIND_POPUP); wp = mouse_find_win(&row_cp, &col_cp, FIND_POPUP);
if (wp != NULL && bt_popup(wp->w_buffer)) if (wp != NULL && WIN_IS_POPUP(wp))
{ {
// Click in a popup window restricts selection to that window, // Click in a popup window restricts selection to that window,
// excluding the border. // excluding the border.
@@ -3052,7 +3052,7 @@ retnomove:
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
// Click in a popup window may start dragging or modeless selection, // Click in a popup window may start dragging or modeless selection,
// but not much else. // but not much else.
if (bt_popup(wp->w_buffer)) if (WIN_IS_POPUP(wp))
{ {
on_sep_line = 0; on_sep_line = 0;
in_popup_win = TRUE; in_popup_win = TRUE;

View File

@@ -777,6 +777,8 @@ static char *(features[]) =
static int included_patches[] = static int included_patches[] =
{ /* Add new patch number below this line */ { /* Add new patch number below this line */
/**/
1612,
/**/ /**/
1611, 1611,
/**/ /**/

View File

@@ -614,8 +614,14 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define VALID_TOPLINE 0x80 // w_topline is valid (for cursor position) #define VALID_TOPLINE 0x80 // w_topline is valid (for cursor position)
// Values for w_popup_flags. // Values for w_popup_flags.
#define POPF_HIDDEN 1 // popup is not displayed #define POPF_IS_POPUP 1 // this is a popup window
#define POPF_HANDLED 2 // popup was just redrawn or filtered #define POPF_HIDDEN 2 // popup is not displayed
#define POPF_HANDLED 4 // popup was just redrawn or filtered
#ifdef FEAT_TEXT_PROP
# define WIN_IS_POPUP(wp) ((wp)->w_popup_flags != 0)
#else
# define WIN_IS_POPUP(wp) 0
#endif
/* /*
* Terminal highlighting attribute bits. * Terminal highlighting attribute bits.

View File

@@ -4887,7 +4887,7 @@ win_free(
int int
win_unlisted(win_T *wp) win_unlisted(win_T *wp)
{ {
return wp == aucmd_win || bt_popup(wp->w_buffer); return wp == aucmd_win || WIN_IS_POPUP(wp);
} }
#if defined(FEAT_TEXT_PROP) || defined(PROTO) #if defined(FEAT_TEXT_PROP) || defined(PROTO)
@@ -4898,7 +4898,10 @@ win_unlisted(win_T *wp)
void void
win_free_popup(win_T *win) win_free_popup(win_T *win)
{ {
if (bt_popup(win->w_buffer))
win_close_buffer(win, DOBUF_WIPE, FALSE); win_close_buffer(win, DOBUF_WIPE, FALSE);
else
close_buffer(win, win->w_buffer, 0, FALSE);
# if defined(FEAT_TIMERS) # if defined(FEAT_TIMERS)
if (win->w_popup_timer != NULL) if (win->w_popup_timer != NULL)
stop_timer(win->w_popup_timer); stop_timer(win->w_popup_timer);
@@ -6605,7 +6608,7 @@ restore_win_noblock(
curbuf = curwin->w_buffer; curbuf = curwin->w_buffer;
} }
#ifdef FEAT_TEXT_PROP #ifdef FEAT_TEXT_PROP
else if (bt_popup(curwin->w_buffer)) else if (WIN_IS_POPUP(curwin))
// original window was closed and now we're in a popup window: Go // original window was closed and now we're in a popup window: Go
// to the first valid window. // to the first valid window.
win_goto(firstwin); win_goto(firstwin);