summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBram Moolenaar <Bram@vim.org>2019-06-30 22:16:10 +0200
committerBram Moolenaar <Bram@vim.org>2019-06-30 22:16:10 +0200
commit5b8cfedfbd19a71a30c73cf44b0aec3da7fc1a24 (patch)
treefdaa4dec72d804fdbaab665d550dc10b3be0dafb
parent892ae723ab95e429222e930cf41b32809567e58e (diff)
downloadvim-git-5b8cfedfbd19a71a30c73cf44b0aec3da7fc1a24.tar.gz
patch 8.1.1612: cannot show an existing buffer in a popup windowv8.1.1612
Problem: Cannot show an existing buffer in a popup window. Solution: Support buffer number argument in popup_create().
-rw-r--r--runtime/doc/popup.txt41
-rw-r--r--src/buffer.c17
-rw-r--r--src/evalfunc.c13
-rw-r--r--src/normal.c4
-rw-r--r--src/popupwin.c81
-rw-r--r--src/proto/buffer.pro1
-rw-r--r--src/screen.c23
-rw-r--r--src/testdir/test_popupwin.vim17
-rw-r--r--src/ui.c4
-rw-r--r--src/version.c2
-rw-r--r--src/vim.h10
-rw-r--r--src/window.c9
12 files changed, 143 insertions, 79 deletions
diff --git a/runtime/doc/popup.txt b/runtime/doc/popup.txt
index 99af0a52e..cfa84d7fe 100644
--- a/runtime/doc/popup.txt
+++ b/runtime/doc/popup.txt
@@ -98,9 +98,6 @@ or by clicking anywhere inside the popup. This must be enabled with the
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
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]
-popup_atcursor({text}, {options}) *popup_atcursor()*
- Show the {text} above the cursor, and close it when the cursor
+popup_atcursor({what}, {options}) *popup_atcursor()*
+ Show the {what} above the cursor, and close it when the cursor
moves. This works like: >
- call popup_create({text}, {
+ call popup_create({what}, {
\ 'pos': 'botleft',
\ 'line': 'cursor-1',
\ 'col': 'cursor',
@@ -191,11 +188,15 @@ popup_close({id} [, {result}]) *popup_close()*
Otherwise zero is passed to the callback.
-popup_create({text}, {options}) *popup_create()*
- Open a popup window showing {text}, which is either:
+popup_create({what}, {options}) *popup_create()*
+ Open a popup window showing {what}, which is either:
+ - a buffer number
- a string
- a list of strings
- 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.
See |popup_create-usage| for details.
@@ -209,9 +210,9 @@ popup_create({text}, {options}) *popup_create()*
< 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: >
- call popup_create({text}, {
+ call popup_create({what}, {
\ 'pos': 'center',
\ 'zindex': 200,
\ 'drag': 1,
@@ -312,12 +313,12 @@ popup_hide({id}) *popup_hide()*
exists but is not a popup window an error is given. *E993*
-popup_menu({text}, {options}) *popup_menu()*
- Show the {text} near the cursor, handle selecting one of the
+popup_menu({what}, {options}) *popup_menu()*
+ Show the {what} near the cursor, handle selecting one of the
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: >
- call popup_create({text}, {
+ call popup_create({what}, {
\ 'pos': 'center',
\ 'zindex': 200,
\ 'drag': 1,
@@ -349,10 +350,10 @@ popup_move({id}, {options}) *popup_move()*
For other options see |popup_setoptions()|.
-popup_notification({text}, {options}) *popup_notification()*
- Show the {text} for 3 seconds at the top of the Vim window.
+popup_notification({what}, {options}) *popup_notification()*
+ Show the {what} for 3 seconds at the top of the Vim window.
This works like: >
- call popup_create({text}, {
+ call popup_create({what}, {
\ 'line': 1,
\ 'col': 10,
\ 'minwidth': 20,
@@ -410,7 +411,8 @@ popup_setoptions({id}, {options}) *popup_setoptions()*
popup_settext({id}, {text}) *popup_settext()*
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
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
|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 list of strings
- a list of dictionaries, where each dictionary has these entries:
diff --git a/src/buffer.c b/src/buffer.c
index ee68bc955..74e0ea6d0 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -122,6 +122,23 @@ read_buffer(
}
/*
+ * 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
* memory.
* Return FAIL for failure, OK otherwise.
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 01afa3d4a..f87fd1f99 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -1963,15 +1963,8 @@ f_bufload(typval_T *argvars, typval_T *rettv UNUSED)
{
buf_T *buf = get_buf_arg(&argvars[0]);
- if (buf != NULL && 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);
- }
+ if (buf != NULL)
+ buffer_ensure_loaded(buf);
}
/*
@@ -4905,7 +4898,7 @@ f_getchar(typval_T *argvars, typval_T *rettv)
return;
(void)mouse_comp_pos(win, &row, &col, &lnum);
# ifdef FEAT_TEXT_PROP
- if (bt_popup(win->w_buffer))
+ if (WIN_IS_POPUP(win))
winnr = 0;
else
# endif
diff --git a/src/normal.c b/src/normal.c
index 2015fd8dc..5c9f929d5 100644
--- a/src/normal.c
+++ b/src/normal.c
@@ -4525,7 +4525,7 @@ nv_mousescroll(cmdarg_T *cap)
if (wp == NULL)
return;
#ifdef FEAT_TEXT_PROP
- if (bt_popup(wp->w_buffer) && !wp->w_has_scrollbar)
+ if (WIN_IS_POPUP(wp) && !wp->w_has_scrollbar)
return;
#endif
curwin = wp;
@@ -4560,7 +4560,7 @@ nv_mousescroll(cmdarg_T *cap)
nv_scroll_line(cap);
}
#ifdef FEAT_TEXT_PROP
- if (bt_popup(curwin->w_buffer))
+ if (WIN_IS_POPUP(curwin))
popup_set_firstline(curwin);
#endif
}
diff --git a/src/popupwin.c b/src/popupwin.c
index a10d4e0a2..3af35b6f0 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -997,14 +997,26 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
win_T *wp;
tabpage_T *tp = NULL;
int tabnr;
- buf_T *buf;
+ int new_buffer;
+ buf_T *buf = NULL;
dict_T *d;
int nr;
int i;
// Check arguments look OK.
- 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))
+ if (argvars[0].v_type == VAR_NUMBER)
+ {
+ 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));
return NULL;
@@ -1038,27 +1050,42 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
return NULL;
rettv->vval.v_number = wp->w_id;
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)
- return NULL;
- ml_open(buf);
+ 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)
+ return NULL;
+ ml_open(buf);
- win_init_popup_win(wp, buf);
+ win_init_popup_win(wp, buf);
- set_local_options_default(wp);
- set_string_option_direct_in_buf(buf, (char_u *)"buftype", -1,
+ set_local_options_default(wp);
+ set_string_option_direct_in_buf(buf, (char_u *)"buftype", -1,
(char_u *)"popup", OPT_FREE|OPT_LOCAL, 0);
- set_string_option_direct_in_buf(buf, (char_u *)"bufhidden", -1,
- (char_u *)"hide", OPT_FREE|OPT_LOCAL, 0);
- buf->b_p_ul = -1; // no undo
- buf->b_p_swf = FALSE; // no swap file
- buf->b_p_bl = FALSE; // unlisted buffer
- buf->b_locked = TRUE;
- wp->w_p_wrap = TRUE; // 'wrap' is default on
+ set_string_option_direct_in_buf(buf, (char_u *)"bufhidden", -1,
+ (char_u *)"hide", OPT_FREE|OPT_LOCAL, 0);
+ buf->b_p_ul = -1; // no undo
+ buf->b_p_swf = FALSE; // no swap file
+ buf->b_p_bl = FALSE; // unlisted buffer
+ buf->b_locked = TRUE;
+ wp->w_p_wrap = TRUE; // 'wrap' is default on
- // Avoid that 'buftype' is reset when this buffer is entered.
- buf->b_p_initialized = TRUE;
+ // Avoid that 'buftype' is reset when this buffer is entered.
+ buf->b_p_initialized = TRUE;
+ }
if (tp != NULL)
{
@@ -1088,7 +1115,8 @@ popup_create(typval_T *argvars, typval_T *rettv, create_type_T type)
}
}
- popup_set_buffer_text(buf, argvars[0]);
+ if (new_buffer)
+ popup_set_buffer_text(buf, argvars[0]);
if (type == TYPE_ATCURSOR)
{
@@ -1456,7 +1484,7 @@ find_popup_win(int 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);
return NULL;
@@ -1524,8 +1552,13 @@ f_popup_settext(typval_T *argvars, typval_T *rettv UNUSED)
if (wp != NULL)
{
- popup_set_buffer_text(wp->w_buffer, argvars[1]);
- popup_adjust_position(wp);
+ 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_adjust_position(wp);
+ }
}
}
@@ -1880,7 +1913,7 @@ f_popup_getoptions(typval_T *argvars, typval_T *rettv)
int
error_if_popup_window()
{
- if (bt_popup(curwin->w_buffer))
+ if (WIN_IS_POPUP(curwin))
{
emsg(_("E994: Not allowed in a popup window"));
return TRUE;
diff --git a/src/proto/buffer.pro b/src/proto/buffer.pro
index 45fcf2b56..010be9c4d 100644
--- a/src/proto/buffer.pro
+++ b/src/proto/buffer.pro
@@ -1,4 +1,5 @@
/* buffer.c */
+void buffer_ensure_loaded(buf_T *buf);
int open_buffer(int read_stdin, exarg_T *eap, int flags);
void set_bufref(bufref_T *bufref, buf_T *buf);
int bufref_valid(bufref_T *bufref);
diff --git a/src/screen.c b/src/screen.c
index 4c3ded2ca..75413451f 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -1005,7 +1005,7 @@ get_wcr_attr(win_T *wp)
if (*wp->w_p_wcr != NUL)
wcr_attr = syn_name2attr(wp->w_p_wcr);
#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);
#endif
return wcr_attr;
@@ -1555,11 +1555,7 @@ win_update(win_T *wp)
if (mid_start == 0)
{
mid_end = wp->w_height;
- if (ONE_WINDOW
-#ifdef FEAT_TEXT_PROP
- && !bt_popup(wp->w_buffer)
-#endif
- )
+ if (ONE_WINDOW && !WIN_IS_POPUP(wp))
{
/* Clear the screen when it was not done by win_del_lines() or
* 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
&& lnum > wp->w_topline
&& !(dy_flags & (DY_LASTLINE | DY_TRUNCATE))
-#ifdef FEAT_TEXT_PROP
- && !bt_popup(wp->w_buffer)
-#endif
+ && !WIN_IS_POPUP(wp)
&& srow + wp->w_lines[idx].wl_size > wp->w_height
#ifdef FEAT_DIFF
&& diff_check_fill(wp, lnum) == 0
@@ -2244,7 +2238,7 @@ win_update(win_T *wp)
}
#endif
#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
wp->w_botline = lnum;
@@ -2310,11 +2304,8 @@ win_update(win_T *wp)
// Make sure the rest of the screen is blank
// put '~'s on rows that aren't part of the file.
- win_draw_end(wp,
-#ifdef FEAT_TEXT_PROP
- bt_popup(wp->w_buffer) ? ' ' :
-#endif
- '~', ' ', FALSE, row, wp->w_height, HLF_EOB);
+ win_draw_end(wp, WIN_IS_POPUP(wp) ? ' ' : '~',
+ ' ', FALSE, row, wp->w_height, HLF_EOB);
}
#ifdef SYN_TIME_LIMIT
@@ -3673,7 +3664,7 @@ win_line(
area_highlighting = TRUE;
}
#ifdef FEAT_TEXT_PROP
- if (bt_popup(wp->w_buffer))
+ if (WIN_IS_POPUP(wp))
screen_line_flags |= SLF_POPUP;
#endif
diff --git a/src/testdir/test_popupwin.vim b/src/testdir/test_popupwin.vim
index a3e6acc5c..32ce96be1 100644
--- a/src/testdir/test_popupwin.vim
+++ b/src/testdir/test_popupwin.vim
@@ -559,7 +559,7 @@ func Test_popup_valid_arguments()
endfunc
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 assert_fails('call popup_create("text", "none")', 'E715:')
call popup_clear()
@@ -1654,3 +1654,18 @@ func Test_popupwin_garbage_collect()
call popup_close(winid)
delfunc MyPopupFilter
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
diff --git a/src/ui.c b/src/ui.c
index 1732fe8ff..1e6c1464a 100644
--- a/src/ui.c
+++ b/src/ui.c
@@ -1078,7 +1078,7 @@ clip_start_selection(int col, int row, int repeated_click)
int col_cp = col;
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,
// excluding the border.
@@ -3052,7 +3052,7 @@ retnomove:
#ifdef FEAT_TEXT_PROP
// Click in a popup window may start dragging or modeless selection,
// but not much else.
- if (bt_popup(wp->w_buffer))
+ if (WIN_IS_POPUP(wp))
{
on_sep_line = 0;
in_popup_win = TRUE;
diff --git a/src/version.c b/src/version.c
index a1c5f88a8..7bd232736 100644
--- a/src/version.c
+++ b/src/version.c
@@ -778,6 +778,8 @@ static char *(features[]) =
static int included_patches[] =
{ /* Add new patch number below this line */
/**/
+ 1612,
+/**/
1611,
/**/
1610,
diff --git a/src/vim.h b/src/vim.h
index cb1d38938..410d9d7e3 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -614,8 +614,14 @@ extern int (*dyn_libintl_wputenv)(const wchar_t *envstring);
#define VALID_TOPLINE 0x80 // w_topline is valid (for cursor position)
// Values for w_popup_flags.
-#define POPF_HIDDEN 1 // popup is not displayed
-#define POPF_HANDLED 2 // popup was just redrawn or filtered
+#define POPF_IS_POPUP 1 // this is a popup window
+#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.
diff --git a/src/window.c b/src/window.c
index d40b06096..b40aae6b2 100644
--- a/src/window.c
+++ b/src/window.c
@@ -4887,7 +4887,7 @@ win_free(
int
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)
@@ -4898,7 +4898,10 @@ win_unlisted(win_T *wp)
void
win_free_popup(win_T *win)
{
- win_close_buffer(win, DOBUF_WIPE, FALSE);
+ if (bt_popup(win->w_buffer))
+ win_close_buffer(win, DOBUF_WIPE, FALSE);
+ else
+ close_buffer(win, win->w_buffer, 0, FALSE);
# if defined(FEAT_TIMERS)
if (win->w_popup_timer != NULL)
stop_timer(win->w_popup_timer);
@@ -6605,7 +6608,7 @@ restore_win_noblock(
curbuf = curwin->w_buffer;
}
#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
// to the first valid window.
win_goto(firstwin);