mirror of
https://github.com/vim/vim.git
synced 2026-05-28 00:21:37 +02:00
patch 9.2.0407: tabpanel: A few issues with the tabpanel
Problem: Several issues around the tabpanel scrollbar:
1. :set tabpanelopt= completion did not offer "scroll" and
"scrollbar".
2. gt/gT and other tab switches did not update the scrollbar
thumb; the current tab could move outside the visible
panel range without the view following.
3. When tpl_scroll_offset was at its maximum, the thumb's
bottom did not reach the last screen row due to integer
truncation in thumb_top (e.g. 31 tabs on 24 rows + :tablast
left a one-row gap).
4. For align:right the scrollbar was drawn on the panel's
left edge (adjacent to the buffer area), which breaks the
common convention that a vertical scrollbar sits on the
right.
Solution: - Add "scroll" and "scrollbar" to the 'tabpanelopt' expansion
list. Cover the completion in test_options.vim and extend
util/gen_opt_test.vim with the new valid/invalid values;
drop the now-redundant acceptance test from
test_tabpanel.vim.
- In draw_tabpanel(), remember the last-drawn curtab and,
when it changes, adjust tpl_scroll_offset so curtab_row
falls inside [offset, offset + Rows). Mouse wheel and
drag leave curtab unchanged, so the user's chosen offset
is preserved.
- In draw_tabpanel_scrollbar(), compute thumb_top as
(Rows - thumb_height) * tpl_scroll_offset
/ (tpl_total_rows - Rows), mirroring the mapping already
used by tabpanel_drag_scrollbar(). This guarantees the
thumb's bottom reaches the last row at the maximum offset.
- In draw_tabpanel(), place the scrollbar at the tabpanel's
right edge for both align:left and align:right (previously
align:right put it on the panel's left edge next to the
vertical separator). For align:right this means the
scrollbar now sits at the screen's right edge.
- Update :h tabpanel-scroll to describe the new, align-
independent placement.
- Add Test_tabpanel_scrollbar_follows_curtab() and
Test_tabpanel_scrollbar_reaches_bottom() to exercise the
regressions fixed by items 2 and 3.
closes: #20052
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Signed-off-by: Hirohito Higashi <h.east.727@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
This commit is contained in:
committed by
Christian Brabandt
parent
7e76514896
commit
2d43240659
+10
-18
@@ -1,4 +1,4 @@
|
||||
*options.txt* For Vim version 9.2. Last change: 2026 Apr 21
|
||||
*options.txt* For Vim version 9.2. Last change: 2026 Apr 27
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -9062,25 +9062,17 @@ A jump table for the options with a short description can be found at |Q_op|.
|
||||
|
||||
columns:{n} Number of columns of the tabpanel.
|
||||
If this value is 0 or less than 'columns', the
|
||||
tab panel will not be displayed.
|
||||
tabpanel will not be displayed.
|
||||
(default 20)
|
||||
|
||||
scroll Enable mouse wheel scrolling over the tabpanel
|
||||
area when the tab list exceeds the visible
|
||||
screen height. The scroll step is controlled
|
||||
by 'mousescroll'. When disabled (the default),
|
||||
the tabpanel shows the page containing the
|
||||
current tab, with no way to view tabs outside
|
||||
that page.
|
||||
|
||||
scrollbar Reserve a one-column scrollbar in the tabpanel
|
||||
showing the current scroll position. The
|
||||
scrollbar uses the |hl-PmenuSbar| and
|
||||
|hl-PmenuThumb| highlight groups for the track
|
||||
and thumb respectively. Clicking on the
|
||||
scrollbar column jumps the thumb to that
|
||||
position; the thumb can also be dragged.
|
||||
Implies "scroll".
|
||||
scrollbar Reserve a one-column scrollbar at the right
|
||||
edge of the tabpanel showing the current
|
||||
scroll position. The scrollbar uses the
|
||||
|hl-PmenuSbar| and |hl-PmenuThumb| highlight
|
||||
groups for the track and thumb respectively.
|
||||
Clicking on the scrollbar column jumps the
|
||||
thumb to that position; the thumb can also be
|
||||
dragged. See |tabpanel-scroll|.
|
||||
|
||||
vert Use a vertical separator for tabpanel.
|
||||
The vertical separator character is taken from
|
||||
|
||||
+18
-18
@@ -1,4 +1,4 @@
|
||||
*tabpage.txt* For Vim version 9.2. Last change: 2026 Apr 26
|
||||
*tabpage.txt* For Vim version 9.2. Last change: 2026 Apr 27
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -485,33 +485,33 @@ groups: |hl-TabPanel| |hl-TabPanelSel| |hl-TabPanelFill|
|
||||
SCROLLING IN THE TABPANEL: *tabpanel-scroll*
|
||||
|
||||
When the total height of the tab page list exceeds the visible screen height,
|
||||
the tabpanel by default displays the "page" that contains the current tab page
|
||||
and offers no way to view tab pages outside that page.
|
||||
mouse wheel events over the tabpanel area scroll the tab page list up or
|
||||
down. The scroll step follows the 'mousescroll' setting. Wheel events
|
||||
inside the tabpanel area are consumed by the tabpanel and do not trigger
|
||||
|<ScrollWheelUp>| or |<ScrollWheelDown>| mappings.
|
||||
|
||||
To make the tabpanel scrollable, add "scroll" to 'tabpanelopt': >
|
||||
:set tabpanelopt+=scroll
|
||||
The current tab page is always brought into view: when the selected tab
|
||||
page changes (by |gt|, |gT|, |:tabnext| etc.), the panel scrolls so the
|
||||
current entry is visible.
|
||||
|
||||
With "scroll" enabled, mouse wheel events over the tabpanel area scroll the
|
||||
tab page list up or down. The scroll step follows the 'mousescroll' setting.
|
||||
Wheel events inside the tabpanel area are consumed by the tabpanel and do not
|
||||
trigger |<ScrollWheelUp>| or |<ScrollWheelDown>| mappings.
|
||||
|
||||
To additionally show a vertical scrollbar indicating the current scroll
|
||||
position, use "scrollbar": >
|
||||
To show a vertical scrollbar indicating the current scroll position, add
|
||||
"scrollbar" to 'tabpanelopt': >
|
||||
:set tabpanelopt+=scrollbar
|
||||
|
||||
The "scrollbar" value implies "scroll". A one-column scrollbar is reserved at
|
||||
the edge of the tabpanel; clicking on the scrollbar column moves the thumb to
|
||||
A one-column scrollbar is always reserved at the right edge of the
|
||||
tabpanel, regardless of 'align'. For |'tabpanelopt'|=align:left this is
|
||||
the edge adjacent to the buffer windows; for align:right it is the right
|
||||
edge of the screen. Clicking on the scrollbar column moves the thumb to
|
||||
the click position, and the thumb can be dragged to scroll continuously.
|
||||
|
||||
When "vert" is combined with "scrollbar", the scrollbar is drawn next to the
|
||||
vertical separator, on the panel side.
|
||||
When "vert" is combined with "scrollbar", the vertical separator is drawn
|
||||
at the tabpanel's boundary with the buffer area and the scrollbar stays at
|
||||
the tabpanel's right edge.
|
||||
|
||||
The scrollbar uses the |hl-PmenuSbar| highlight group for the track and
|
||||
|hl-PmenuThumb| for the thumb.
|
||||
|
||||
The scroll offset is remembered across redraws but is reset when "scroll" or
|
||||
"scrollbar" is toggled off and back on.
|
||||
The scroll offset is remembered across redraws.
|
||||
|
||||
MOUSE CLICKS IN THE TABPANEL: *tabpanel-mouse*
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
*version9.txt* For Vim version 9.2. Last change: 2026 Apr 26
|
||||
*version9.txt* For Vim version 9.2. Last change: 2026 Apr 27
|
||||
|
||||
|
||||
VIM REFERENCE MANUAL by Bram Moolenaar
|
||||
@@ -52616,8 +52616,8 @@ Other ~
|
||||
- Allow mouse clickable regions in the 'statusline', 'tabline' and the
|
||||
'tabpanel' using the |stl-%[FuncName]| atom.
|
||||
- Enable reflow support in the |:terminal|.
|
||||
- Added "scroll" and "scrollbar" sub-options to 'tabpanelopt' so the tabpanel
|
||||
can scroll when the tab page list exceeds the visible screen height.
|
||||
- Added "scrollbar" sub-option to 'tabpanelopt' so the tabpanel can scroll
|
||||
when the tab page list exceeds the visible screen height.
|
||||
|
||||
Platform specific ~
|
||||
-----------------
|
||||
|
||||
+1
-1
@@ -30,7 +30,7 @@ static char *(p_briopt_values[]) = {"shift:", "min:", "sbr", "list:", "column:",
|
||||
#endif
|
||||
#if defined(FEAT_TABPANEL)
|
||||
// Note: Keep this in sync with tabpanelopt_changed()
|
||||
static char *(p_tplo_values[]) = {"align:", "columns:", "vert", NULL};
|
||||
static char *(p_tplo_values[]) = {"align:", "columns:", "scrollbar", "vert", NULL};
|
||||
static char *(p_tplo_align_values[]) = {"left", "right", NULL};
|
||||
#endif
|
||||
#if defined(FEAT_DIFF)
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
/* tabpanel.c */
|
||||
int tabpanelopt_changed(void);
|
||||
void tabpanel_forget_tabpage(const tabpage_T *tp);
|
||||
int tabpanel_width(void);
|
||||
int tabpanel_leftcol(void);
|
||||
void draw_tabpanel(void);
|
||||
|
||||
+80
-43
@@ -43,11 +43,11 @@ static int opt_scope = OPT_LOCAL;
|
||||
static int tpl_align = ALIGN_LEFT;
|
||||
static int tpl_columns = 20;
|
||||
static bool tpl_is_vert = false;
|
||||
static bool tpl_scroll = false;
|
||||
static bool tpl_scrollbar = false;
|
||||
static int tpl_scroll_offset = 0;
|
||||
static int tpl_total_rows = 0;
|
||||
static int tpl_scrollbar_col = -1; // screen column of scrollbar, -1 if none
|
||||
static int tpl_scrollbar_col = -1; // screen column of scrollbar, -1 if none
|
||||
static tabpage_T *tpl_last_curtab = NULL; // last curtab seen by draw_tabpanel
|
||||
|
||||
typedef struct {
|
||||
win_T *wp;
|
||||
@@ -69,7 +69,6 @@ tabpanelopt_changed(void)
|
||||
int new_align = ALIGN_LEFT;
|
||||
long new_columns = 20;
|
||||
bool new_is_vert = false;
|
||||
bool new_scroll = false;
|
||||
bool new_scrollbar = false;
|
||||
|
||||
p = p_tplo;
|
||||
@@ -107,12 +106,6 @@ tabpanelopt_changed(void)
|
||||
{
|
||||
p += 9;
|
||||
new_scrollbar = true;
|
||||
new_scroll = true;
|
||||
}
|
||||
else if (STRNCMP(p, "scroll", 6) == 0)
|
||||
{
|
||||
p += 6;
|
||||
new_scroll = true;
|
||||
}
|
||||
|
||||
if (*p != ',' && *p != NUL)
|
||||
@@ -124,15 +117,26 @@ tabpanelopt_changed(void)
|
||||
tpl_align = new_align;
|
||||
tpl_columns = new_columns;
|
||||
tpl_is_vert = new_is_vert;
|
||||
if (tpl_scroll != new_scroll)
|
||||
tpl_scroll_offset = 0;
|
||||
tpl_scroll = new_scroll;
|
||||
tpl_scrollbar = new_scrollbar;
|
||||
|
||||
// Re-center the current tab on the next redraw.
|
||||
tpl_last_curtab = NULL;
|
||||
|
||||
shell_new_columns();
|
||||
return OK;
|
||||
}
|
||||
|
||||
/*
|
||||
* Drop any internal reference to "tp", so draw_tabpanel() never compares
|
||||
* against a dangling pointer after the tabpage has been freed.
|
||||
*/
|
||||
void
|
||||
tabpanel_forget_tabpage(const tabpage_T *tp)
|
||||
{
|
||||
if (tpl_last_curtab == tp)
|
||||
tpl_last_curtab = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return the width of tabpanel.
|
||||
*/
|
||||
@@ -264,6 +268,31 @@ tabpanel_append_click_regions(
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Ensure the current tab is visible by adjusting tpl_scroll_offset when
|
||||
* the selected tab has changed since the previous redraw. Mouse wheel or
|
||||
* scrollbar drag operations leave curtab unchanged, so the user's chosen
|
||||
* offset is preserved in those cases.
|
||||
*/
|
||||
static void
|
||||
follow_curtab_if_needed(int curtab_row)
|
||||
{
|
||||
if (Rows <= 0 || curtab == tpl_last_curtab)
|
||||
return;
|
||||
|
||||
if (curtab_row < tpl_scroll_offset)
|
||||
tpl_scroll_offset = curtab_row;
|
||||
else if (curtab_row >= tpl_scroll_offset + Rows)
|
||||
tpl_scroll_offset = curtab_row - Rows + 1;
|
||||
|
||||
int max_offset = tpl_total_rows > Rows ? tpl_total_rows - Rows : 0;
|
||||
|
||||
if (tpl_scroll_offset < 0)
|
||||
tpl_scroll_offset = 0;
|
||||
else if (tpl_scroll_offset > max_offset)
|
||||
tpl_scroll_offset = max_offset;
|
||||
}
|
||||
|
||||
/*
|
||||
* draw the tabpanel.
|
||||
*/
|
||||
@@ -293,30 +322,36 @@ draw_tabpanel(void)
|
||||
int sb_len = tpl_scrollbar ? SCROLL_LEN : 0;
|
||||
int sb_screen_col = -1;
|
||||
|
||||
// The scrollbar is always placed at the right edge of the tabpanel,
|
||||
// regardless of 'align'. The vertical separator sits at the panel's
|
||||
// boundary with the buffer area (left edge for align:right, right edge
|
||||
// for align:left).
|
||||
if (tpl_is_vert)
|
||||
{
|
||||
if (is_right)
|
||||
{
|
||||
// draw main contents in tabpanel
|
||||
do_by_tplmode(TPLMODE_GET_CURTAB_ROW, VERT_LEN + sb_len,
|
||||
maxwidth - VERT_LEN, &curtab_row, NULL);
|
||||
do_by_tplmode(TPLMODE_REDRAW, VERT_LEN + sb_len, maxwidth,
|
||||
// Panel on the right: vert at panel's left edge, scrollbar at
|
||||
// panel's right edge (= screen's right edge).
|
||||
do_by_tplmode(TPLMODE_GET_CURTAB_ROW, VERT_LEN,
|
||||
maxwidth - sb_len, &curtab_row, NULL);
|
||||
follow_curtab_if_needed(curtab_row);
|
||||
do_by_tplmode(TPLMODE_REDRAW, VERT_LEN, maxwidth - sb_len,
|
||||
&curtab_row, NULL);
|
||||
// draw vert separator in tabpanel
|
||||
for (vsrow = 0; vsrow < Rows; vsrow++)
|
||||
screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
|
||||
topframe->fr_width, vs_attr);
|
||||
if (tpl_scrollbar)
|
||||
sb_screen_col = topframe->fr_width + VERT_LEN;
|
||||
sb_screen_col = topframe->fr_width + maxwidth - SCROLL_LEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
// draw main contents in tabpanel
|
||||
// Panel on the left: scrollbar just left of vert, vert at
|
||||
// panel's right edge (boundary with buffer).
|
||||
do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0,
|
||||
maxwidth - VERT_LEN - sb_len, &curtab_row, NULL);
|
||||
follow_curtab_if_needed(curtab_row);
|
||||
do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth - VERT_LEN - sb_len,
|
||||
&curtab_row, NULL);
|
||||
// draw vert separator in tabpanel
|
||||
for (vsrow = 0; vsrow < Rows; vsrow++)
|
||||
screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
|
||||
maxwidth - VERT_LEN, vs_attr);
|
||||
@@ -328,16 +363,20 @@ draw_tabpanel(void)
|
||||
{
|
||||
if (is_right)
|
||||
{
|
||||
do_by_tplmode(TPLMODE_GET_CURTAB_ROW, sb_len, maxwidth,
|
||||
// Panel on the right, no vert: scrollbar at screen's right edge.
|
||||
do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth - sb_len,
|
||||
&curtab_row, NULL);
|
||||
follow_curtab_if_needed(curtab_row);
|
||||
do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth - sb_len,
|
||||
&curtab_row, NULL);
|
||||
do_by_tplmode(TPLMODE_REDRAW, sb_len, maxwidth, &curtab_row, NULL);
|
||||
if (tpl_scrollbar)
|
||||
sb_screen_col = topframe->fr_width;
|
||||
sb_screen_col = topframe->fr_width + maxwidth - SCROLL_LEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth - sb_len,
|
||||
&curtab_row, NULL);
|
||||
follow_curtab_if_needed(curtab_row);
|
||||
do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth - sb_len,
|
||||
&curtab_row, NULL);
|
||||
if (tpl_scrollbar)
|
||||
@@ -354,6 +393,7 @@ draw_tabpanel(void)
|
||||
// A user function may reset KeyTyped, restore it.
|
||||
KeyTyped = saved_KeyTyped;
|
||||
|
||||
tpl_last_curtab = curtab;
|
||||
redraw_tabpanel = FALSE;
|
||||
}
|
||||
|
||||
@@ -606,13 +646,7 @@ do_by_tplmode(
|
||||
args.col_end = col_end;
|
||||
|
||||
if (tplmode != TPLMODE_GET_CURTAB_ROW && args.maxrow > 0)
|
||||
{
|
||||
if (tpl_scroll)
|
||||
args.offsetrow = tpl_scroll_offset;
|
||||
else
|
||||
while (args.offsetrow + args.maxrow <= *pcurtab_row)
|
||||
args.offsetrow += args.maxrow;
|
||||
}
|
||||
args.offsetrow = tpl_scroll_offset;
|
||||
|
||||
tp = first_tabpage;
|
||||
|
||||
@@ -632,16 +666,9 @@ do_by_tplmode(
|
||||
{
|
||||
args.attr = attr_tpls;
|
||||
if (tplmode == TPLMODE_GET_CURTAB_ROW)
|
||||
{
|
||||
// Capture the row of the current tab and keep iterating so
|
||||
// tpl_total_rows receives the true content height below.
|
||||
*pcurtab_row = row;
|
||||
// When scroll mode is active keep iterating so tpl_total_rows
|
||||
// receives the true content height; otherwise bail out early.
|
||||
if (!tpl_scroll)
|
||||
{
|
||||
do_unlet((char_u *)"g:actual_curtabpage", TRUE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
args.attr = attr_tpl;
|
||||
@@ -742,7 +769,7 @@ do_by_tplmode(
|
||||
// Capture the true content height during the GET_CURTAB_ROW pass, which
|
||||
// ignores maxrow and therefore walks every tab. REDRAW stops at the
|
||||
// visible edge so its "row" is clamped and unusable here.
|
||||
if (tplmode == TPLMODE_GET_CURTAB_ROW && tpl_scroll)
|
||||
if (tplmode == TPLMODE_GET_CURTAB_ROW)
|
||||
tpl_total_rows = row;
|
||||
}
|
||||
|
||||
@@ -761,10 +788,21 @@ draw_tabpanel_scrollbar(int screen_col)
|
||||
|
||||
if (tpl_total_rows > Rows && Rows > 0)
|
||||
{
|
||||
int max_offset = tpl_total_rows - Rows;
|
||||
int track_range;
|
||||
|
||||
thumb_height = Rows * Rows / tpl_total_rows;
|
||||
if (thumb_height < 1)
|
||||
thumb_height = 1;
|
||||
thumb_top = Rows * tpl_scroll_offset / tpl_total_rows;
|
||||
|
||||
// Map tpl_scroll_offset onto the track: at offset 0 the thumb's top
|
||||
// is at row 0, at the maximum offset its bottom reaches the last
|
||||
// row. This is the exact inverse of tabpanel_drag_scrollbar().
|
||||
track_range = Rows - thumb_height;
|
||||
if (track_range > 0 && max_offset > 0)
|
||||
thumb_top = track_range * tpl_scroll_offset / max_offset;
|
||||
else
|
||||
thumb_top = 0;
|
||||
if (thumb_top + thumb_height > Rows)
|
||||
thumb_top = Rows - thumb_height;
|
||||
if (thumb_top < 0)
|
||||
@@ -848,7 +886,6 @@ tabpanel_drag_scrollbar(int screen_row)
|
||||
/*
|
||||
* Scroll the tabpanel by 'count' rows in direction 'dir' (1 = down, -1 = up).
|
||||
* Returns true if the offset changed and a redraw was scheduled.
|
||||
* Has no effect unless 'tabpanelopt' contains "scroll".
|
||||
*/
|
||||
bool
|
||||
tabpanel_scroll(int dir, int count)
|
||||
@@ -856,7 +893,7 @@ tabpanel_scroll(int dir, int count)
|
||||
int max_offset;
|
||||
int new_offset;
|
||||
|
||||
if (!tpl_scroll || tabpanel_width() == 0)
|
||||
if (tabpanel_width() == 0)
|
||||
return false;
|
||||
|
||||
max_offset = tpl_total_rows - Rows;
|
||||
|
||||
+8
-8
@@ -1,10 +1,10 @@
|
||||
|1+2&#ffffff0@1|:|t|a|b| @3> +0&&@34
|
||||
|5+8#0000001#e0e0e08|:|t|a|b| @4> +0#0000000#ffffff0@34
|
||||
|6+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
|
||||
|7+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
|
||||
|8+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
|
||||
|9+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
|
||||
|1+8#0000001#e0e0e08|0|:|t|a|b| @3|~+0#4040ff13#ffffff0| @33
|
||||
|1+2#0000000&@1|:|t|a|b| @3|~+0#4040ff13&| @33
|
||||
|1+8#0000001#e0e0e08|2|:|t|a|b| @3|~+0#4040ff13#ffffff0| @33
|
||||
|1+8#0000001#e0e0e08|3|:|t|a|b| @3|~+0#4040ff13#ffffff0| @33
|
||||
|1+8#0000001#e0e0e08|4|:|t|a|b| @3|~+0#4040ff13#ffffff0| @33
|
||||
|1+8#0000001#e0e0e08|5|:|t|a|b| @3|~+0#4040ff13#ffffff0| @33
|
||||
|1+8#0000001#e0e0e08|6|:|t|a|b| @3|~+0#4040ff13#ffffff0| @33
|
||||
|1+8#0000001#e0e0e08|7|:|t|a|b| @3|~+0#4040ff13#ffffff0| @33
|
||||
|1+8#0000001#e0e0e08|8|:|t|a|b| @3|~+0#4040ff13#ffffff0| @33
|
||||
|1+8#0000001#e0e0e08|9|:|t|a|b| @3|~+0#4040ff13#ffffff0| @33
|
||||
|2+8#0000001#e0e0e08|0|:|t|a|b| @3|:+0#0000000#ffffff0|t|a|b|n|e|x|t| |-|3| @6|0|,|0|-|1| @7|A|l@1|
|
||||
|1+8#0000001#e0e0e08|4|:|t|a|b| @3|:+0#0000000#ffffff0|t|a|b|n|e|x|t| |-|3| @6|0|,|0|-|1| @7|A|l@1|
|
||||
|
||||
@@ -593,6 +593,12 @@ func Test_set_completion_string_values()
|
||||
if exists('+tabclose')
|
||||
call assert_equal('left uselast', join(sort(getcompletion('set tabclose=', 'cmdline'))), ' ')
|
||||
endif
|
||||
if has('tabpanel')
|
||||
call assert_equal(['align:', 'columns:', 'scrollbar', 'vert'],
|
||||
\ getcompletion('set tabpanelopt=', 'cmdline'))
|
||||
call assert_equal(['left', 'right'],
|
||||
\ getcompletion('set tabpanelopt=align:', 'cmdline'))
|
||||
endif
|
||||
if exists('+termwintype')
|
||||
call assert_equal('conpty', getcompletion('set termwintype=', 'cmdline')[1])
|
||||
endif
|
||||
|
||||
@@ -963,49 +963,26 @@ func Test_tabpanel_large_columns()
|
||||
call assert_fails(':set tabpanelopt=columns:-1', 'E474:')
|
||||
endfunc
|
||||
|
||||
func Test_tabpanel_scrollopt_accepted()
|
||||
" 'scroll' / 'scrollbar' must be accepted in 'tabpanelopt'.
|
||||
set tabpanelopt=scroll
|
||||
call assert_equal('scroll', &tabpanelopt)
|
||||
set tabpanelopt=scrollbar
|
||||
call assert_equal('scrollbar', &tabpanelopt)
|
||||
|
||||
" Combination with other values.
|
||||
set tabpanelopt=align:right,scroll
|
||||
call assert_equal('align:right,scroll', &tabpanelopt)
|
||||
set tabpanelopt=columns:15,vert,scrollbar
|
||||
call assert_equal('columns:15,vert,scrollbar', &tabpanelopt)
|
||||
set tabpanelopt=align:right,columns:12,vert,scrollbar
|
||||
call assert_equal('align:right,columns:12,vert,scrollbar', &tabpanelopt)
|
||||
|
||||
" Unknown values must still fail.
|
||||
call assert_fails(':set tabpanelopt=scrol', 'E474:')
|
||||
call assert_fails(':set tabpanelopt=scrollbarx', 'E474:')
|
||||
|
||||
call s:reset()
|
||||
endfunc
|
||||
|
||||
func Test_tabpanel_scroll_many_tabs()
|
||||
let save_lines = &lines
|
||||
let save_showtabpanel = &showtabpanel
|
||||
let save_tabpanelopt = &tabpanelopt
|
||||
|
||||
" Make the screen short so the tab list exceeds the visible height.
|
||||
" Make the screen short so the tab page list exceeds the visible height.
|
||||
set lines=8
|
||||
set showtabpanel=2
|
||||
set tabpanelopt=scroll
|
||||
set tabpanelopt=
|
||||
for i in range(20)
|
||||
tabnew
|
||||
endfor
|
||||
|
||||
" Should not crash with many tabs and scroll enabled.
|
||||
" Should not crash with many tabs (scroll behaviour is always on).
|
||||
redraw!
|
||||
|
||||
" Switching to scrollbar resets the offset but must also not crash.
|
||||
" Toggling scrollbar must also not crash.
|
||||
set tabpanelopt=scrollbar
|
||||
redraw!
|
||||
|
||||
" Disabling scroll returns to normal behavior.
|
||||
set tabpanelopt=
|
||||
redraw!
|
||||
|
||||
@@ -1024,6 +1001,94 @@ func Test_tabpanel_scroll_many_tabs()
|
||||
let &lines = save_lines
|
||||
endfunc
|
||||
|
||||
" The scrollbar thumb must follow the current tab when it is moved by
|
||||
" gt/gT/:tabnext/:tablast, so that the selected tab is always visible.
|
||||
func Test_tabpanel_scrollbar_follows_curtab()
|
||||
let save_lines = &lines
|
||||
let save_columns = &columns
|
||||
let save_showtabpanel = &showtabpanel
|
||||
let save_tabpanelopt = &tabpanelopt
|
||||
|
||||
set lines=10 columns=40
|
||||
set showtabpanel=2 tabpanelopt=scrollbar,columns:8
|
||||
for i in range(49)
|
||||
tabnew
|
||||
endfor
|
||||
let sb_col = 8
|
||||
|
||||
" With curtab at the top of the list, row 1 shows the thumb and the
|
||||
" last row shows the track. Record the two attrs for comparison.
|
||||
tabfirst
|
||||
redraw
|
||||
let attr_thumb = screenattr(1, sb_col)
|
||||
let attr_track = screenattr(&lines, sb_col)
|
||||
call assert_notequal(attr_thumb, attr_track)
|
||||
|
||||
" Jump to a tab far outside the visible range: thumb must leave the top.
|
||||
30tabnext
|
||||
redraw
|
||||
call assert_equal(attr_track, screenattr(1, sb_col))
|
||||
|
||||
" Back to the first tab: thumb returns to the top.
|
||||
tabfirst
|
||||
redraw
|
||||
call assert_equal(attr_thumb, screenattr(1, sb_col))
|
||||
call assert_equal(attr_track, screenattr(&lines, sb_col))
|
||||
|
||||
" gT from the first tab wraps to the last: thumb moves to the bottom.
|
||||
normal! gT
|
||||
redraw
|
||||
call assert_equal(attr_track, screenattr(1, sb_col))
|
||||
call assert_equal(attr_thumb, screenattr(&lines, sb_col))
|
||||
|
||||
" gt from the last tab wraps to the first: thumb returns to the top.
|
||||
normal! gt
|
||||
redraw
|
||||
call assert_equal(attr_thumb, screenattr(1, sb_col))
|
||||
call assert_equal(attr_track, screenattr(&lines, sb_col))
|
||||
|
||||
%bwipeout!
|
||||
let &tabpanelopt = save_tabpanelopt
|
||||
let &showtabpanel = save_showtabpanel
|
||||
let &lines = save_lines
|
||||
let &columns = save_columns
|
||||
endfunc
|
||||
|
||||
" With 31 tabs on 24 rows, :tablast must place the scrollbar thumb's
|
||||
" bottom at the last screen row. Before the fix, integer truncation in
|
||||
" thumb_top left a one-row gap at the bottom.
|
||||
func Test_tabpanel_scrollbar_reaches_bottom()
|
||||
let save_lines = &lines
|
||||
let save_columns = &columns
|
||||
let save_showtabpanel = &showtabpanel
|
||||
let save_tabpanelopt = &tabpanelopt
|
||||
|
||||
set lines=24 columns=40
|
||||
set showtabpanel=2 tabpanelopt=scrollbar,columns:8
|
||||
for i in range(30)
|
||||
tabnew
|
||||
endfor
|
||||
let sb_col = 8
|
||||
|
||||
" Identify the thumb attr while the thumb is at the top.
|
||||
tabfirst
|
||||
redraw
|
||||
let attr_thumb = screenattr(1, sb_col)
|
||||
let attr_track = screenattr(&lines, sb_col)
|
||||
call assert_notequal(attr_thumb, attr_track)
|
||||
|
||||
" :tablast must push the thumb all the way to the bottom.
|
||||
tablast
|
||||
redraw
|
||||
call assert_equal(attr_thumb, screenattr(&lines, sb_col))
|
||||
|
||||
%bwipeout!
|
||||
let &tabpanelopt = save_tabpanelopt
|
||||
let &showtabpanel = save_showtabpanel
|
||||
let &lines = save_lines
|
||||
let &columns = save_columns
|
||||
endfunc
|
||||
|
||||
func Test_tabpanel_variable_height()
|
||||
|
||||
let save_lines = &lines
|
||||
|
||||
@@ -330,9 +330,11 @@ let test_values = {
|
||||
\ 'tabline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']],
|
||||
\ 'tabpanel': [['', 'aaa', 'bbb'], []],
|
||||
\ 'tabpanelopt': [['', 'align:left', 'align:right', 'vert', 'columns:0',
|
||||
\ 'columns:20', 'columns:999'],
|
||||
\ 'columns:20', 'columns:999', 'scrollbar',
|
||||
\ 'columns:15,vert,scrollbar',
|
||||
\ 'align:right,columns:12,vert,scrollbar'],
|
||||
\ ['xxx', 'align:', 'align:middle', 'colomns:', 'cols:10',
|
||||
\ 'cols:-1']],
|
||||
\ 'cols:-1', 'scroll', 'scrol', 'scrollbarx']],
|
||||
\ 'tagcase': [['followic', 'followscs', 'ignore', 'match', 'smart'],
|
||||
\ ['', 'xxx', 'smart,match']],
|
||||
\ 'termencoding': [has('gui_gtk') ? [] : ['', 'utf-8'], ['xxx']],
|
||||
|
||||
@@ -729,6 +729,8 @@ static char *(features[]) =
|
||||
|
||||
static int included_patches[] =
|
||||
{ /* Add new patch number below this line */
|
||||
/**/
|
||||
407,
|
||||
/**/
|
||||
406,
|
||||
/**/
|
||||
|
||||
@@ -4784,6 +4784,9 @@ free_tabpage(tabpage_T *tp)
|
||||
|
||||
if (tp == lastused_tabpage)
|
||||
lastused_tabpage = NULL;
|
||||
#ifdef FEAT_TABPANEL
|
||||
tabpanel_forget_tabpage(tp);
|
||||
#endif
|
||||
|
||||
vim_free(tp->tp_localdir);
|
||||
vim_free(tp->tp_prevdir);
|
||||
|
||||
Reference in New Issue
Block a user