patch 9.1.1391: Vim does not have a vertical tabpanel

Problem:  Vim does not have a tabpanel
Solution: include the tabpanel feature
          (Naruhiko Nishino, thinca)

closes: #17263

Co-authored-by: thinca <thinca@gmail.com>
Signed-off-by: Naruhiko Nishino <naru123456789@gmail.com>
Signed-off-by: Christian Brabandt <cb@256bit.org>
diff --git a/src/Make_ami.mak b/src/Make_ami.mak
index 4dc86dd..bd8b525 100644
--- a/src/Make_ami.mak
+++ b/src/Make_ami.mak
@@ -162,6 +162,7 @@
 	strings.c \
 	syntax.c \
 	tag.c \
+	tabpanel.c \
 	term.c \
 	termlib.c \
 	testing.c \
diff --git a/src/Make_cyg_ming.mak b/src/Make_cyg_ming.mak
index ab9c3b1..37f9f6c 100644
--- a/src/Make_cyg_ming.mak
+++ b/src/Make_cyg_ming.mak
@@ -875,6 +875,7 @@
 	$(OUTDIR)/spellsuggest.o \
 	$(OUTDIR)/strings.o \
 	$(OUTDIR)/syntax.o \
+	$(OUTDIR)/tabpanel.o \
 	$(OUTDIR)/tag.o \
 	$(OUTDIR)/term.o \
 	$(OUTDIR)/testing.o \
diff --git a/src/Make_mvc.mak b/src/Make_mvc.mak
index d6dbd2b..08016d4 100644
--- a/src/Make_mvc.mak
+++ b/src/Make_mvc.mak
@@ -779,6 +779,7 @@
 	$(OUTDIR)\spellsuggest.obj \
 	$(OUTDIR)\strings.obj \
 	$(OUTDIR)\syntax.obj \
+	$(OUTDIR)\tabpanel.obj \
 	$(OUTDIR)\tag.obj \
 	$(OUTDIR)\term.obj \
 	$(OUTDIR)\testing.obj \
@@ -1778,6 +1779,8 @@
 
 $(OUTDIR)/syntax.obj:	$(OUTDIR) syntax.c  $(INCL)
 
+$(OUTDIR)/tabpanel.obj:	$(OUTDIR) tabpanel.c  $(INCL)
+
 $(OUTDIR)/tag.obj:	$(OUTDIR) tag.c  $(INCL)
 
 $(OUTDIR)/term.obj:	$(OUTDIR) term.c  $(INCL)
@@ -2001,6 +2004,7 @@
 	proto/spellsuggest.pro \
 	proto/strings.pro \
 	proto/syntax.pro \
+	proto/tabpanel.pro \
 	proto/tag.pro \
 	proto/term.pro \
 	proto/testing.pro \
diff --git a/src/Make_vms.mms b/src/Make_vms.mms
index a30ed65..9dce2b5 100644
--- a/src/Make_vms.mms
+++ b/src/Make_vms.mms
@@ -424,6 +424,7 @@
 	spellsuggest.c \
 	strings.c \
 	syntax.c \
+	tabpanel.c \
 	tag.c \
 	term.c \
 	terminal.c \
@@ -559,6 +560,7 @@
 	spellsuggest.obj \
 	strings.obj \
 	syntax.obj \
+	tabpanel.obj \
 	tag.obj \
 	term.obj \
 	terminal.obj \
@@ -1146,6 +1148,10 @@
  ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \
  gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
  errors.h globals.h
+tabpanel.obj : tabpanel.c vim.h [.auto]config.h feature.h os_unix.h   \
+ ascii.h keymap.h termdefs.h macros.h structs.h regexp.h \
+ gui.h beval.h [.proto]gui_beval.pro option.h ex_cmds.h proto.h \
+ errors.h globals.h
 tag.obj : tag.c vim.h [.auto]config.h feature.h os_unix.h   \
  ascii.h keymap.h termdefs.h macros.h structs.h regexp.h gui.h beval.h \
  [.proto]gui_beval.pro option.h ex_cmds.h proto.h errors.h globals.h
diff --git a/src/Makefile b/src/Makefile
index 962e47b..9a1a1cc 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -1576,6 +1576,7 @@
 	spellsuggest.c \
 	strings.c \
 	syntax.c \
+	tabpanel.c \
 	tag.c \
 	term.c \
 	terminal.c \
@@ -1737,6 +1738,7 @@
 	objects/spellsuggest.o \
 	objects/strings.o \
 	objects/syntax.o \
+	objects/tabpanel.o \
 	objects/tag.o \
 	objects/term.o \
 	objects/terminal.o \
@@ -1930,6 +1932,7 @@
 	spellsuggest.pro \
 	strings.pro \
 	syntax.pro \
+	tabpanel.pro \
 	tag.pro \
 	term.pro \
 	terminal.pro \
@@ -3547,6 +3550,9 @@
 objects/syntax.o: syntax.c
 	$(CCC) -o $@ syntax.c
 
+objects/tabpanel.o: tabpanel.c
+	$(CCC) -o $@ tabpanel.c
+
 objects/tag.o: tag.c
 	$(CCC) -o $@ tag.c
 
@@ -4214,6 +4220,11 @@
  proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \
  libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
  globals.h errors.h
+objects/tabpanel.o: tabpanel.c vim.h protodef.h auto/config.h feature.h os_unix.h \
+ auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \
+ proto/gui_beval.pro structs.h regexp.h gui.h \
+ libvterm/include/vterm_keycodes.h alloc.h ex_cmds.h spell.h proto.h \
+ globals.h errors.h
 objects/tag.o: tag.c vim.h protodef.h auto/config.h feature.h os_unix.h \
  auto/osdef.h ascii.h keymap.h termdefs.h macros.h option.h beval.h \
  proto/gui_beval.pro structs.h regexp.h gui.h libvterm/include/vterm.h \
diff --git a/src/change.c b/src/change.c
index c48d254..438bbda 100644
--- a/src/change.c
+++ b/src/change.c
@@ -142,6 +142,9 @@
     ml_setflags(curbuf);
     check_status(curbuf);
     redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
     need_maketitle = TRUE;	    // set window title later
 }
 
@@ -917,6 +920,9 @@
 	    save_file_ff(buf);
 	check_status(buf);
 	redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+	redraw_tabpanel = TRUE;
+#endif
 	need_maketitle = TRUE;	    // set window title later
 	++CHANGEDTICK(buf);
     }
diff --git a/src/clipboard.c b/src/clipboard.c
index fb967dc..d0feb2f 100644
--- a/src/clipboard.c
+++ b/src/clipboard.c
@@ -404,7 +404,7 @@
 	gui_mch_invert_rectangle(row, col, height, width);
     else
 #endif
-	screen_draw_rectangle(row, col, height, width, invert);
+	screen_draw_rectangle(row, col + TPL_LCOL(NULL), height, width, invert);
 #ifdef FEAT_PROP_POPUP
     screen_zindex = 0;
 #endif
diff --git a/src/drawline.c b/src/drawline.c
index 57ee9a5..3be9a3a 100644
--- a/src/drawline.c
+++ b/src/drawline.c
@@ -875,7 +875,7 @@
 	}
     }
 
-    screen_line(wp, wlv->screen_row, wp->w_wincol, wlv->col,
+    screen_line(wp, wlv->screen_row, wp->w_wincol + TPL_LCOL(wp), wlv->col,
 		    clear_end ? wp->w_width : -wp->w_width,
 		    wlv->vcol - 1, wlv->screen_line_flags);
 }
@@ -4355,7 +4355,7 @@
 #ifdef FEAT_PROP_POPUP
 		     && !text_prop_above && !text_prop_follows
 #endif
-		     && wp->w_width == Columns)
+		     && wp->w_width == COLUMNS_WITHOUT_TPL())
 	    {
 		// Remember that the line wraps, used for modeless copy.
 		LineWraps[wlv.screen_row - 1] = TRUE;
@@ -4380,7 +4380,7 @@
 									  == 2
 				 || (*mb_off2cells)(
 				     LineOffset[wlv.screen_row - 1]
-							    + (int)Columns - 2,
+							    + (int)COLUMNS_WITHOUT_TPL() - 2,
 				     LineOffset[wlv.screen_row]
 						      + screen_Columns) == 2)))
 		{
@@ -4390,17 +4390,17 @@
 		    // auto-wrap, we overwrite the character.
 		    if (screen_cur_col != wp->w_width)
 			screen_char(LineOffset[wlv.screen_row - 1]
-						       + (unsigned)Columns - 1,
-				       wlv.screen_row - 1, (int)(Columns - 1));
+						       + (unsigned)COLUMNS_WITHOUT_TPL() - 1,
+				       wlv.screen_row - 1, (int)(COLUMNS_WITHOUT_TPL() - 1));
 
 		    // When there is a multi-byte character, just output a
 		    // space to keep it simple.
 		    if (has_mbyte && MB_BYTE2LEN(ScreenLines[LineOffset[
-				     wlv.screen_row - 1] + (Columns - 1)]) > 1)
+				     wlv.screen_row - 1] + (COLUMNS_WITHOUT_TPL() - 1)]) > 1)
 			out_char(' ');
 		    else
 			out_char(ScreenLines[LineOffset[wlv.screen_row - 1]
-							    + (Columns - 1)]);
+							    + (COLUMNS_WITHOUT_TPL() - 1)]);
 		    // force a redraw of the first char on the next line
 		    ScreenAttrs[LineOffset[wlv.screen_row]] = (sattr_T)-1;
 		    screen_start();	// don't know where cursor is now
diff --git a/src/drawscreen.c b/src/drawscreen.c
index 4736bf1..1e71cae 100644
--- a/src/drawscreen.c
+++ b/src/drawscreen.c
@@ -209,6 +209,9 @@
 		    redraw_cmdline = TRUE;
 		redraw_tabline = TRUE;
 	    }
+#if defined(FEAT_TABPANEL)
+	    redraw_tabpanel = TRUE;
+#endif
 	}
 	msg_scrolled = 0;
 	need_wait_return = FALSE;
@@ -265,6 +268,11 @@
     if (redraw_tabline || type >= UPD_NOT_VALID)
 	draw_tabline();
 
+#if defined(FEAT_TABPANEL)
+    if (redraw_tabpanel || type >= UPD_NOT_VALID)
+	draw_tabpanel();
+#endif
+
 #ifdef FEAT_SYN_HL
     // Correct stored syntax highlighting info for changes in each displayed
     // buffer.  Each buffer must only be done once.
@@ -331,6 +339,10 @@
 	    win_redr_status(wp, TRUE); // any popup menu will be redrawn below
 	}
     }
+#if defined(FEAT_TABPANEL)
+    if (redraw_tabpanel)
+	draw_tabpanel();
+#endif
 #if defined(FEAT_SEARCH_EXTRA)
     end_search_hl();
 #endif
@@ -529,14 +541,13 @@
 	    plen = this_ru_col - 1;
 	}
 
-	screen_puts(p, row, wp->w_wincol, attr);
-	screen_fill(row, row + 1, plen + wp->w_wincol,
-			this_ru_col + wp->w_wincol, fillchar, fillchar, attr);
-
+	screen_puts(p, row, wp->w_wincol + TPL_LCOL(wp), attr);
+	screen_fill(row, row + 1, plen + wp->w_wincol + TPL_LCOL(wp),
+			this_ru_col + wp->w_wincol + TPL_LCOL(wp), fillchar, fillchar, attr);
 	if ((NameBufflen = get_keymap_str(wp, (char_u *)"<%s>", NameBuff, MAXPATHL)) > 0
 		&& (this_ru_col - plen) > (NameBufflen + 1))
 	    screen_puts(NameBuff, row, (int)(this_ru_col - NameBufflen
-						   - 1 + wp->w_wincol), attr);
+						   - 1 + wp->w_wincol + TPL_LCOL(wp)), attr);
 
 	win_redr_ruler(wp, TRUE, ignore_pum);
 
@@ -561,7 +572,8 @@
 	    fillchar = fillchar_status(&attr, wp);
 	else
 	    fillchar = fillchar_vsep(&attr, wp);
-	screen_putchar(fillchar, row, W_ENDCOL(wp), attr);
+	if (W_ENDCOL(wp) < COLUMNS_WITHOUT_TPL())
+	    screen_putchar(fillchar, row, W_ENDCOL(wp) + TPL_LCOL(wp), attr);
     }
     busy = FALSE;
 }
@@ -620,6 +632,11 @@
     // Redraw the tab pages line if needed.
     if (redraw_tabline)
 	draw_tabline();
+
+#if defined(FEAT_TABPANEL)
+    if (redraw_tabpanel)
+	draw_tabpanel();
+#endif
 }
 
     void
@@ -781,11 +798,11 @@
 	    buffer[bufferlen] = NUL;
 	}
 
-	screen_puts(buffer, row, this_ru_col + off, attr);
+	screen_puts(buffer, row, this_ru_col + off + TPL_LCOL(wp), attr);
 	n1 = redraw_cmdline;
 	screen_fill(row, row + 1,
-		this_ru_col + off + bufferlen,
-		(off + width),
+		this_ru_col + off + bufferlen + TPL_LCOL(wp),
+		(off + width) + TPL_LCOL(wp),
 		fillchar, fillchar, attr);
 	// don't redraw the cmdline because of showing the ruler
 	redraw_cmdline = n1;
@@ -1026,8 +1043,8 @@
     }
     wp->w_winbar_items[item_idx].wb_menu = NULL; // end marker
 
-    screen_line(wp, wp->w_winrow, wp->w_wincol, wp->w_width, wp->w_width, -1,
-									    0);
+    screen_line(wp, wp->w_winrow, wp->w_wincol + TPL_LCOL(wp), wp->w_width,
+							  wp->w_width, -1, 0);
 }
 #endif
 
@@ -1361,8 +1378,8 @@
     }
 #endif
 
-    screen_line(wp, row + W_WINROW(wp), wp->w_wincol,
-					      wp->w_width, wp->w_width, -1, 0);
+    screen_line(wp, row + W_WINROW(wp), wp->w_wincol + TPL_LCOL(wp),
+						wp->w_width, wp->w_width, -1, 0);
 
     // Update w_cline_height and w_cline_folded if the cursor line was
     // updated (saves a call to plines() later).
@@ -2672,8 +2689,8 @@
 	    // Last line isn't finished: Display "@@@" at the end.
 	    screen_fill(W_WINROW(wp) + wp->w_height - 1,
 		    W_WINROW(wp) + wp->w_height,
-		    start_col < wp->w_wincol ? wp->w_wincol : start_col,
-		    (int)W_ENDCOL(wp),
+		    (start_col < wp->w_wincol ? wp->w_wincol : start_col) + TPL_LCOL(wp),
+		    (int)W_ENDCOL(wp) + TPL_LCOL(wp),
 		    symbol, symbol, HL_ATTR(HLF_AT));
 	    set_empty_rows(wp, srow);
 	    wp->w_botline = lnum;
@@ -2898,6 +2915,11 @@
 	    win_redr_status(wp, FALSE);
     }
 
+#if defined(FEAT_TABPANEL)
+    if (redraw_tabpanel)
+	draw_tabpanel();
+#endif
+
     update_finish();
 }
 #endif
@@ -2930,6 +2952,11 @@
     if (redraw_tabline)
 	draw_tabline();
 
+#if defined(FEAT_TABPANEL)
+    if (redraw_tabpanel)
+	draw_tabpanel();
+#endif
+
     if (wp->w_redr_status || p_ru
 # ifdef FEAT_STL_OPT
 	    || *p_stl != NUL || *wp->w_p_stl != NUL
@@ -3328,6 +3355,11 @@
 	    win_redr_status(wp, FALSE);
     if (redraw_tabline)
 	draw_tabline();
+
+#if defined(FEAT_TABPANEL)
+    if (redraw_tabpanel)
+	draw_tabpanel();
+#endif
 }
 
 /*
diff --git a/src/edit.c b/src/edit.c
index 3c98bb8..4d45e8e 100644
--- a/src/edit.c
+++ b/src/edit.c
@@ -1714,7 +1714,7 @@
 
 	    if (fix_col != pc_col)
 	    {
-		screen_putchar(' ', pc_row, fix_col, attr);
+		screen_putchar(' ', pc_row, fix_col + TPL_LCOL(NULL), attr);
 		--curwin->w_wcol;
 		pc_status = PC_STATUS_RIGHT;
 	    }
@@ -1734,7 +1734,7 @@
 	screen_getbytes(pc_row, pc_col, pc_bytes, &pc_attr);
 	pc_status = PC_STATUS_SET;
     }
-    screen_putchar(c, pc_row, pc_col, attr);
+    screen_putchar(c, pc_row, pc_col + TPL_LCOL(NULL), attr);
 }
 
 #if defined(FEAT_JOB_CHANNEL) || defined(PROTO)
diff --git a/src/errors.h b/src/errors.h
index d718507..eddfc1b 100644
--- a/src/errors.h
+++ b/src/errors.h
@@ -3730,3 +3730,5 @@
 #endif
 EXTERN char e_cannot_switch_to_a_closing_buffer[]
 	INIT(= N_("E1546: Cannot switch to a closing buffer"));
+EXTERN char e_cannot_not_support_redrawtabpanel[]
+	INIT(= N_("E1547: This version of Vim does support :redrawtabpanel"));
diff --git a/src/evalfunc.c b/src/evalfunc.c
index 74afd9d..76955a7 100644
--- a/src/evalfunc.c
+++ b/src/evalfunc.c
@@ -7415,6 +7415,13 @@
 		0
 #endif
 		},
+	{"tabpanel",
+#if defined(FEAT_TABPANEL)
+		1,
+#else
+		0,
+#endif
+	},
 	{"tag_binary", 1},	// graduated feature
 	{"tcl",
 #if defined(FEAT_TCL) && !defined(DYNAMIC_TCL)
diff --git a/src/ex_cmdidxs.h b/src/ex_cmdidxs.h
index 609a81d..1f01c2f 100644
--- a/src/ex_cmdidxs.h
+++ b/src/ex_cmdidxs.h
@@ -23,14 +23,14 @@
   /* p */ 341,
   /* q */ 382,
   /* r */ 385,
-  /* s */ 405,
-  /* t */ 475,
-  /* u */ 522,
-  /* v */ 533,
-  /* w */ 554,
-  /* x */ 568,
-  /* y */ 578,
-  /* z */ 579
+  /* s */ 406,
+  /* t */ 476,
+  /* u */ 523,
+  /* v */ 534,
+  /* w */ 555,
+  /* x */ 569,
+  /* y */ 579,
+  /* z */ 580
 };
 
 /*
@@ -58,7 +58,7 @@
   /* o */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  1,  2,  5,  0,  0,  0,  0,  0,  0,  9,  0, 11,  0,  0,  0 },
   /* p */ {  1,  3,  4,  0,  5,  0,  0,  0,  0,  0,  0,  0,  0,  0,  8, 10,  0,  0, 17, 18, 27,  0, 29,  0, 30,  0 },
   /* q */ {  2,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
-  /* r */ {  0,  0,  0,  0,  0,  0,  0,  0, 12,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 14, 19,  0,  0,  0,  0 },
+  /* r */ {  0,  0,  0,  0,  0,  0,  0,  0, 13,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 15, 20,  0,  0,  0,  0 },
   /* s */ {  2,  6, 15,  0, 19, 23,  0, 25, 26,  0,  0, 29, 31, 35, 39, 41,  0, 50,  0, 51,  0, 64, 65,  0, 66,  0 },
   /* t */ {  2,  0, 19,  0, 24, 26,  0, 27,  0, 29,  0, 30, 34, 37, 39, 40,  0, 41, 43,  0, 44,  0,  0,  0, 46,  0 },
   /* u */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 10,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 },
@@ -69,4 +69,4 @@
   /* z */ {  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0 }
 };
 
-static const int command_count = 596;
+static const int command_count = 597;
diff --git a/src/ex_cmds.c b/src/ex_cmds.c
index 4eb67e3..d3d757b 100644
--- a/src/ex_cmds.c
+++ b/src/ex_cmds.c
@@ -1854,6 +1854,9 @@
 	if (rename_buffer(eap->arg) == FAIL)
 	    return;
 	redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+	redraw_tabpanel = TRUE;
+#endif
     }
 
     // print file name if no argument or 'F' is not in 'shortmess'
@@ -2100,6 +2103,9 @@
 	    {
 		curbuf->b_p_ro = FALSE;
 		redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+		redraw_tabpanel = TRUE;
+#endif
 	    }
 	}
 
diff --git a/src/ex_cmds.h b/src/ex_cmds.h
index 0659f87..fb8d62f 100644
--- a/src/ex_cmds.h
+++ b/src/ex_cmds.h
@@ -1292,6 +1292,9 @@
 EXCMD(CMD_redrawtabline, "redrawtabline", ex_redrawtabline,
 	EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
 	ADDR_NONE),
+EXCMD(CMD_redrawtabpanel, "redrawtabpanel", ex_redrawtabpanel,
+	EX_TRLBAR|EX_CMDWIN|EX_LOCK_OK,
+	ADDR_NONE),
 EXCMD(CMD_registers,	"registers",	ex_display,
 	EX_EXTRA|EX_NOTRLCOM|EX_TRLBAR|EX_SBOXOK|EX_CMDWIN|EX_LOCK_OK,
 	ADDR_NONE),
diff --git a/src/ex_docmd.c b/src/ex_docmd.c
index b87e3c7..a929465 100644
--- a/src/ex_docmd.c
+++ b/src/ex_docmd.c
@@ -247,6 +247,7 @@
 static void	ex_redir(exarg_T *eap);
 static void	ex_redrawstatus(exarg_T *eap);
 static void	ex_redrawtabline(exarg_T *eap);
+static void	ex_redrawtabpanel(exarg_T *eap);
 static void	close_redir(void);
 static void	ex_mark(exarg_T *eap);
 static void	ex_startinsert(exarg_T *eap);
@@ -8233,7 +8234,7 @@
     {
 	n = W_WINROW(curwin) + curwin->w_wrow - msg_scrolled;
 	if (n >= 0)
-	    windgoto(n, curwin->w_wincol + curwin->w_wcol);
+	    windgoto(n, curwin->w_wincol + curwin->w_wcol + TPL_LCOL(curwin));
     }
 
     len = eap->line2;
@@ -8992,6 +8993,29 @@
     out_flush();
 }
 
+/*
+ * ":redrawtabpanel": force redraw of the tabpanel
+ */
+    static void
+ex_redrawtabpanel(exarg_T *eap UNUSED)
+{
+    int save_RedrawingDisabled = RedrawingDisabled;
+    RedrawingDisabled = 0;
+
+    int save_p_lz = p_lz;
+    p_lz = FALSE;
+
+#if defined(FEAT_TABPANEL)
+    draw_tabpanel();
+#else
+    emsg(_(e_cannot_not_support_redrawtabpanel));
+#endif
+
+    RedrawingDisabled = save_RedrawingDisabled;
+    p_lz = save_p_lz;
+    out_flush();
+}
+
     static void
 close_redir(void)
 {
diff --git a/src/feature.h b/src/feature.h
index 703a72f..56d1958 100644
--- a/src/feature.h
+++ b/src/feature.h
@@ -524,6 +524,13 @@
 #endif
 
 /*
+ * +tabpanel		Tab SideBar
+ */
+#ifdef FEAT_HUGE
+# define FEAT_TABPANEL
+#endif
+
+/*
  * +browse		":browse" command.
  *			or just the ":browse" command modifier
  */
diff --git a/src/fileio.c b/src/fileio.c
index f6e35ab..2c6c40e 100644
--- a/src/fileio.c
+++ b/src/fileio.c
@@ -3534,6 +3534,9 @@
     }
     status_redraw_all();
     redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
 #if defined(FEAT_PROP_POPUP) && defined(FEAT_QUICKFIX)
     popup_update_preview_title();
 #endif
diff --git a/src/globals.h b/src/globals.h
index 7006364..f143c8f 100644
--- a/src/globals.h
+++ b/src/globals.h
@@ -1056,6 +1056,10 @@
 EXTERN tabpage_T    *lastused_tabpage;
 EXTERN int	    redraw_tabline INIT(= FALSE);  // need to redraw tabline
 
+#if defined(FEAT_TABPANEL)
+EXTERN int	    redraw_tabpanel INIT(= FALSE);  // need to redraw tabpanel
+#endif
+
 /*
  * All buffers are linked in a list. 'firstbuf' points to the first entry,
  * 'lastbuf' to the last entry and 'curbuf' to the currently active buffer.
diff --git a/src/gui.c b/src/gui.c
index 7b61381..41647d6 100644
--- a/src/gui.c
+++ b/src/gui.c
@@ -4906,6 +4906,9 @@
 
     row = Y_2_ROW(y);
     col = X_2_COL(x);
+
+    col -= TPL_LCOL(NULL);
+
     if (row < 0 || col < 0)		// before first window
 	return NULL;
     wp = mouse_find_win(&row, &col, popup);
@@ -5376,6 +5379,8 @@
     int		col = X_2_COL(x);
     win_T	*wp;
 
+    col -= TPL_LCOL(NULL);
+
     if (row < 0 || col < 0)
 	return;
 
diff --git a/src/highlight.c b/src/highlight.c
index 6567035..807753a 100644
--- a/src/highlight.c
+++ b/src/highlight.c
@@ -249,6 +249,9 @@
 	 "TabLineSel term=bold cterm=bold gui=bold"),
     CENT("TabLineFill term=reverse cterm=reverse",
 	 "TabLineFill term=reverse cterm=reverse gui=reverse"),
+    "default link TabPanel TabLine",
+    "default link TabPanelSel TabLineSel",
+    "default link TabPanelFill TabLineFill",
 #ifdef FEAT_GUI
     "Cursor guibg=fg guifg=bg",
     "lCursor guibg=fg guifg=bg", // should be different, but what?
diff --git a/src/misc2.c b/src/misc2.c
index 909812c..7912577 100644
--- a/src/misc2.c
+++ b/src/misc2.c
@@ -1879,6 +1879,9 @@
     // This may cause the buffer to become (un)modified.
     check_status(curbuf);
     redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
     need_maketitle = TRUE;	    // set window title later
 }
 
diff --git a/src/mouse.c b/src/mouse.c
index 4e10e72..65540e5 100644
--- a/src/mouse.c
+++ b/src/mouse.c
@@ -232,6 +232,9 @@
     int		moved;		// Has cursor moved?
     int		in_status_line;	// mouse in status line
     static int	in_tab_line = FALSE; // mouse clicked in tab line
+#if defined(FEAT_TABPANEL)
+    static int	in_tabpanel = FALSE; // mouse clicked in tabpanel
+#endif
     int		in_sep_line;	// mouse in vertical separator line
     int		c1, c2;
 #if defined(FEAT_FOLDING)
@@ -342,9 +345,16 @@
 	if (!is_drag)			// release, reset got_click
 	{
 	    got_click = FALSE;
-	    if (in_tab_line)
+	    if (in_tab_line
+#if defined(FEAT_TABPANEL)
+		|| in_tabpanel
+#endif
+		    )
 	    {
 		in_tab_line = FALSE;
+#if defined(FEAT_TABPANEL)
+		in_tabpanel = FALSE;
+#endif
 		return FALSE;
 	    }
 	}
@@ -469,6 +479,78 @@
 
     start_visual.lnum = 0;
 
+    // Check for clicking in the tab page line.
+#if defined(FEAT_TABPANEL)
+    if (mouse_col < TPL_LCOL(NULL))
+    {
+	if (is_drag)
+	{
+	    if (in_tabpanel)
+	    {
+		c1 = get_tabpagenr_on_tabpanel();
+		tabpage_move(c1 <= 0 ? 9999 : c1 < tabpage_index(curtab)
+								? c1 - 1 : c1);
+	    }
+	    return FALSE;
+	}
+
+	// click in a tab selects that tab page
+	if (is_click
+# ifdef FEAT_CMDWIN
+		&& cmdwin_type == 0
+# endif
+		&& mouse_col < Columns)
+	{
+	    in_tabpanel = TRUE;
+	    c1 = get_tabpagenr_on_tabpanel();
+	    if (c1 >= 0)
+	    {
+		if ((mod_mask & MOD_MASK_MULTI_CLICK) == MOD_MASK_2CLICK)
+		{
+		    // double click opens new page
+		    end_visual_mode();
+		    tabpage_new();
+		    tabpage_move(c1 == 0 ? 9999 : c1 - 1);
+		}
+		else
+		{
+		    // Go to specified tab page, or next one if not clicking
+		    // on a label.
+		    goto_tabpage(c1);
+
+		    // It's like clicking on the status line of a window.
+		    if (curwin != old_curwin)
+			end_visual_mode();
+		}
+	    }
+	    else
+	    {
+		tabpage_T	*tp;
+
+		// Close the current or specified tab page.
+		if (c1 == -999)
+		    tp = curtab;
+		else
+		    tp = find_tabpage(-c1);
+		if (tp == curtab)
+		{
+		    if (first_tabpage->tp_next != NULL)
+			tabpage_close(FALSE);
+		}
+		else if (tp != NULL)
+		    tabpage_close_other(tp, FALSE);
+	    }
+	}
+	return TRUE;
+    }
+    else if (is_drag && in_tabpanel)
+    {
+	c1 = get_tabpagenr_on_tabpanel();
+	tabpage_move(c1 <= 0 ? 9999 : c1 - 1);
+	return FALSE;
+    }
+#endif
+
     if (TabPageIdxs != NULL)  // only when initialized
     {
 	// Check for clicking in the tab page line.
@@ -1643,6 +1725,10 @@
     int		mouse_char = ' ';
 #endif
 
+    col -= TPL_LCOL(NULL);
+    if (col < 0)
+	return IN_TABPANEL;
+
     mouse_past_bottom = FALSE;
     mouse_past_eol = FALSE;
 
@@ -1727,7 +1813,7 @@
 
     if (!(flags & MOUSE_FOCUS))
     {
-	if (row < 0 || col < 0)			// check if it makes sense
+	if (row < 0 || col + TPL_LCOL(NULL) < 0) // check if it makes sense
 	    return IN_UNKNOWN;
 
 	// find the window where the row is in and adjust "row" and "col" to be
@@ -3247,6 +3333,9 @@
 	    winid = wp->w_id;
 	    winrow = row + 1;
 	    wincol = col + 1;
+	    wincol -= TPL_LCOL(NULL);
+	    if (wincol < 0)
+		wincol = 0;
 	    row -= top_off;
 	    col -= left_off;
 	    if (row >= 0 && row < wp->w_height && col >= 0 && col < wp->w_width)
diff --git a/src/netbeans.c b/src/netbeans.c
index 5cbbab7..4f53785 100644
--- a/src/netbeans.c
+++ b/src/netbeans.c
@@ -1747,6 +1747,9 @@
 	    {
 		check_status(buf->bufp);
 		redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+		redraw_tabpanel = TRUE;
+#endif
 		maketitle();
 		update_screen(0);
 	    }
diff --git a/src/option.c b/src/option.c
index ab9ee66..d6a0098 100644
--- a/src/option.c
+++ b/src/option.c
@@ -3107,6 +3107,9 @@
 {
     need_maketitle = TRUE;
     redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
 }
 
 /*
@@ -8832,6 +8835,18 @@
 #endif
 }
 
+#if defined(FEAT_TABPANEL)
+/*
+ * Process the new 'showtabpanel' option value.
+ */
+    char *
+did_set_showtabpanel(optset_T *args)
+{
+    shell_new_columns();
+    return NULL;
+}
+#endif
+
 #if defined(FEAT_EVAL) || defined(PROTO)
     static void
 didset_options_sctx(int opt_flags, char **buf)
diff --git a/src/option.h b/src/option.h
index bb1226e..e78a7cb 100644
--- a/src/option.h
+++ b/src/option.h
@@ -984,7 +984,15 @@
 #define SWB_NEWTAB		0x008
 #define SWB_VSPLIT		0x010
 #define SWB_USELAST		0x020
+
 EXTERN char_u	*p_spk;		// 'splitkeep'
+
+#if defined(FEAT_TABPANEL)
+EXTERN char_u	*p_tpl;		// 'tabpanel'
+EXTERN long	p_stpl;		// 'showtabpanel'
+EXTERN char_u	*p_tplo;	// 'tabpanelopt'
+#endif
+
 #ifdef FEAT_SYN_HL
 EXTERN char_u	*p_syn;		// 'syntax'
 #endif
diff --git a/src/optiondefs.h b/src/optiondefs.h
index f035104..d509463 100644
--- a/src/optiondefs.h
+++ b/src/optiondefs.h
@@ -305,7 +305,7 @@
 # define ISP_LATIN1 (char_u *)"@,161-255"
 #endif
 
-# define HIGHLIGHT_INIT "8:SpecialKey,~:EndOfBuffer,@:NonText,d:Directory,e:ErrorMsg,i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow,N:CursorLineNr,G:CursorLineSign,O:CursorLineFold,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,E:DiffTextAdd,>:SignColumn,-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,k:PmenuMatch,<:PmenuMatchSel,[:PmenuKind,]:PmenuKindSel,{:PmenuExtra,}:PmenuExtraSel,x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine,z:StatusLineTerm,Z:StatusLineTermNC,g:MsgArea,h:ComplMatchIns"
+# define HIGHLIGHT_INIT "8:SpecialKey,~:EndOfBuffer,@:NonText,d:Directory,e:ErrorMsg,i:IncSearch,l:Search,y:CurSearch,m:MoreMsg,M:ModeMsg,n:LineNr,a:LineNrAbove,b:LineNrBelow,N:CursorLineNr,G:CursorLineSign,O:CursorLineFold,r:Question,s:StatusLine,S:StatusLineNC,c:VertSplit,t:Title,v:Visual,V:VisualNOS,w:WarningMsg,W:WildMenu,f:Folded,F:FoldColumn,A:DiffAdd,C:DiffChange,D:DiffDelete,T:DiffText,E:DiffTextAdd,>:SignColumn,-:Conceal,B:SpellBad,P:SpellCap,R:SpellRare,L:SpellLocal,+:Pmenu,=:PmenuSel,k:PmenuMatch,<:PmenuMatchSel,[:PmenuKind,]:PmenuKindSel,{:PmenuExtra,}:PmenuExtraSel,x:PmenuSbar,X:PmenuThumb,*:TabLine,#:TabLineSel,_:TabLineFill,!:CursorColumn,.:CursorLine,o:ColorColumn,q:QuickFixLine,z:StatusLineTerm,Z:StatusLineTermNC,g:MsgArea,h:ComplMatchIns,%:TabPanel,^:TabPanelSel,&:TabPanelFill"
 
 // Default python version for pyx* commands
 #if defined(FEAT_PYTHON) && defined(FEAT_PYTHON3)
@@ -2368,6 +2368,11 @@
     {"showtabline", "stal", P_NUM|P_VI_DEF|P_RALL,
 			    (char_u *)&p_stal, PV_NONE, did_set_showtabline, NULL,
 			    {(char_u *)1L, (char_u *)0L} SCTX_INIT},
+#if defined(FEAT_TABPANEL)
+    {"showtabpanel", "stpl", P_NUM|P_RALL,
+			    (char_u *)&p_stpl, PV_NONE, did_set_showtabpanel, NULL,
+			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
+#endif
     {"sidescroll",  "ss",   P_NUM|P_VI_DEF,
 			    (char_u *)&p_ss, PV_NONE, NULL, NULL,
 			    {(char_u *)0L, (char_u *)0L} SCTX_INIT},
@@ -2527,6 +2532,16 @@
     {"tabpagemax",  "tpm",  P_NUM|P_VI_DEF,
 			    (char_u *)&p_tpm, PV_NONE, NULL, NULL,
 			    {(char_u *)10L, (char_u *)0L} SCTX_INIT},
+#if defined(FEAT_TABPANEL)
+    {"tabpanel",  "tpl",    P_STRING|P_VI_DEF|P_RALL,
+			    (char_u *)&p_tpl, PV_NONE, NULL, NULL,
+			    {(char_u *)"", (char_u *)0L} SCTX_INIT},
+    {"tabpanelopt","tplo",  P_STRING|P_VI_DEF|P_ONECOMMA|P_NODUP,
+			    (char_u *)&p_tplo, PV_NONE, did_set_tabpanelopt,
+			    expand_set_tabpanelopt,
+			    {(char_u *)"", (char_u *)0L}
+			    SCTX_INIT},
+#endif
     {"tabstop",	    "ts",   P_NUM|P_VI_DEF|P_RBUF,
 			    (char_u *)&p_ts, PV_TS,
 			    did_set_shiftwidth_tabstop, NULL,
diff --git a/src/optionstr.c b/src/optionstr.c
index ce57cb4..8e233e8 100644
--- a/src/optionstr.c
+++ b/src/optionstr.c
@@ -28,6 +28,9 @@
 // Note: Keep this in sync with briopt_check()
 static char *(p_briopt_values[]) = {"shift:", "min:", "sbr", "list:", "column:", NULL};
 #endif
+#if defined(FEAT_TABPANEL)
+static char *(p_tpl_values[]) = {"wrap", "align:", "columns:", "vert:", NULL};
+#endif
 #if defined(FEAT_DIFF)
 // Note: Keep this in sync with diffopt_changed()
 static char *(p_dip_values[]) = {"filler", "context:", "iblank", "icase", "iwhite", "iwhiteall", "iwhiteeol", "horizontal", "vertical", "closeoff", "hiddenoff", "foldcolumn:", "followwrap", "internal", "indent-heuristic", "algorithm:", "inline:", "linematch:", NULL};
@@ -3547,6 +3550,33 @@
 }
 #endif
 
+#if defined(FEAT_TABPANEL)
+/*
+ * Process the new 'tabpanelopt' option value.
+ */
+    char *
+did_set_tabpanelopt(optset_T *args)
+{
+    if (tabpanelopt_changed() == FAIL)
+	return e_invalid_argument;
+
+    shell_new_columns();
+
+    return NULL;
+}
+
+    int
+expand_set_tabpanelopt(optexpand_T *args, int *numMatches, char_u ***matches)
+{
+    return expand_set_opt_string(
+	    args,
+	    p_tpl_values,
+	    ARRAY_LENGTH(p_tpl_values) - 1,
+	    numMatches,
+	    matches);
+}
+#endif
+
 /*
  * The 'scrollopt' option is changed.
  */
diff --git a/src/popupmenu.c b/src/popupmenu.c
index 4aaddaf..d629049 100644
--- a/src/popupmenu.c
+++ b/src/popupmenu.c
@@ -656,22 +656,24 @@
 	width = cells + over_cell + 1;
 	rt = orig_rt;
 
-	screen_putchar(truncrl, row, col - width + 1, attr);
+	screen_putchar(truncrl, row, col - width + 1 + TPL_LCOL(NULL), attr);
 
 	if (over_cell > 0)
-	    screen_fill(row, row + 1, col - width + 2,
-		    col - width + 2 + over_cell, ' ', ' ', attr);
+	    screen_fill(row, row + 1, col - width + 2 + TPL_LCOL(NULL),
+		    col - width + 2 + over_cell + TPL_LCOL(NULL), ' ', ' ',
+		    attr);
     }
 
     if (attrs == NULL)
-	screen_puts_len(rt, (int)STRLEN(rt), row, col - cells + 1, attr);
+	screen_puts_len(rt, (int)STRLEN(rt), row,
+		col - cells + 1 + TPL_LCOL(NULL), attr);
     else
-	pum_screen_puts_with_attrs(row, col - cells + 1, cells, rt,
-		(int)STRLEN(rt), attrs);
+	pum_screen_puts_with_attrs(row, col - cells + 1 + TPL_LCOL(NULL),
+		cells, rt, (int)STRLEN(rt), attrs);
 
     vim_free(rt_start);
     VIM_CLEAR(st);
-    return col - width;
+    return col - width + TPL_LCOL(NULL);
 }
 #endif
 
@@ -743,17 +745,18 @@
     }
 
     if (attrs == NULL)
-	screen_puts_len(st, size, row, col, attr);
+	screen_puts_len(st, size, row, col + TPL_LCOL(NULL), attr);
     else
-	pum_screen_puts_with_attrs(row, col, cells, st, size, attrs);
+	pum_screen_puts_with_attrs(row, col + TPL_LCOL(NULL), cells, st, size,
+		attrs);
 
     if (truncated)
     {
 	if (over_cell > 0)
-	    screen_fill(row, row + 1, col + cells,
-		    col + cells + over_cell, ' ', ' ', attr);
+	    screen_fill(row, row + 1, col + cells + TPL_LCOL(NULL),
+		    col + cells + over_cell + TPL_LCOL(NULL), ' ', ' ', attr);
 
-	screen_putchar(trunc, row, col + cells + over_cell, attr);
+	screen_putchar(trunc, row, col + cells + over_cell + TPL_LCOL(NULL), attr);
     }
 
     VIM_CLEAR(st);
@@ -863,10 +866,10 @@
 
 #ifdef FEAT_RIGHTLEFT
     if (pum_rl)
-	screen_putchar(' ', row, pum_col - pum_width, attr);
+	screen_putchar(' ', row, pum_col - pum_width + TPL_LCOL(NULL), attr);
     else
 #endif
-	screen_putchar(' ', row, pum_col + pum_width, attr);
+	screen_putchar(' ', row, pum_col + pum_width + TPL_LCOL(NULL), attr);
 }
 
 /*
@@ -949,12 +952,12 @@
 	if (pum_rl)
 	{
 	    if (pum_col < curwin->w_wincol + curwin->w_width - 1)
-		screen_putchar(' ', row, pum_col + 1, attr);
+		screen_putchar(' ', row, pum_col + 1 + TPL_LCOL(NULL), attr);
 	}
 	else
 #endif
 	    if (pum_col > 0)
-		screen_putchar(' ', row, pum_col - 1, attr);
+		screen_putchar(' ', row, pum_col - 1 + TPL_LCOL(NULL), attr);
 
 	// Display each entry, use two spaces for a Tab.
 	// Do this 3 times and order from p_cia
@@ -995,15 +998,16 @@
 #ifdef FEAT_RIGHTLEFT
 	    if (pum_rl)
 	    {
-		screen_fill(row, row + 1, pum_col - basic_width - n + 1,
-						col + 1, ' ', ' ', orig_attr);
+		screen_fill(row, row + 1, pum_col - basic_width - n + 1 + TPL_LCOL(NULL),
+						col + 1 + TPL_LCOL(NULL), ' ', ' ', orig_attr);
 		col = pum_col - basic_width - n;
 	    }
 	    else
 #endif
 	    {
-		screen_fill(row, row + 1, col, pum_col + basic_width + n,
-							' ', ' ', orig_attr);
+		screen_fill(row, row + 1, col + TPL_LCOL(NULL),
+			pum_col + basic_width + n + TPL_LCOL(NULL), ' ', ' ',
+			orig_attr);
 		col = pum_col + basic_width + n;
 	    }
 	    totwidth = basic_width + n;
@@ -1011,12 +1015,14 @@
 
 #ifdef FEAT_RIGHTLEFT
 	if (pum_rl)
-	    screen_fill(row, row + 1, pum_col - pum_width + 1, col + 1, ' ',
-							    ' ', orig_attr);
+	    screen_fill(row, row + 1,
+		    pum_col - pum_width + 1 + TPL_LCOL(NULL),
+		    col + 1 + TPL_LCOL(NULL), ' ', ' ', orig_attr);
 	else
 #endif
-	    screen_fill(row, row + 1, col, pum_col + pum_width, ' ', ' ',
-								orig_attr);
+	    screen_fill(row, row + 1, col + TPL_LCOL(NULL),
+		    pum_col + pum_width + TPL_LCOL(NULL),
+		    ' ', ' ', orig_attr);
 	pum_draw_scrollbar(row, i, thumb_pos, thumb_height);
 
 	++row;
@@ -1396,6 +1402,9 @@
     pum_array = NULL;
     redraw_all_later(UPD_NOT_VALID);
     redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
     if (pum_in_cmdline)
     {
 	clear_cmdline = TRUE;
diff --git a/src/popupwin.c b/src/popupwin.c
index 60a54d7..a9a2843 100644
--- a/src/popupwin.c
+++ b/src/popupwin.c
@@ -86,7 +86,7 @@
     if (STRCMP(key, "line") == 0)
 	n = screen_screenrow() + 1 + n;
     else // "col"
-	n = screen_screencol() + 1 + n;
+	n = screen_screencol() + 1 + n - TPL_LCOL(NULL);
 
     // Zero means "not set", use -1 instead.
     if (n == 0)
@@ -1545,7 +1545,7 @@
     }
     if (center_hor)
     {
-	wp->w_wincol = (Columns - wp->w_width - extra_width) / 2;
+	wp->w_wincol = (Columns - wp->w_width - extra_width - TPL_LCOL(NULL)) / 2;
 	if (wp->w_wincol < 0)
 	    wp->w_wincol = 0;
     }
@@ -4081,7 +4081,7 @@
 	// win_update() doesn't handle them.
 	top_off = popup_top_extra(wp);
 	left_extra = wp->w_popup_padding[3] + wp->w_popup_border[3]
-							 - wp->w_popup_leftoff;
+		+ TPL_LCOL(NULL) - wp->w_popup_leftoff;
 	if (wp->w_wincol + left_extra < 0)
 	    left_extra = -wp->w_wincol;
 	wp->w_winrow += top_off;
@@ -4163,7 +4163,7 @@
 	}
 
 	// Title goes on top of border or padding.
-	title_wincol = wp->w_wincol + 1;
+	title_wincol = wp->w_wincol + 1 + TPL_LCOL(NULL);
 	if (wp->w_popup_title != NULL)
 	{
 	    title_len = vim_strsize(wp->w_popup_title);
@@ -4191,7 +4191,7 @@
 		      wp->w_popup_border[0] > 0 ? border_attr[0] : popup_attr);
 	}
 
-	wincol = wp->w_wincol - wp->w_popup_leftoff;
+	wincol = wp->w_wincol - wp->w_popup_leftoff + TPL_LCOL(NULL);
 	top_padding = wp->w_popup_padding[0];
 	if (wp->w_popup_border[0] > 0)
 	{
@@ -4229,7 +4229,7 @@
 	{
 	    padcol = wincol + wp->w_popup_border[3];
 	    padendcol = wp->w_wincol + total_width - wp->w_popup_border[1]
-							 - wp->w_has_scrollbar;
+		    + TPL_LCOL(NULL) - wp->w_has_scrollbar;
 	    if (padcol < 0)
 	    {
 		padendcol += padcol;
@@ -4327,7 +4327,7 @@
 	    if (wp->w_has_scrollbar)
 	    {
 		int line = i - top_off;
-		int scroll_col = wp->w_wincol + total_width - 1
+		int scroll_col = wp->w_wincol + total_width - 1 + TPL_LCOL(NULL)
 						       - wp->w_popup_border[1];
 
 		if (line >= 0 && line < wp->w_height)
diff --git a/src/proto.h b/src/proto.h
index a5ca9e4..8282dc3 100644
--- a/src/proto.h
+++ b/src/proto.h
@@ -123,6 +123,9 @@
 # ifdef FEAT_VIMINFO
 #  include "viminfo.pro"
 # endif
+# ifdef FEAT_TABPANEL
+#  include "tabpanel.pro"
+# endif
 
 // These prototypes cannot be produced automatically.
 int smsg(const char *, ...) ATTRIBUTE_COLD ATTRIBUTE_FORMAT_PRINTF(1, 2);
diff --git a/src/proto/option.pro b/src/proto/option.pro
index c6dfc1b..f9ae7c4 100644
--- a/src/proto/option.pro
+++ b/src/proto/option.pro
@@ -1,4 +1,5 @@
 /* option.c */
+char *did_set_showtabpanel(optset_T *args);
 void set_init_1(int clean_arg);
 void set_fencs_unicode(void);
 void set_string_default(char *name, char_u *val);
diff --git a/src/proto/optionstr.pro b/src/proto/optionstr.pro
index 4c4ec3e..84dd1fb 100644
--- a/src/proto/optionstr.pro
+++ b/src/proto/optionstr.pro
@@ -1,4 +1,6 @@
 /* optionstr.c */
+char *did_set_tabpanelopt(optset_T *args);
+int expand_set_tabpanelopt(optexpand_T *args, int *numMatches, char_u ***matches);
 void didset_string_options(void);
 void trigger_optionset_string(int opt_idx, int opt_flags, char_u *oldval, char_u *oldval_l, char_u *oldval_g, char_u *newval);
 void check_buf_options(buf_T *buf);
diff --git a/src/proto/tabpanel.pro b/src/proto/tabpanel.pro
new file mode 100644
index 0000000..3cbaa2f
--- /dev/null
+++ b/src/proto/tabpanel.pro
@@ -0,0 +1,7 @@
+/* tabpanel.c */
+int tabpanel_width(void);
+int tabpanel_leftcol(win_T	*wp);
+int tabpanelopt_changed(void);
+void draw_tabpanel(void);
+int get_tabpagenr_on_tabpanel(void);
+/* vim: set ft=c : */
diff --git a/src/screen.c b/src/screen.c
index 4fcd9d3..d8a060f 100644
--- a/src/screen.c
+++ b/src/screen.c
@@ -156,13 +156,13 @@
     if (wp->w_p_rl)
     {
 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
-		W_ENDCOL(wp) - nn, (int)W_ENDCOL(wp) - off,
+		W_ENDCOL(wp) - nn + TPL_LCOL(wp), (int)W_ENDCOL(wp) - off + TPL_LCOL(wp),
 		c1, c2, attr);
     }
     else
 #endif
 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
-		wp->w_wincol + off, (int)wp->w_wincol + nn,
+		wp->w_wincol + off + TPL_LCOL(wp), (int)wp->w_wincol + nn + TPL_LCOL(wp),
 		c1, c2, attr);
     return nn;
 }
@@ -215,17 +215,17 @@
     if (wp->w_p_rl)
     {
 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
-		wp->w_wincol, W_ENDCOL(wp) - 1 - n,
-		c2, c2, attr);
+		wp->w_wincol + TPL_LCOL(wp), W_ENDCOL(wp) - 1 - n +
+		TPL_LCOL(wp), c2, c2, attr);
 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
-		W_ENDCOL(wp) - 1 - n, W_ENDCOL(wp) - n,
-		c1, c2, attr);
+		W_ENDCOL(wp) - 1 - n + TPL_LCOL(wp), W_ENDCOL(wp) - n +
+		TPL_LCOL(wp), c1, c2, attr);
     }
     else
 #endif
     {
 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + endrow,
-		wp->w_wincol + n, (int)W_ENDCOL(wp),
+		wp->w_wincol + n + TPL_LCOL(wp), (int)W_ENDCOL(wp) + TPL_LCOL(wp),
 		c1, c2, attr);
     }
 
@@ -395,7 +395,9 @@
 
     if (!popup_visible)
 	return FALSE;
-    off = row * screen_Columns + col;
+    if (col < TPL_LCOL(NULL))
+	return FALSE;
+    off = row * screen_Columns + col - TPL_LCOL(NULL);
     return popup_mask[off] > screen_zindex || popup_transparent[off];
 }
 #endif
@@ -855,7 +857,7 @@
     {
 	// For a window that has a right neighbor, draw the separator char
 	// right of the window contents.  But not on top of a popup window.
-	if (coloff + col < Columns)
+	if (coloff + col < TPL_LCOL(NULL) + COLUMNS_WITHOUT_TPL())
 	{
 	    if (!skip_for_popup(row, col + coloff))
 	    {
@@ -920,10 +922,13 @@
     if (!wp->w_vsep_width)
 	return;
 
+    if (COLUMNS_WITHOUT_TPL() <= W_ENDCOL(wp) + 1)
+	return;
+
     // draw the vertical separator right of this window
     c = fillchar_vsep(&hl, wp);
     screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
-	    W_ENDCOL(wp), W_ENDCOL(wp) + 1,
+	    W_ENDCOL(wp) + TPL_LCOL(wp), W_ENDCOL(wp) + 1 + TPL_LCOL(wp),
 	    c, ' ', hl);
 }
 
@@ -1053,7 +1058,7 @@
 	row = 0;
 	fillchar = ' ';
 	attr = HL_ATTR(HLF_TPF);
-	maxwidth = Columns;
+	maxwidth = COLUMNS_WITHOUT_TPL();
 	opt_name = (char_u *)"tabline";
     }
     else
@@ -1150,7 +1155,7 @@
     for (n = 0; hltab[n].start != NULL; n++)
     {
 	len = (int)(hltab[n].start - p);
-	screen_puts_len(p, len, row, col, curattr);
+	screen_puts_len(p, len, row, col + TPL_LCOL(wp), curattr);
 	col += vim_strnsize(p, len);
 	p = hltab[n].start;
 
@@ -1171,7 +1176,7 @@
 	else
 	    curattr = highlight_user[hltab[n].userhl - 1];
     }
-    screen_puts(p, row, col, curattr);
+    screen_puts(p, row, col + TPL_LCOL(wp), curattr);
 
     if (wp == NULL)
     {
@@ -1188,7 +1193,7 @@
 	    p = tabtab[n].start;
 	    fillchar = tabtab[n].userhl;
 	}
-	while (col < Columns)
+	while (col < COLUMNS_WITHOUT_TPL())
 	    TabPageIdxs[col++] = fillchar;
     }
 
@@ -2128,14 +2133,14 @@
     if (wp == NULL)
     {
 	col = 0;
-	width = Columns;
+	width = COLUMNS_WITHOUT_TPL();
     }
     else
     {
 	col = wp->w_wincol;
 	width = wp->w_width;
     }
-    screen_draw_rectangle(row, col, end - row, width, FALSE);
+    screen_draw_rectangle(row, col + TPL_LCOL(wp), end - row, width, FALSE);
 }
 
     void
@@ -2850,6 +2855,9 @@
     win_rest_invalid(firstwin);	// redraw all regular windows
     redraw_cmdline = TRUE;
     redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
     if (must_redraw == UPD_CLEAR)	// no need to clear again
 	must_redraw = UPD_NOT_VALID;
     msg_scrolled = 0;		// compute_cmdrow() uses this
@@ -2910,6 +2918,11 @@
     unsigned	off_to = LineOffset[to] + wp->w_wincol;
     unsigned	off_from = LineOffset[from] + wp->w_wincol;
 
+#if defined(FEAT_TABPANEL)
+    off_to += TPL_LCOL(wp);
+    off_from += TPL_LCOL(wp);
+#endif
+
     mch_memmove(ScreenLines + off_to, ScreenLines + off_from,
 	    wp->w_width * sizeof(schar_T));
     if (enc_utf8)
@@ -3243,7 +3256,7 @@
 			   && (*mb_ptr2cells)(ml_get_cursor()) == 2
 			   && vim_isprintc(gchar_cursor())) ? 2 : 1)) :
 #endif
-							    curwin->w_wcol));
+					    curwin->w_wcol) + TPL_LCOL(NULL));
     }
 }
 
@@ -3313,7 +3326,7 @@
 	if (lastrow > Rows)
 	    lastrow = Rows;
 	screen_fill(nextrow - line_count, lastrow - line_count,
-		  wp->w_wincol, (int)W_ENDCOL(wp),
+		  wp->w_wincol + TPL_LCOL(wp), (int)W_ENDCOL(wp) + TPL_LCOL(wp),
 		  ' ', ' ', 0);
     }
 
@@ -3411,7 +3424,8 @@
 	return FAIL;
 
     // only a few lines left: redraw is faster
-    if (mayclear && Rows - line_count < 5 && wp->w_width == Columns)
+    if (mayclear && Rows - line_count < 5
+	    && wp->w_width == COLUMNS_WITHOUT_TPL())
     {
 	if (!no_win_do_lines_ins)
 	    screenclear();	    // will set wp->w_lines_valid to 0
@@ -3428,7 +3442,7 @@
     if (row + line_count >= wp->w_height)
     {
 	screen_fill(W_WINROW(wp) + row, W_WINROW(wp) + wp->w_height,
-		wp->w_wincol, (int)W_ENDCOL(wp),
+		wp->w_wincol + TPL_LCOL(wp), (int)W_ENDCOL(wp) + TPL_LCOL(wp),
 		' ', ' ', 0);
 	return OK;
     }
@@ -3450,9 +3464,10 @@
      * a character in the lower right corner of the scroll region may cause a
      * scroll-up .
      */
-    if (scroll_region || wp->w_width != Columns)
+    if (scroll_region || wp->w_width != COLUMNS_WITHOUT_TPL())
     {
-	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
+	if (scroll_region && (wp->w_width == COLUMNS_WITHOUT_TPL()
+		    || *T_CSV != NUL))
 	    scroll_region_set(wp, row);
 	if (del)
 	    retval = screen_del_lines(W_WINROW(wp) + row, 0, line_count,
@@ -3460,7 +3475,8 @@
 	else
 	    retval = screen_ins_lines(W_WINROW(wp) + row, 0, line_count,
 					   wp->w_height - row, clear_attr, wp);
-	if (scroll_region && (wp->w_width == Columns || *T_CSV != NUL))
+	if (scroll_region && (wp->w_width == COLUMNS_WITHOUT_TPL()
+		    || *T_CSV != NUL))
 	    scroll_region_reset();
 	return retval;
     }
@@ -3583,7 +3599,7 @@
      * exists.
      */
     result_empty = (row + line_count >= end);
-    if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
+    if (wp != NULL && wp->w_width != COLUMNS_WITHOUT_TPL() && *T_CSV == NUL)
     {
 	// Avoid that lines are first cleared here and then redrawn, which
 	// results in many characters updated twice.  This happens with CTRL-F
@@ -3629,7 +3645,7 @@
 #ifdef FEAT_CLIPBOARD
     // Remove a modeless selection when inserting lines halfway the screen
     // or not the full width of the screen.
-    if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
+    if (off + row > 0 || (wp != NULL && wp->w_width != COLUMNS_WITHOUT_TPL()))
 	clip_clear_selection(&clip_star);
     else
 	clip_scroll_selection(-line_count);
@@ -3661,7 +3677,7 @@
     end += off;
     for (i = 0; i < line_count; ++i)
     {
-	if (wp != NULL && wp->w_width != Columns)
+	if (wp != NULL && wp->w_width != COLUMNS_WITHOUT_TPL())
 	{
 	    // need to copy part of a line
 	    j = end - 1 - i;
@@ -3669,10 +3685,11 @@
 		linecopy(j + line_count, j, wp);
 	    j += line_count;
 	    if (can_clear((char_u *)" "))
-		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
-								   clear_attr);
+		lineclear(LineOffset[j] + wp->w_wincol + TPL_LCOL(wp),
+			wp->w_width, clear_attr);
 	    else
-		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
+		lineinvalid(LineOffset[j] + wp->w_wincol + TPL_LCOL(wp),
+			wp->w_width);
 	    LineWraps[j] = FALSE;
 	}
 	else
@@ -3687,9 +3704,10 @@
 	    LineOffset[j + line_count] = temp;
 	    LineWraps[j + line_count] = FALSE;
 	    if (can_clear((char_u *)" "))
-		lineclear(temp, (int)Columns, clear_attr);
+		lineclear(temp + TPL_LCOL(wp), COLUMNS_WITHOUT_TPL(),
+			clear_attr);
 	    else
-		lineinvalid(temp, (int)Columns);
+		lineinvalid(temp + TPL_LCOL(wp), COLUMNS_WITHOUT_TPL());
 	}
     }
 
@@ -3740,6 +3758,10 @@
 	}
     }
 
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
+
 #ifdef FEAT_GUI
     gui_can_update_cursor();
     if (gui.in_use)
@@ -3818,7 +3840,7 @@
      * 5. Use T_DL (delete line) if it exists.
      * 6. redraw the characters from ScreenLines[].
      */
-    if (wp != NULL && wp->w_width != Columns && *T_CSV == NUL)
+    if (wp != NULL && wp->w_width != COLUMNS_WITHOUT_TPL() && *T_CSV == NUL)
     {
 	// Avoid that lines are first cleared here and then redrawn, which
 	// results in many characters updated twice.  This happens with CTRL-F
@@ -3841,7 +3863,7 @@
     else if (*T_CDL != NUL && line_count > 1 && can_delete)
 	type = USE_T_CDL;
     else if (can_clear(T_CE) && result_empty
-	    && (wp == NULL || wp->w_width == Columns))
+	    && (wp == NULL || wp->w_width == COLUMNS_WITHOUT_TPL()))
 	type = USE_T_CE;
     else if (*T_DL != NUL && can_delete)
 	type = USE_T_DL;
@@ -3853,7 +3875,7 @@
 #ifdef FEAT_CLIPBOARD
     // Remove a modeless selection when deleting lines halfway the screen or
     // not the full width of the screen.
-    if (off + row > 0 || (wp != NULL && wp->w_width != Columns))
+    if (off + row > 0 || (wp != NULL && wp->w_width != COLUMNS_WITHOUT_TPL()))
 	clip_clear_selection(&clip_star);
     else
 	clip_scroll_selection(line_count);
@@ -3892,7 +3914,7 @@
     end += off;
     for (i = 0; i < line_count; ++i)
     {
-	if (wp != NULL && wp->w_width != Columns)
+	if (wp != NULL && wp->w_width != COLUMNS_WITHOUT_TPL())
 	{
 	    // need to copy part of a line
 	    j = row + i;
@@ -3900,10 +3922,11 @@
 		linecopy(j - line_count, j, wp);
 	    j -= line_count;
 	    if (can_clear((char_u *)" "))
-		lineclear(LineOffset[j] + wp->w_wincol, wp->w_width,
-								   clear_attr);
+		lineclear(LineOffset[j] + wp->w_wincol + TPL_LCOL(wp),
+			wp->w_width, clear_attr);
 	    else
-		lineinvalid(LineOffset[j] + wp->w_wincol, wp->w_width);
+		lineinvalid(LineOffset[j] + wp->w_wincol + TPL_LCOL(wp),
+			wp->w_width);
 	    LineWraps[j] = FALSE;
 	}
 	else
@@ -3919,9 +3942,10 @@
 	    LineOffset[j - line_count] = temp;
 	    LineWraps[j - line_count] = FALSE;
 	    if (can_clear((char_u *)" "))
-		lineclear(temp, (int)Columns, clear_attr);
+		lineclear(temp + TPL_LCOL(NULL), COLUMNS_WITHOUT_TPL(),
+			clear_attr);
 	    else
-		lineinvalid(temp, (int)Columns);
+		lineinvalid(temp + TPL_LCOL(NULL), COLUMNS_WITHOUT_TPL());
 	}
     }
 
@@ -3992,6 +4016,10 @@
 	}
     }
 
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
+
 #ifdef FEAT_GUI
     gui_can_update_cursor();
     if (gui.in_use)
@@ -4304,6 +4332,10 @@
 #endif
 					    );
 
+#if defined(FEAT_TABPANEL)
+    col = TPL_LCOL(NULL);
+#endif
+
     if (ScreenLines == NULL)
 	return;
     redraw_tabline = FALSE;
@@ -4332,7 +4364,7 @@
 	FOR_ALL_TABPAGES(tp)
 	    ++tabcount;
 
-	tabwidth = (Columns - 1 + tabcount / 2) / tabcount;
+	tabwidth = (COLUMNS_WITHOUT_TPL() - 1 + tabcount / 2) / tabcount;
 	if (tabwidth < 6)
 	    tabwidth = 6;
 
@@ -4713,6 +4745,9 @@
     CHARSTAB_ENTRY(&fill_chars.diff,	    "diff"),
     CHARSTAB_ENTRY(&fill_chars.eob,	    "eob"),
     CHARSTAB_ENTRY(&fill_chars.lastline,    "lastline"),
+#if defined(FEAT_TABPANEL)
+    CHARSTAB_ENTRY(&fill_chars.tpl_vert,    "tpl_vert"),
+#endif
     CHARSTAB_ENTRY(&fill_chars.trunc,	    "trunc"),
     CHARSTAB_ENTRY(&fill_chars.truncrl,	    "truncrl"),
 };
@@ -4828,6 +4863,9 @@
 		fill_chars.diff = '-';
 		fill_chars.eob = '~';
 		fill_chars.lastline = '@';
+#if defined(FEAT_TABPANEL)
+		fill_chars.tpl_vert = '|';
+#endif
 		fill_chars.trunc = '>';
 		fill_chars.truncrl = '<';
 	    }
diff --git a/src/structs.h b/src/structs.h
index 1cb70b8..cd7370d 100644
--- a/src/structs.h
+++ b/src/structs.h
@@ -3851,6 +3851,9 @@
     int	diff;
     int	eob;
     int	lastline;
+#if defined(FEAT_TABPANEL)
+    int	tpl_vert;
+#endif
     int trunc;
     int truncrl;
 } fill_chars_T;
diff --git a/src/tabpanel.c b/src/tabpanel.c
new file mode 100644
index 0000000..f4bed4b
--- /dev/null
+++ b/src/tabpanel.c
@@ -0,0 +1,660 @@
+/* vi:set ts=8 sts=4 sw=4 noet:
+ *
+ * VIM - Vi IMproved	by Bram Moolenaar
+ *
+ * Do ":help uganda"  in Vim to read copying and usage conditions.
+ * Do ":help credits" in Vim to see a list of people who contributed.
+ * See README.txt for an overview of the Vim source code.
+ */
+
+/*
+ * tabpanel.c:
+ */
+
+#include "vim.h"
+
+#if defined(FEAT_TABPANEL) || defined(PROTO)
+
+static void do_by_tplmode(int tplmode, int col_start, int col_end,
+	int* pcurtab_row, int* ptabpagenr);
+
+// set pcurtab_row. don't redraw tabpanel.
+#define TPLMODE_GET_CURTAB_ROW	0
+// set ptabpagenr. don't redraw tabpanel.
+#define TPLMODE_GET_TABPAGENR	1
+// redraw tabpanel.
+#define TPLMODE_REDRAW		2
+
+#define TPL_FILLCHAR		' '
+
+#define VERT_LEN		1
+
+// tpl_vert's values
+#define VERT_OFF		0
+#define VERT_ON			1
+
+// tpl_align's values
+#define ALIGN_LEFT		0
+#define ALIGN_RIGHT		1
+
+static char_u *opt_name = (char_u *)"tabpanel";
+static int opt_scope = OPT_LOCAL;
+static int tpl_align = ALIGN_LEFT;
+static int tpl_columns = 20;
+static int tpl_vert = VERT_OFF;
+
+typedef struct {
+    win_T   *wp;
+    win_T   *cwp;
+    char_u  *user_defined;
+    int	maxrow;
+    int	offsetrow;
+    int	*prow;
+    int	*pcol;
+    int	attr;
+    int	col_start;
+    int	col_end;
+} tabpanel_T;
+
+    int
+tabpanelopt_changed(void)
+{
+    char_u	*p;
+    int		new_align = ALIGN_LEFT;
+    int		new_columns = 20;
+    int		new_vert = VERT_OFF;
+
+    p = p_tplo;
+    while (*p != NUL)
+    {
+	if (STRNCMP(p, "align:left", 10) == 0)
+	{
+	    p += 10;
+	    new_align = ALIGN_LEFT;
+	}
+	else if (STRNCMP(p, "align:right", 11) == 0)
+	{
+	    p += 11;
+	    new_align = ALIGN_RIGHT;
+	}
+	else if (STRNCMP(p, "columns:", 8) == 0 && VIM_ISDIGIT(p[8]))
+	{
+	    p += 8;
+	    new_columns = getdigits(&p);
+	}
+	else if (STRNCMP(p, "vert", 4) == 0)
+	{
+	    p += 4;
+	    new_vert = VERT_ON;
+	}
+
+	if (*p != ',' && *p != NUL)
+	    return FAIL;
+	if (*p == ',')
+	    ++p;
+    }
+
+    tpl_align = new_align;
+    tpl_columns = new_columns;
+    tpl_vert = new_vert;
+
+    return OK;
+}
+
+/*
+ * Return the width of tabpanel.
+ */
+    int
+tabpanel_width(void)
+{
+    if (msg_scrolled != 0)
+	return 0;
+
+    switch (p_stpl)
+    {
+	case 0:
+	    return 0;
+	case 1:
+	    if (first_tabpage->tp_next == NULL)
+		return 0;
+    }
+    if (Columns < tpl_columns)
+	return 0;
+    else
+	return tpl_columns;
+}
+
+/*
+ * Return the offset of a window considering the width of tabpanel.
+ */
+    int
+tabpanel_leftcol(win_T *wp)
+{
+    if (cmdline_pum_active())
+	return 0;
+    else if (wp != NULL && WIN_IS_POPUP(wp))
+	return 0;
+    else
+	return tpl_align == ALIGN_RIGHT ? 0 : tabpanel_width();
+}
+
+/*
+ * draw the tabpanel.
+ */
+    void
+draw_tabpanel(void)
+{
+    int		saved_KeyTyped = KeyTyped;
+    int		saved_got_int = got_int;
+    int		maxwidth = tabpanel_width();
+    int		vs_attr = HL_ATTR(HLF_C);
+    int		curtab_row = 0;
+#ifndef MSWIN
+    int		row = 0;
+    int		off = 0;
+#endif
+int		vsrow = 0;
+    int		is_right = tpl_align == ALIGN_RIGHT;
+
+    if (0 == maxwidth)
+	return;
+
+#ifndef MSWIN
+    // We need this section only for the Vim running on WSL.
+    for (row = 0; row < cmdline_row; row++)
+    {
+	if (is_right)
+	    off = LineOffset[row] + Columns - maxwidth;
+	else
+	    off = LineOffset[row];
+
+	vim_memset(ScreenLines + off, ' ',
+		(size_t)maxwidth * sizeof(schar_T));
+	if (enc_utf8)
+	    vim_memset(ScreenLinesUC + off, -1,
+		(size_t)maxwidth * sizeof(u8char_T));
+    }
+#endif
+
+    // Reset got_int to avoid build_stl_str_hl() isn't evaluted.
+    got_int = FALSE;
+
+    if (tpl_vert == VERT_ON)
+    {
+	if (is_right)
+	{
+	    // draw main contents in tabpanel
+	    do_by_tplmode(TPLMODE_GET_CURTAB_ROW, VERT_LEN,
+		    maxwidth - VERT_LEN, &curtab_row, NULL);
+	    do_by_tplmode(TPLMODE_REDRAW, VERT_LEN, maxwidth, &curtab_row,
+		    NULL);
+	    // clear for multi-byte vert separater
+	    screen_fill(0, cmdline_row, COLUMNS_WITHOUT_TPL(),
+		    COLUMNS_WITHOUT_TPL() + VERT_LEN,
+		    TPL_FILLCHAR, TPL_FILLCHAR, vs_attr);
+	    // draw vert separater in tabpanel
+	    for (vsrow = 0; vsrow < cmdline_row; vsrow++)
+		screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
+			COLUMNS_WITHOUT_TPL(), vs_attr);
+	}
+	else
+	{
+	    // draw main contents in tabpanel
+	    do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth - VERT_LEN,
+		    &curtab_row, NULL);
+	    do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth - VERT_LEN,
+		    &curtab_row, NULL);
+	    // clear for multi-byte vert separater
+	    screen_fill(0, cmdline_row, maxwidth - VERT_LEN,
+		    maxwidth, TPL_FILLCHAR, TPL_FILLCHAR, vs_attr);
+	    // draw vert separater in tabpanel
+	    for (vsrow = 0; vsrow < cmdline_row; vsrow++)
+		screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
+			maxwidth - VERT_LEN, vs_attr);
+	}
+    }
+    else
+    {
+	do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
+	do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth, &curtab_row, NULL);
+    }
+
+    got_int |= saved_got_int;
+
+    // A user function may reset KeyTyped, restore it.
+    KeyTyped = saved_KeyTyped;
+
+    redraw_tabpanel = FALSE;
+}
+
+/*
+ * Return tabpagenr when clicking and dragging in tabpanel.
+ */
+    int
+get_tabpagenr_on_tabpanel(void)
+{
+    int		maxwidth = tabpanel_width();
+    int		curtab_row = 0;
+    int		tabpagenr = 0;
+
+    if (0 == maxwidth)
+	return -1;
+
+    do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
+    do_by_tplmode(TPLMODE_GET_TABPAGENR, 0, maxwidth, &curtab_row,
+	    &tabpagenr);
+
+    return tabpagenr;
+}
+
+/*
+ * Fill tailing area between {start_row} and {end_row - 1}.
+ */
+    static void
+screen_fill_tailing_area(
+	int	tplmode,
+	int	row_start,
+	int	row_end,
+	int	col_start,
+	int	col_end,
+	int	attr)
+{
+    int is_right = tpl_align == ALIGN_RIGHT;
+    if (TPLMODE_REDRAW == tplmode)
+	screen_fill(row_start, row_end,
+		(is_right ? COLUMNS_WITHOUT_TPL() : 0) + col_start,
+		(is_right ? COLUMNS_WITHOUT_TPL() : 0) + col_end,
+		TPL_FILLCHAR, TPL_FILLCHAR, attr);
+}
+
+/*
+ * screen_puts_len() for tabpanel.
+ */
+    static void
+screen_puts_len_for_tabpanel(
+	int	    tplmode,
+	char_u	    *p,
+	int	    len,
+	int	    attr,
+	tabpanel_T  *pargs)
+{
+    int		j, k;
+    int		chlen;
+    int		chcells;
+    char_u	buf[IOSIZE];
+    char_u*	temp;
+
+    for (j = 0; j < len;)
+    {
+	if ((TPLMODE_GET_CURTAB_ROW != tplmode)
+		&& (pargs->maxrow <= (*pargs->prow - pargs->offsetrow)))
+	    break;
+
+	if ((p[j] == '\n') || (p[j] == '\r'))
+	{
+	    // fill the tailing area of current row.
+	    if (0 <= (*pargs->prow - pargs->offsetrow)
+		    && (*pargs->prow - pargs->offsetrow) < pargs->maxrow)
+		screen_fill_tailing_area(tplmode,
+			*pargs->prow - pargs->offsetrow,
+			*pargs->prow - pargs->offsetrow + 1,
+			*pargs->pcol, pargs->col_end, attr);
+	    (*pargs->prow)++;
+	    *pargs->pcol = pargs->col_start;
+	    j++;
+	}
+	else
+	{
+	    if (has_mbyte)
+		chlen = (*mb_ptr2len)(p + j);
+	    else
+		chlen = (int)STRLEN(p + j);
+
+	    for (k = 0; k < chlen; k++)
+		buf[k] = p[j + k];
+	    buf[chlen] = NUL;
+	    j += chlen;
+
+	    // Make all characters printable.
+	    temp = transstr(buf);
+	    if (temp != NULL)
+	    {
+		vim_strncpy(buf, temp, sizeof(buf) - 1);
+		vim_free(temp);
+	    }
+
+	    if (has_mbyte)
+		chcells = (*mb_ptr2cells)(buf);
+	    else
+		chcells = 1;
+
+	    if (pargs->col_end < (*pargs->pcol) + chcells)
+	    {
+		// fill the tailing area of current row.
+		if (0 <= (*pargs->prow - pargs->offsetrow)
+			&& (*pargs->prow - pargs->offsetrow) < pargs->maxrow)
+		    screen_fill_tailing_area(tplmode,
+			    *pargs->prow - pargs->offsetrow,
+			    *pargs->prow - pargs->offsetrow + 1,
+			    *pargs->pcol, pargs->col_end, attr);
+		*pargs->pcol = pargs->col_end;
+
+		if (pargs->col_end < chcells)
+		    break;
+	    }
+
+	    if ((*pargs->pcol) + chcells <= pargs->col_end)
+	    {
+		int off = (tpl_align == ALIGN_RIGHT)
+			? COLUMNS_WITHOUT_TPL()
+			: 0;
+		if ((TPLMODE_REDRAW == tplmode)
+			&& (0 <= (*pargs->prow - pargs->offsetrow)
+			&& (*pargs->prow - pargs->offsetrow) < pargs->maxrow))
+		    screen_puts(buf, *pargs->prow - pargs->offsetrow,
+			    *pargs->pcol + off, attr);
+		(*pargs->pcol) += chcells;
+	    }
+	}
+    }
+}
+
+/*
+ * default tabpanel drawing behavior if 'tabpanel' option is empty.
+ */
+    static void
+draw_tabpanel_default(int tplmode, tabpanel_T *pargs)
+{
+    int		modified;
+    int		wincount;
+    int		len = 0;
+    char_u	buf[2] = { NUL, NUL };
+
+    modified = FALSE;
+    for (wincount = 0; pargs->wp != NULL;
+	    pargs->wp = pargs->wp->w_next, ++wincount)
+	if (bufIsChanged(pargs->wp->w_buffer))
+	    modified = TRUE;
+
+    if (modified || 1 < wincount)
+    {
+	if (1 < wincount)
+	{
+	    vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
+	    len = (int)STRLEN(NameBuff);
+	    screen_puts_len_for_tabpanel(tplmode, NameBuff, len,
+#if defined(FEAT_SYN_HL)
+		    hl_combine_attr(pargs->attr, HL_ATTR(HLF_T)),
+#else
+		    pargs->attr,
+#endif
+		    pargs);
+	}
+	if (modified)
+	{
+	    buf[0] = '+';
+	    screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
+	}
+
+	buf[0] = TPL_FILLCHAR;
+	screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
+    }
+
+    get_trans_bufname(pargs->cwp->w_buffer);
+    shorten_dir(NameBuff);
+    len = (int)STRLEN(NameBuff);
+    screen_puts_len_for_tabpanel(tplmode, NameBuff, len, pargs->attr, pargs);
+
+    // fill the tailing area of current row.
+    if (0 <= (*pargs->prow - pargs->offsetrow)
+	    && (*pargs->prow - pargs->offsetrow) < pargs->maxrow)
+	screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
+		*pargs->prow - pargs->offsetrow + 1,
+		*pargs->pcol, pargs->col_end, pargs->attr);
+    *pargs->pcol = pargs->col_end;
+}
+
+/*
+ * default tabpanel drawing behavior if 'tabpanel' option is NOT empty.
+ */
+    static void
+draw_tabpanel_userdefined(int tplmode, tabpanel_T *pargs)
+{
+    char_u	*p;
+    int		p_crb_save;
+    char_u	buf[IOSIZE];
+    stl_hlrec_T *hltab;
+    stl_hlrec_T *tabtab;
+    int		curattr;
+    int		n;
+
+    // Temporarily reset 'cursorbind', we don't want a side effect from moving
+    // the cursor away and back.
+    p_crb_save = pargs->cwp->w_p_crb;
+    pargs->cwp->w_p_crb = FALSE;
+
+    // Make a copy, because the statusline may include a function call that
+    // might change the option value and free the memory.
+    p = vim_strsave(pargs->user_defined);
+
+    build_stl_str_hl(pargs->cwp, buf, sizeof(buf),
+	    p, opt_name, opt_scope,
+	    TPL_FILLCHAR, pargs->col_end - pargs->col_start, &hltab, &tabtab);
+
+    vim_free(p);
+    pargs->cwp->w_p_crb = p_crb_save;
+
+    curattr = pargs->attr;
+    p = buf;
+    for (n = 0; hltab[n].start != NULL; n++)
+    {
+	screen_puts_len_for_tabpanel(tplmode, p, (int)(hltab[n].start - p),
+		curattr, pargs);
+	p = hltab[n].start;
+	if (hltab[n].userhl == 0)
+	    curattr = pargs->attr;
+	else if (hltab[n].userhl < 0)
+	    curattr = syn_id2attr(-hltab[n].userhl);
+#ifdef FEAT_TERMINAL
+	else if (pargs->wp != NULL && pargs->wp != curwin
+		&& bt_terminal(pargs->wp->w_buffer)
+		&& pargs->wp->w_status_height != 0)
+	    curattr = highlight_stltermnc[hltab[n].userhl - 1];
+	else if (pargs->wp != NULL && bt_terminal(pargs->wp->w_buffer)
+		&& pargs->wp->w_status_height != 0)
+	    curattr = highlight_stlterm[hltab[n].userhl - 1];
+#endif
+	else if (pargs->wp != NULL && pargs->wp != curwin
+		&& pargs->wp->w_status_height != 0)
+	    curattr = highlight_stlnc[hltab[n].userhl - 1];
+	else
+	    curattr = highlight_user[hltab[n].userhl - 1];
+    }
+    screen_puts_len_for_tabpanel(tplmode, p, (int)STRLEN(p), curattr, pargs);
+
+    // fill the tailing area of current row.
+    if (0 <= (*pargs->prow - pargs->offsetrow)
+	    && (*pargs->prow - pargs->offsetrow) < pargs->maxrow)
+	screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
+		*pargs->prow - pargs->offsetrow + 1, *pargs->pcol,
+		pargs->col_end, curattr);
+    *pargs->pcol = pargs->col_end;
+}
+
+    static char_u *
+starts_with_percent_and_bang(tabpanel_T *pargs)
+{
+    int		len = 0;
+    char_u	*usefmt = p_tpl;
+
+    if (usefmt == NULL)
+	return NULL;
+
+    len = (int)STRLEN(usefmt);
+
+    if (len == 0)
+	return NULL;
+
+#ifdef FEAT_EVAL
+    // if "fmt" was set insecurely it needs to be evaluated in the sandbox
+    int	use_sandbox = was_set_insecurely(opt_name, opt_scope);
+
+    // When the format starts with "%!" then evaluate it as an expression and
+    // use the result as the actual format string.
+    if (1 < len && usefmt[0] == '%' && usefmt[1] == '!')
+    {
+	typval_T	tv;
+	char_u		*p = NULL;
+
+	tv.v_type = VAR_NUMBER;
+	tv.vval.v_number = pargs->cwp->w_id;
+	set_var((char_u *)"g:tabpanel_winid", &tv, FALSE);
+
+	p = eval_to_string_safe(usefmt + 2, use_sandbox, FALSE, FALSE);
+	if (p != NULL)
+	    usefmt = p;
+
+	do_unlet((char_u *)"g:tabpanel_winid", TRUE);
+    }
+#endif
+
+    return usefmt;
+}
+
+/*
+ * do something by tplmode for drawing tabpanel.
+ */
+    static void
+do_by_tplmode(
+	int	tplmode,
+	int	col_start,
+	int	col_end,
+	int	*pcurtab_row,
+	int	*ptabpagenr)
+{
+    int		attr_tplf = HL_ATTR(HLF_TPLF);
+    int		attr_tpls = HL_ATTR(HLF_TPLS);
+    int		attr_tpl = HL_ATTR(HLF_TPL);
+    int		col = col_start;
+    int		row = 0;
+    tabpage_T	*tp = NULL;
+    typval_T	v;
+    tabpanel_T    args;
+
+    args.maxrow = cmdline_row;
+    args.offsetrow = 0;
+    args.col_start = col_start;
+    args.col_end = col_end;
+
+    if (TPLMODE_GET_CURTAB_ROW != tplmode)
+	if (0 < args.maxrow)
+	    while (args.offsetrow + args.maxrow <= *pcurtab_row)
+		args.offsetrow += args.maxrow;
+
+    tp = first_tabpage;
+
+    for (row = 0; tp != NULL; row++)
+    {
+	if ((TPLMODE_GET_CURTAB_ROW != tplmode)
+		&& (args.maxrow <= (row - args.offsetrow)))
+	    break;
+
+	col = col_start;
+
+	v.v_type = VAR_NUMBER;
+	v.vval.v_number = tabpage_index(tp);
+	set_var((char_u *)"g:actual_curtabpage", &v, TRUE);
+
+	if (tp->tp_topframe == topframe)
+	{
+	    args.attr = attr_tpls;
+	    if (TPLMODE_GET_CURTAB_ROW == tplmode)
+	    {
+		*pcurtab_row = row;
+		break;
+	    }
+	}
+	else
+	    args.attr = attr_tpl;
+
+	if (tp == curtab)
+	{
+	    args.cwp = curwin;
+	    args.wp = firstwin;
+	}
+	else
+	{
+	    args.cwp = tp->tp_curwin;
+	    args.wp = tp->tp_firstwin;
+	}
+
+	char_u*	usefmt = starts_with_percent_and_bang(&args);
+	if (usefmt != NULL)
+	{
+	    char_u	buf[IOSIZE];
+	    char_u	*p = usefmt;
+	    size_t	i = 0;
+
+	    while (p[i] != '\0')
+	    {
+		while ((p[i] == '\n') || (p[i] == '\r'))
+		{
+		    // fill the tailing area of current row.
+		    if (0 <= (row - args.offsetrow)
+			    && (row - args.offsetrow) < args.maxrow)
+			screen_fill_tailing_area(tplmode,
+				row - args.offsetrow,
+				row - args.offsetrow + 1,
+				col, args.col_end, args.attr);
+		    row++;
+		    col = col_start;
+		    p++;
+		}
+
+		while ((p[i] != '\n') && (p[i] != '\r')
+			&& (p[i] != '\0'))
+		{
+		    if (i + 1 >= sizeof(buf))
+			break;
+		    buf[i] = p[i];
+		    i++;
+		}
+		buf[i] = '\0';
+
+		args.user_defined = buf;
+		args.prow = &row;
+		args.pcol = &col;
+		draw_tabpanel_userdefined(tplmode, &args);
+
+		p += i;
+		i = 0;
+	    }
+	    if (usefmt != p_tpl)
+		VIM_CLEAR(usefmt);
+	}
+	else
+	{
+	    args.user_defined = NULL;
+	    args.prow = &row;
+	    args.pcol = &col;
+	    draw_tabpanel_default(tplmode, &args);
+	}
+
+	do_unlet((char_u *)"g:actual_curtabpage", TRUE);
+
+	tp = tp->tp_next;
+
+	if ((TPLMODE_GET_TABPAGENR == tplmode)
+		&& (mouse_row <= (row - args.offsetrow)))
+	{
+	    *ptabpagenr = v.vval.v_number;
+	    break;
+	}
+    }
+
+    // fill the area of TabPanelFill.
+    screen_fill_tailing_area(tplmode, row - args.offsetrow, args.maxrow,
+	    args.col_start, args.col_end, attr_tplf);
+}
+
+#endif // FEAT_TABPANEL
diff --git a/src/term.c b/src/term.c
index 03bad0d..2d2c940 100644
--- a/src/term.c
+++ b/src/term.c
@@ -4454,9 +4454,16 @@
 {
     OUT_STR(tgoto((char *)T_CS, W_WINROW(wp) + wp->w_height - 1,
 							 W_WINROW(wp) + off));
+#if defined(FEAT_TABPANEL)
+    if (*T_CSV != NUL)
+	OUT_STR(tgoto((char *)T_CSV,
+		wp->w_wincol + wp->w_width - 1 + TPL_LCOL(NULL),
+		wp->w_wincol + TPL_LCOL(NULL)));
+#else
     if (*T_CSV != NUL && wp->w_width != Columns)
 	OUT_STR(tgoto((char *)T_CSV, wp->w_wincol + wp->w_width - 1,
 							       wp->w_wincol));
+#endif
     screen_start();		    // don't know where cursor is now
 }
 
@@ -4468,7 +4475,7 @@
 {
     OUT_STR(tgoto((char *)T_CS, (int)Rows - 1, 0));
     if (*T_CSV != NUL)
-	OUT_STR(tgoto((char *)T_CSV, (int)Columns - 1, 0));
+	OUT_STR(tgoto((char *)T_CSV, COLUMNS_WITHOUT_TPL() - 1, 0));
     screen_start();		    // don't know where cursor is now
 }
 
diff --git a/src/terminal.c b/src/terminal.c
index 9f94825..a075840 100644
--- a/src/terminal.c
+++ b/src/terminal.c
@@ -1351,7 +1351,7 @@
 	// do not use the window cursor position
 	position_cursor(curwin, &curbuf->b_term->tl_cursor_pos);
 	windgoto(W_WINROW(curwin) + curwin->w_wrow,
-		 curwin->w_wincol + curwin->w_wcol);
+		 curwin->w_wincol + curwin->w_wcol + TPL_LCOL(NULL));
     }
     if (redraw)
     {
@@ -1430,6 +1430,10 @@
 	if (buffer == curbuf && (State & MODE_CMDLINE) == 0)
 	{
 	    update_screen(UPD_VALID_NO_UPDATE);
+#if defined(FEAT_TABPANEL)
+	    if (redraw_tabpanel)
+		draw_tabpanel();
+#endif
 	    // update_screen() can be slow, check the terminal wasn't closed
 	    // already
 	    if (buffer == curbuf && curbuf->b_term != NULL)
@@ -4116,7 +4120,8 @@
 #ifdef FEAT_MENU
 				+ winbar_height(wp)
 #endif
-				, wp->w_wincol, pos.col, wp->w_width, -1,
+				, wp->w_wincol + TPL_LCOL(wp), pos.col,
+				wp->w_width, -1,
 #ifdef FEAT_PROP_POPUP
 				popup_is_popup(wp) ? SLF_POPUP :
 #endif
diff --git a/src/testdir/Make_all.mak b/src/testdir/Make_all.mak
index 88bf5c3..ef86a7d 100644
--- a/src/testdir/Make_all.mak
+++ b/src/testdir/Make_all.mak
@@ -311,6 +311,7 @@
 	test_tab \
 	test_tabline \
 	test_tabpage \
+	test_tabpanel \
 	test_tagcase \
 	test_tagfunc \
 	test_tagjump \
@@ -567,6 +568,7 @@
 	test_system.res \
 	test_tab.res \
 	test_tabpage.res \
+	test_tabpanel.res \
 	test_tagjump.res \
 	test_taglist.res \
 	test_tcl.res \
diff --git a/src/testdir/dumps/Test_tabpanel_commandline_0.dump b/src/testdir/dumps/Test_tabpanel_commandline_0.dump
new file mode 100644
index 0000000..5ed359c
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_commandline_0.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]| | +0#0000000#ffffff0@34
+|[+2&&|N|o| |N|a|m|e|]| |~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+|a+0#0000001#ffff4012|b@1|r|e|v|i|a|t|e| +3#0000000#ffffff0@1|a|b|c|l|e|a|r| @1|a|b|o|v|e|l|e|f|t| @1|a|b|s|t|r|a|c|t| @4
+|:+0&&|a|b@1|r|e|v|i|a|t|e> @33
diff --git a/src/testdir/dumps/Test_tabpanel_commandline_1.dump b/src/testdir/dumps/Test_tabpanel_commandline_1.dump
new file mode 100644
index 0000000..a44f54e
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_commandline_1.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]| | +0#0000000#ffffff0@34
+|[+2&&|N|o| |N|a|m|e|]| |~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +0#0000001#e0e0e08|a|b@1|r|e|v|i|a|t|e| @4| +0#4040ff13#ffffff0@28
+| +0#0000001#ffd7ff255|a|b|c|l|e|a|r| @7| +0#4040ff13#ffffff0@28
+| +0#0000001#ffd7ff255|a|b|o|v|e|l|e|f|t| @5| +0#4040ff13#ffffff0@28
+| +0#0000001#ffd7ff255|a|b|s|t|r|a|c|t| @6| +0#4040ff13#ffffff0@28
+|:+0#0000000&|a|b@1|r|e|v|i|a|t|e> @33
diff --git a/src/testdir/dumps/Test_tabpanel_dont_overflow_into_tabpanel_0.dump b/src/testdir/dumps/Test_tabpanel_dont_overflow_into_tabpanel_0.dump
new file mode 100644
index 0000000..5fd8f9b
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_dont_overflow_into_tabpanel_0.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]| @1|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|+| |[|N|o| |N|a|m|e|]| | +1&&@9|X+8#0000001#e0e0e08
+|++2#0000000#ffffff0| |[|N|o| |N|a|m|e>x+0&&@34
+| +1&&@9|x+0&&@34
+| +1&&@9|x+0&&@29| @4
+| +1&&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +0#0000000&@36|1|,|1| @4
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_00.dump b/src/testdir/dumps/Test_tabpanel_drawing_00.dump
new file mode 100644
index 0000000..1491b66
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_00.dump
@@ -0,0 +1,6 @@
+> +0&#ffffff0@44
+|~+0#4040ff13&| @43
+|~| @43
+|~| @43
+|~| @43
+| +0#0000000&@26|0|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_01.dump b/src/testdir/dumps/Test_tabpanel_drawing_01.dump
new file mode 100644
index 0000000..8601542
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_01.dump
@@ -0,0 +1,6 @@
+|X+2&#ffffff0|t|a|b|p|a|n|e|l|1| @5> +0&&@28
+| +1&&@15|~+0#4040ff13&| @27
+| +1#0000000&@15|~+0#4040ff13&| @27
+| +1#0000000&@15|~+0#4040ff13&| @27
+| +1#0000000&@15|~+0#4040ff13&| @27
+| +0#0000000&@26|0|,|0|-|1| @8|A|l|0|,
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_02.dump b/src/testdir/dumps/Test_tabpanel_drawing_02.dump
new file mode 100644
index 0000000..f7567dc
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_02.dump
@@ -0,0 +1,6 @@
+|2+2#e000e06#ffffff0| +2#0000000&|X|t|a|b|p|a|n|e|l|1| @3> +0&&@19||+1&&| +0&&@7
+| +1&&@15|~+0#4040ff13&| @18||+1#0000000&|~+0#4040ff13&| @6
+| +1#0000000&@15|~+0#4040ff13&| @18||+1#0000000&|~+0#4040ff13&| @6
+| +1#0000000&@15|~+0#4040ff13&| @18||+1#0000000&|~+0#4040ff13&| @6
+| +1#0000000&@15|<+3&&|a|b|p|a|n|e|l|1| |0|,|0|-|1| @1|A|l@1| |<+1&&|l|1| |0|,|0|-
+| +0&&@44
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_03.dump b/src/testdir/dumps/Test_tabpanel_drawing_03.dump
new file mode 100644
index 0000000..cb67b9e
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_03.dump
@@ -0,0 +1,6 @@
+|2+2#e000e06#ffffff0|++2#0000000&| |X|t|a|b|p|a|n|e|l|1| @2>a+0&&| @18||+1&&|a+0&&| @6
+| +1&&@15|b+0&&| @18||+1&&|b+0&&| @6
+| +1&&@15|c+0&&| @18||+1&&|c+0&&| @6
+| +1&&@15|~+0#4040ff13&| @18||+1#0000000&|~+0#4040ff13&| @6
+| +1#0000000&@15|<+3&&|n|e|l|1| |[|+|]| |1|,|1| @3|A|l@1| |<+1&&|+|]| |1|,|1| 
+| +0&&@44
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_04.dump b/src/testdir/dumps/Test_tabpanel_drawing_04.dump
new file mode 100644
index 0000000..61b759e
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_04.dump
@@ -0,0 +1,6 @@
+|2+8#e000e06#e0e0e08|++8#0000001&| |X|t|a|b|p|a|n|e|l|1| @2>d+0#0000000#ffffff0| @27
+|++2&&| |X|t|a|b|p|a|n|e|l|2| @3|e+0&&| @27
+| +1&&@15|f+0&&| @27
+| +1&&@15|~+0#4040ff13&| @27
+| +1#0000000&@15|~+0#4040ff13&| @27
+| +0#0000000&@42|1|,
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_05.dump b/src/testdir/dumps/Test_tabpanel_drawing_05.dump
new file mode 100644
index 0000000..e9ea7cb
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_05.dump
@@ -0,0 +1,6 @@
+| +8#0000001#e0e0e08@15>d+0#0000000#ffffff0| @27
+|1+8#0000001#e0e0e08|:|X+2#4040ff13#ffffff0|t|a|b|p|a|n|e|l|1| +8#0000001#e0e0e08@3|e+0#0000000#ffffff0| @27
+| +2&&@15|f+0&&| @27
+|2+2&&|:|X+0#4040ff13&|t|a|b|p|a|n|e|l|2| +2#0000000&@3|~+0#4040ff13&| @27
+| +1#0000000&@15|~+0#4040ff13&| @27
+| +0#0000000&@42|1|,
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_06.dump b/src/testdir/dumps/Test_tabpanel_drawing_06.dump
new file mode 100644
index 0000000..b5935d3
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_06.dump
@@ -0,0 +1,6 @@
+>d+0&#ffffff0| @27| +8#0000001#e0e0e08@15
+|e+0#0000000#ffffff0| @27|1+8#0000001#e0e0e08|:|X+2#4040ff13#ffffff0|t|a|b|p|a|n|e|l|1| +8#0000001#e0e0e08@3
+|f+0#0000000#ffffff0| @27| +2&&@15
+|~+0#4040ff13&| @27|2+2#0000000&|:|X+0#4040ff13&|t|a|b|p|a|n|e|l|2| +2#0000000&@3
+|~+0#4040ff13&| @27| +1#0000000&@15
+| +0&&@26|1|,|1| @10|A|l@1| 
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_07.dump b/src/testdir/dumps/Test_tabpanel_drawing_07.dump
new file mode 100644
index 0000000..440988b
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_07.dump
@@ -0,0 +1,6 @@
+> +0&#ffffff0@28| +8#0000001#e0e0e08@15
+|~+0#4040ff13#ffffff0| @27|1+8#0000001#e0e0e08|:|X+2#4040ff13#ffffff0|t|a|b|p|a|n|e|l|1| +8#0000001#e0e0e08@3
+|~+0#4040ff13#ffffff0| @27| +8#0000001#e0e0e08@15
+|~+0#4040ff13#ffffff0| @27|2+8#0000001#e0e0e08|:|X+0#4040ff13#ffffff0|t|a|b|p|a|n|e|l|2| +8#0000001#e0e0e08@3
+|~+0#4040ff13#ffffff0| @27| +2#0000000&@15
+| +0&&@26|0|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_08.dump b/src/testdir/dumps/Test_tabpanel_drawing_08.dump
new file mode 100644
index 0000000..57bbf92
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_08.dump
@@ -0,0 +1,6 @@
+>a+0&#ffffff0| @18||+1&&|a+0&&| @6| +2&&@15
+|b+0&&| @18||+1&&|b+0&&| @6|1+2&&|:|X+0#4040ff13&|t|a|b|p|a|n|e|l|1| +2#0000000&@3
+|c+0&&| @18||+1&&|c+0&&| @6| +1&&@15
+|~+0#4040ff13&| @18||+1#0000000&|~+0#4040ff13&| @6| +1#0000000&@15
+|<+3&&|n|e|l|1| |[|+|]| |1|,|1| @3|A|l@1| |<+1&&|+|]| |1|,|1| @16
+| +0&&@26|1|,|1| @10|A|l@1| 
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_fill_tailing_0.dump b/src/testdir/dumps/Test_tabpanel_drawing_fill_tailing_0.dump
new file mode 100644
index 0000000..40e3bd7
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_fill_tailing_0.dump
@@ -0,0 +1,10 @@
+| +8#0000001#e0e0e08@19> +0#0000000#ffffff0@24
+|T+8#0000001#e0e0e08|O|P| @16|~+0#4040ff13#ffffff0| @23
+|a+8#0000001#e0e0e08@2|.|t|x|t| @12|~+0#4040ff13#ffffff0| @23
+|B+8#0000001#e0e0e08|O|T@1|O|M| @13|~+0#4040ff13#ffffff0| @23
+| +2#0000000&@19|~+0#4040ff13&| @23
+|T+2#0000000&|O|P| @16|~+0#4040ff13&| @23
+|b+2#0000000&@2|.|t|x|t| @12|~+0#4040ff13&| @23
+|B+2#0000000&|O|T@1|O|M| @13|~+0#4040ff13&| @23
+| +1#0000000&@19|~+0#4040ff13&| @23
+| +0#0000000&@44
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_pum_0.dump b/src/testdir/dumps/Test_tabpanel_drawing_pum_0.dump
new file mode 100644
index 0000000..190e5d9
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_pum_0.dump
@@ -0,0 +1,10 @@
+|a+8#0000001#e0e0e08@2|.|t|x|t| @12|!+0#0000000#ffffff0> @23
+|b+2&&@2|.|t|x|t| @12|!+0#0000001#e0e0e08| @14| +0#0000000#0000001| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|#+0#0000001#ffd7ff255| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|&+0#0000001#ffd7ff255| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|*+0#0000001#ffd7ff255| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|++0#0000001#ffd7ff255@1| @13| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|-+0#0000001#ffd7ff255@1| @13| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|<+0#0000001#ffd7ff255| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|=+0#0000001#ffd7ff255| @14| +0#0000000#a8a8a8255| +0#4040ff13#ffffff0@7
+|-+2#0000000&@1| |m+0#00e0003&|a|t|c|h| |1| |o|f| |5|9|6| +0#0000000&@27
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_pum_1.dump b/src/testdir/dumps/Test_tabpanel_drawing_pum_1.dump
new file mode 100644
index 0000000..9888bc0
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_pum_1.dump
@@ -0,0 +1,10 @@
+|a+8#0000001#e0e0e08@2|.|t|x|t| @12|!+0#0000000#ffffff0| @23
+|++2&&| |b@2|.|t|x|t| @10| +0&&@1|a|b@1|r|e|v|i|a|t|e> @12
+| +1&&@19|~+0#4040ff13&| +0#0000001#e0e0e08|a|b@1|r|e|v|i|a|t|e| @4| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|~+0#4040ff13&| +0#0000001#ffd7ff255|a|b|c|l|e|a|r| @7| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|~+0#4040ff13&| +0#0000001#ffd7ff255|a|b|o|v|e|l|e|f|t| @5| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|~+0#4040ff13&| +0#0000001#ffd7ff255|a|b|s|t|r|a|c|t| @6| +0#4040ff13#ffffff0@7
+| +1#0000000&@19|~+0#4040ff13&| @23
+| +1#0000000&@19|~+0#4040ff13&| @23
+| +1#0000000&@19|~+0#4040ff13&| @23
+|-+2#0000000&@1| |m+0#00e0003&|a|t|c|h| |1| |o|f| |4| +0#0000000&@29
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_scrolling_0.dump b/src/testdir/dumps/Test_tabpanel_drawing_scrolling_0.dump
new file mode 100644
index 0000000..fa1947e
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_scrolling_0.dump
@@ -0,0 +1,10 @@
+|a+8#0000001#e0e0e08@2|.|t|x|t| @12| +0#af5f00255#ffffff0@1|9| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t||+1&&| +0#af5f00255&@1|1| 
+|2+2#e000e06&|++2#0000000&| |b@2|.|t|x|t| @9| +0#af5f00255&|1|0| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t||+1&&| +0#af5f00255&@1|2| 
+| +1#0000000&@19| +0#af5f00255&|1@1| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t||+1&&| +0#af5f00255&@1|3| 
+| +1#0000000&@19| +0#af5f00255&|1|2| >@+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t||+1&&| +0#af5f00255&@1|4| 
+| +1#0000000&@19| +0#af5f00255&|1|3| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t||+1&&| +0#af5f00255&@1|5| 
+| +1#0000000&@19| +0#af5f00255&|1|4| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t||+1&&| +0#af5f00255&@1|6| 
+| +1#0000000&@19| +0#af5f00255&|1|5| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t||+1&&| +0#af5f00255&@1|7| 
+| +1#0000000&@19| +0#af5f00255&|1|6| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t||+1&&| +0#af5f00255&@1|8| 
+| +1#0000000&@19|<+3&&|.|t|x|t| |[|+|]| |1|2|,|1| @3|8|%| |<+1&&| |1|,
+| +0&&@44
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_scrolling_1.dump b/src/testdir/dumps/Test_tabpanel_drawing_scrolling_1.dump
new file mode 100644
index 0000000..6370449
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_scrolling_1.dump
@@ -0,0 +1,10 @@
+|a+8#0000001#e0e0e08@2|.|t|x|t| @12| +0#af5f00255#ffffff0@1|1| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+|2+2#e000e06&|++2#0000000&| |b@2|.|t|x|t| @9| +0#af5f00255&@1|2| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19| +0#af5f00255&@1|3| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19|b@2|.|t|x|t| |[|+|]| @1|1|,|1| @5|T|o|p
+| @19| +0#af5f00255&|1|5| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19| +0#af5f00255&|1|6| >@+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19| +0#af5f00255&|1|7| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19| +0#af5f00255&|1|8| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19|b+3&&@2|.|t|x|t| |[|+|]| @1|1|6|,|1| @4|1|4|%
+| +0&&@44
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_scrolling_2.dump b/src/testdir/dumps/Test_tabpanel_drawing_scrolling_2.dump
new file mode 100644
index 0000000..50b55ea
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_scrolling_2.dump
@@ -0,0 +1,10 @@
+|a+8#0000001#e0e0e08@2|.|t|x|t| @12| +0#af5f00255#ffffff0|1|9| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+|2+2#e000e06&|++2#0000000&| |b@2|.|t|x|t| @9| +0#af5f00255&|2|0| >@+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19| +0#af5f00255&|2|1| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19| +0#af5f00255&|2@1| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19|b+3&&@2|.|t|x|t| |[|+|]| @1|2|0|,|1| @4|1|8|%
+| +1&&@19| +0#af5f00255&@1|1| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19| +0#af5f00255&@1|2| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19| +0#af5f00255&@1|3| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t|e|x|t| @1
+| +1&&@19|b@2|.|t|x|t| |[|+|]| @1|1|,|1| @5|T|o|p
+| +0&&@44
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_scrolling_3.dump b/src/testdir/dumps/Test_tabpanel_drawing_scrolling_3.dump
new file mode 100644
index 0000000..fdde1ab
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_scrolling_3.dump
@@ -0,0 +1,10 @@
+|a+8#0000001#e0e0e08@2|.|t|x|t| @12| +0#af5f00255#ffffff0@1|1| ||+1#0000000&| +0#af5f00255&|2|5| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t
+|2+2#e000e06&|++2#0000000&| |b@2|.|t|x|t| @9| +0#af5f00255&@1|2| ||+1#0000000&| +0#af5f00255&|2|6| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t
+| +1&&@19| +0#af5f00255&@1|3| ||+1#0000000&| +0#af5f00255&|2|7| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t
+| +1&&@19| +0#af5f00255&@1|4| ||+1#0000000&| +0#af5f00255&|2|8| >@+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t
+| +1&&@19| +0#af5f00255&@1|5| ||+1#0000000&| +0#af5f00255&|2|9| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t
+| +1&&@19| +0#af5f00255&@1|6| ||+1#0000000&| +0#af5f00255&|3|0| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t
+| +1&&@19| +0#af5f00255&@1|7| ||+1#0000000&| +0#af5f00255&|3|1| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t
+| +1&&@19| +0#af5f00255&@1|8| ||+1#0000000&| +0#af5f00255&|3|2| |t+0#0000000&|e|x|t| |t|e|x|t| |t|e|x|t| |t
+| +1&&@19|<| |1|,| |<+3&&|.|t|x|t| |[|+|]| |2|8|,|1| @2|2|6|%
+| +0&&@44
diff --git a/src/testdir/dumps/Test_tabpanel_drawing_with_popupwin_0.dump b/src/testdir/dumps/Test_tabpanel_drawing_with_popupwin_0.dump
new file mode 100644
index 0000000..080fa27
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_drawing_with_popupwin_0.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]| @10|╔+0#0000000#ffffff0|═|╗|.@18|╔|═|╗
+|[+2&&|S|c|r|a|t|c|h|]| @10|║+0&&|@|║|.@18|║|@|║
+| +1&&@19|╚+0&&|═|╝|.@5|a|t|c|u|r|s|o|r|.@4|╚|═|╝
+| +1&&@19|.+0&&@8>.@15
+| +1&&@19|.+0&&@24
+| +1&&@19|╔+0&&|═|╗|.@18|╔|═|╗
+| +1&&@19|║+0&&|@|║|.@18|║|@|║
+| +1&&@19|╚+0&&|═|╝|.@18|╚|═|╝
+| +1&&@19|.+0&&@24
+| @44
diff --git a/src/testdir/dumps/Test_tabpanel_eval_tabpanel_statusline_tabline_0.dump b/src/testdir/dumps/Test_tabpanel_eval_tabpanel_statusline_tabline_0.dump
new file mode 100644
index 0000000..9214434
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_eval_tabpanel_statusline_tabline_0.dump
@@ -0,0 +1,10 @@
+|$+8#0000001#e0e0e08| |[|a@2|]| |$|│+1#0000000#ffffff0|$| @13|[|c@2|]| @13|$
+|$+8#0000001#e0e0e08| |[|b@2|]| |$|│+1#0000000#ffffff0> +0&&@34
+|$+2&&| |[|c@2|]| |$|│+1&&|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|$+3&&| @13|[|c@2|]| @13|$
+|"+0&&|c@2|"| |[|N|e|w|]| @33
diff --git a/src/testdir/dumps/Test_tabpanel_eval_tabpanel_statusline_tabline_1.dump b/src/testdir/dumps/Test_tabpanel_eval_tabpanel_statusline_tabline_1.dump
new file mode 100644
index 0000000..dae0d0b
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_eval_tabpanel_statusline_tabline_1.dump
@@ -0,0 +1,10 @@
+|$+1&#ffffff0| @13|[|c@2|]| @13|$|│|$+8#0000001#e0e0e08| |[|a@2|]| |$
+> +0#0000000#ffffff0@34|│+1&&|$+8#0000001#e0e0e08| |[|b@2|]| |$
+|~+0#4040ff13#ffffff0| @33|│+1#0000000&|$+2&&| |[|c@2|]| |$
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|$+3&&| @13|[|c@2|]| @13|$|│+1&&| @8
+|:+0&&|s|e|t| |t|a|b|p|a|n|e|l|o|p|t|+|=|a|l|i|g|n|:|r|i|g|h|t| @15
diff --git a/src/testdir/dumps/Test_tabpanel_eval_tabpanel_with_linebreaks_0.dump b/src/testdir/dumps/Test_tabpanel_eval_tabpanel_with_linebreaks_0.dump
new file mode 100644
index 0000000..dd55218
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_eval_tabpanel_with_linebreaks_0.dump
@@ -0,0 +1,10 @@
+|t+8#0000001#e0e0e08|o|p| @7|a@2| @1|b@2| | +2#0000000#ffffff0|c@2| | +1&&@18|X+8#0000001#e0e0e08
+|$| |[|a@2|]| @1|$> +0#0000000#ffffff0@34
+|b+8#0000001#e0e0e08|o|t@1|o|m| @3|~+0#4040ff13#ffffff0| @33
+|t+8#0000001#e0e0e08|o|p| @6|~+0#4040ff13#ffffff0| @33
+|$+8#0000001#e0e0e08| |[|b@2|]| @1|$|~+0#4040ff13#ffffff0| @33
+|b+8#0000001#e0e0e08|o|t@1|o|m| @3|~+0#4040ff13#ffffff0| @33
+|t+2#0000000&|o|p| @6|~+0#4040ff13&| @33
+|$+2#0000000&| |[|c@2|]| @1|$|~+0#4040ff13&| @33
+|b+2#0000000&|o|t@1|o|m| @3|~+0#4040ff13&| @33
+|"+0#0000000&|c@2|"| |[|N|e|w|]| @25|0|,|0|-|1| @2
diff --git a/src/testdir/dumps/Test_tabpanel_eval_tabpanel_with_linebreaks_1.dump b/src/testdir/dumps/Test_tabpanel_eval_tabpanel_with_linebreaks_1.dump
new file mode 100644
index 0000000..84bf683
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_eval_tabpanel_with_linebreaks_1.dump
@@ -0,0 +1,10 @@
+| +8#0000001#e0e0e08|a@2| @1|b@2| | +2#0000000#ffffff0|c@2| | +1&&@19|t+8#0000001#e0e0e08|o|p| @6
+> +0#0000000#ffffff0@34|$+8#0000001#e0e0e08| |[|a@2|]| @1|$
+|~+0#4040ff13#ffffff0| @33|b+8#0000001#e0e0e08|o|t@1|o|m| @3
+|~+0#4040ff13#ffffff0| @33|t+8#0000001#e0e0e08|o|p| @6
+|~+0#4040ff13#ffffff0| @33|$+8#0000001#e0e0e08| |[|b@2|]| @1|$
+|~+0#4040ff13#ffffff0| @33|b+8#0000001#e0e0e08|o|t@1|o|m| @3
+|~+0#4040ff13#ffffff0| @33|t+2#0000000&|o|p| @6
+|~+0#4040ff13&| @33|$+2#0000000&| |[|c@2|]| @1|$
+|~+0#4040ff13&| @33|b+2#0000000&|o|t@1|o|m| @3
+|:+0&&|s|e|t| |t|a|b|p|a|n|e|l|o|p|t|+|=|a|l|i|g|n|:|r|i|g|0|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_tabpanel_many_tabpages_0.dump b/src/testdir/dumps/Test_tabpanel_many_tabpages_0.dump
new file mode 100644
index 0000000..e974381
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_many_tabpages_0.dump
@@ -0,0 +1,10 @@
+|1+2&#ffffff0|:|t|a|b| @4> +0&&@34
+|2+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|3+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|4+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|5+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|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
+| +0#0000000&@36|0|,|0|-|1| @2
diff --git a/src/testdir/dumps/Test_tabpanel_many_tabpages_1.dump b/src/testdir/dumps/Test_tabpanel_many_tabpages_1.dump
new file mode 100644
index 0000000..3ac3dde
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_many_tabpages_1.dump
@@ -0,0 +1,10 @@
+|1+8#0000001#e0e0e08|:|t|a|b| @4> +0#0000000#ffffff0@34
+|2+2&&|:|t|a|b| @4|~+0#4040ff13&| @33
+|3+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|4+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|5+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|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
+| +0#0000000&@36|0|,|0|-|1| @2
diff --git a/src/testdir/dumps/Test_tabpanel_many_tabpages_2.dump b/src/testdir/dumps/Test_tabpanel_many_tabpages_2.dump
new file mode 100644
index 0000000..7b980e6
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_many_tabpages_2.dump
@@ -0,0 +1,10 @@
+|1+8#0000001#e0e0e08|:|t|a|b| @4> +0#0000000#ffffff0@34
+|2+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|3+2#0000000&|:|t|a|b| @4|~+0#4040ff13&| @33
+|4+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|5+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|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
+| +0#0000000&@36|0|,|0|-|1| @2
diff --git a/src/testdir/dumps/Test_tabpanel_many_tabpages_3.dump b/src/testdir/dumps/Test_tabpanel_many_tabpages_3.dump
new file mode 100644
index 0000000..fa3c09c
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_many_tabpages_3.dump
@@ -0,0 +1,10 @@
+|1+8#0000001#e0e0e08|:|t|a|b| @4> +0#0000000#ffffff0@34
+|2+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|3+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|4+2#0000000&|:|t|a|b| @4|~+0#4040ff13&| @33
+|5+8#0000001#e0e0e08|:|t|a|b| @4|~+0#4040ff13#ffffff0| @33
+|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
+| +0#0000000&@36|0|,|0|-|1| @2
diff --git a/src/testdir/dumps/Test_tabpanel_many_tabpages_4.dump b/src/testdir/dumps/Test_tabpanel_many_tabpages_4.dump
new file mode 100644
index 0000000..07ff180
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_many_tabpages_4.dump
@@ -0,0 +1,10 @@
+|1+8#0000001#e0e0e08|0|:|t|a|b| @3> +0#0000000#ffffff0@34
+|1+2&&@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
+|:+0#0000000&|t|a|b|n|e|x|t| |-|3| @25|0|,|0|-|1| @2
diff --git a/src/testdir/dumps/Test_tabpanel_noeval_tabpanel_statusline_tabline_0.dump b/src/testdir/dumps/Test_tabpanel_noeval_tabpanel_statusline_tabline_0.dump
new file mode 100644
index 0000000..9214434
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_noeval_tabpanel_statusline_tabline_0.dump
@@ -0,0 +1,10 @@
+|$+8#0000001#e0e0e08| |[|a@2|]| |$|│+1#0000000#ffffff0|$| @13|[|c@2|]| @13|$
+|$+8#0000001#e0e0e08| |[|b@2|]| |$|│+1#0000000#ffffff0> +0&&@34
+|$+2&&| |[|c@2|]| |$|│+1&&|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|$+3&&| @13|[|c@2|]| @13|$
+|"+0&&|c@2|"| |[|N|e|w|]| @33
diff --git a/src/testdir/dumps/Test_tabpanel_noeval_tabpanel_statusline_tabline_1.dump b/src/testdir/dumps/Test_tabpanel_noeval_tabpanel_statusline_tabline_1.dump
new file mode 100644
index 0000000..dae0d0b
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_noeval_tabpanel_statusline_tabline_1.dump
@@ -0,0 +1,10 @@
+|$+1&#ffffff0| @13|[|c@2|]| @13|$|│|$+8#0000001#e0e0e08| |[|a@2|]| |$
+> +0#0000000#ffffff0@34|│+1&&|$+8#0000001#e0e0e08| |[|b@2|]| |$
+|~+0#4040ff13#ffffff0| @33|│+1#0000000&|$+2&&| |[|c@2|]| |$
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|$+3&&| @13|[|c@2|]| @13|$|│+1&&| @8
+|:+0&&|s|e|t| |t|a|b|p|a|n|e|l|o|p|t|+|=|a|l|i|g|n|:|r|i|g|h|t| @15
diff --git a/src/testdir/dumps/Test_tabpanel_tabline_and_tabpanel_0.dump b/src/testdir/dumps/Test_tabpanel_tabline_and_tabpanel_0.dump
new file mode 100644
index 0000000..fdca7f1
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_tabline_and_tabpanel_0.dump
@@ -0,0 +1,10 @@
+|a+8#0000001#e0e0e08@2|.|t|x|t| @1|│+1#0000000#ffffff0| +8#0000001#e0e0e08|a@2|.|t|x|t| @1|b@2|.|t|x|t| | +2#0000000#ffffff0|c@2|.|t|x|t| | +1&&@6|X+8#0000001#e0e0e08
+|b@2|.|t|x|t| @1|│+1#0000000#ffffff0> +0&&@34
+|c+2&&@2|.|t|x|t| @1|│+1&&|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+|"+0#0000000&|c@2|.|t|x|t|"| |[|N|e|w|]| @21|0|,|0|-|1| @2
diff --git a/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_0.dump b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_0.dump
new file mode 100644
index 0000000..a50355f
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_0.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]|│+1#0000000#ffffff0| +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@11|X+8#0000001#e0e0e08
+|[+2#0000000#ffffff0|N|o| |N|a|m|e|]|│+1&&> +0&&@34
+| +1&&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +0#0000000&@36|0|,|0|-|1| @2
diff --git a/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_1.dump b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_1.dump
new file mode 100644
index 0000000..e347c7e
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_1.dump
@@ -0,0 +1,10 @@
+|│+1&#ffffff0| +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@20|X+8#0000001#e0e0e08
+|│+1#0000000#ffffff0> +0&&@43
+|│+1&&|~+0#4040ff13&| @42
+|│+1#0000000&|~+0#4040ff13&| @42
+|│+1#0000000&|~+0#4040ff13&| @42
+|│+1#0000000&|~+0#4040ff13&| @42
+|│+1#0000000&|~+0#4040ff13&| @42
+|│+1#0000000&|~+0#4040ff13&| @42
+|│+1#0000000&|~+0#4040ff13&| @42
+|:+0#0000000&|s|e|t| |t|a|b|p|a|n|e|l|o|p|t|=|c|o|l|u|m|n|s|:|1|,|v|0|,|0|-|1| @8|A|l@1
diff --git a/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_2.dump b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_2.dump
new file mode 100644
index 0000000..d1c5b92
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_2.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]|│+1#0000000#ffffff0| +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@11|X+8#0000001#e0e0e08
+|[+2#0000000#ffffff0|N|o| |N|a|m|e|]|│+1&&> +0&&@34
+| +1&&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+| +1#0000000&@8|│|~+0#4040ff13&| @33
+|:+0#0000000&|s|e|t| |t|a|b|p|a|n|e|l|o|p|t|=|c|o|l|u|m|n|s|:|1|0|,|v|e|r|t| @4|0|,|0|-|1| @2
diff --git a/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_3.dump b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_3.dump
new file mode 100644
index 0000000..fc84c0b
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_left_3.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|│+1#0000000#ffffff0| +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@19|X+8#0000001#e0e0e08
+|[+2#0000000#ffffff0|│+1&&> +0&&@42
+| +1&&|│|~+0#4040ff13&| @41
+| +1#0000000&|│|~+0#4040ff13&| @41
+| +1#0000000&|│|~+0#4040ff13&| @41
+| +1#0000000&|│|~+0#4040ff13&| @41
+| +1#0000000&|│|~+0#4040ff13&| @41
+| +1#0000000&|│|~+0#4040ff13&| @41
+| +1#0000000&|│|~+0#4040ff13&| @41
+|:+0#0000000&|s|e|t| |t|a|b|p|a|n|e|l|o|p|t|=|c|o|l|u|m|n|s|:|2|,|v|e|0|,|0|-|1| @8|A|l
diff --git a/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_0.dump b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_0.dump
new file mode 100644
index 0000000..02aa109
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_0.dump
@@ -0,0 +1,10 @@
+| +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@12|│|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]
+> +0#0000000#ffffff0@34|│+1&&|[+2&&|N|o| |N|a|m|e|]
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+| +0&&@26|0|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_1.dump b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_1.dump
new file mode 100644
index 0000000..8e97a7e
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_1.dump
@@ -0,0 +1,10 @@
+| +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@21|│
+> +0&&@43|│+1&&
+|~+0#4040ff13&| @42|│+1#0000000&
+|~+0#4040ff13&| @42|│+1#0000000&
+|~+0#4040ff13&| @42|│+1#0000000&
+|~+0#4040ff13&| @42|│+1#0000000&
+|~+0#4040ff13&| @42|│+1#0000000&
+|~+0#4040ff13&| @42|│+1#0000000&
+|~+0#4040ff13&| @42|│+1#0000000&
+|:+0&&|s|e|t| |t|a|b|p|a|n|e|l|o|p|t|=|a|l|i|g|n|:|r|i|g|h|0|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_2.dump b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_2.dump
new file mode 100644
index 0000000..6e33239
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_2.dump
@@ -0,0 +1,10 @@
+| +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@12|│|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]
+> +0#0000000#ffffff0@34|│+1&&|[+2&&|N|o| |N|a|m|e|]
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|~+0#4040ff13&| @33|│+1#0000000&| @8
+|:+0&&|s|e|t| |t|a|b|p|a|n|e|l|o|p|t|=|a|l|i|g|n|:|r|i|g|h|0|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_3.dump b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_3.dump
new file mode 100644
index 0000000..1f9255b
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_vert_is_multibytes_right_3.dump
@@ -0,0 +1,10 @@
+| +8#0000001#e0e0e08|[|N|o| |N|a|m|e|]| | +2#0000000#ffffff0|[|N|o| |N|a|m|e|]| | +1&&@20|│|[+8#0000001#e0e0e08
+> +0#0000000#ffffff0@42|│+1&&|[+2&&
+|~+0#4040ff13&| @41|│+1#0000000&| 
+|~+0#4040ff13&| @41|│+1#0000000&| 
+|~+0#4040ff13&| @41|│+1#0000000&| 
+|~+0#4040ff13&| @41|│+1#0000000&| 
+|~+0#4040ff13&| @41|│+1#0000000&| 
+|~+0#4040ff13&| @41|│+1#0000000&| 
+|~+0#4040ff13&| @41|│+1#0000000&| 
+|:+0&&|s|e|t| |t|a|b|p|a|n|e|l|o|p|t|=|a|l|i|g|n|:|r|i|g|h|0|,|0|-|1| @8|A|l@1| 
diff --git a/src/testdir/dumps/Test_tabpanel_visual_0.dump b/src/testdir/dumps/Test_tabpanel_visual_0.dump
new file mode 100644
index 0000000..af7ba65
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_visual_0.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]| |a+0&#a8a8a8255@2|1| |b@2|1| >c+0#0000000#ffffff0@2|1| |d@2|1| @15
+|++2&&| |[|N|o| |N|a|m|e|a+0&&@2|2| |b@2|2| |c@2|2| |d@2|2| @15
+| +1&&@9|a+0&&@2|3| |b@2|3| |c@2|3| |d@2|3| @15
+| +1&&@9|a+0&&@2|4| |b@2|4| |c@2|4| |d@2|4| @15
+| +1&&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+|-+2#0000000&@1| |V|I|S|U|A|L| |-@1| +0&&@4|1@1| @17|1|,|1@1| @3
diff --git a/src/testdir/dumps/Test_tabpanel_visual_1.dump b/src/testdir/dumps/Test_tabpanel_visual_1.dump
new file mode 100644
index 0000000..0cdc5f2
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_visual_1.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]| |a+0#0000000#ffffff0@2|1| |b@2|1| |c@2|1| |d@2|1| @15
+|++2&&| |[|N|o| |N|a|m|e|a+0&&@2|2| |b+0#0000001#a8a8a8255@2|2| |c@2>2+0#0000000#ffffff0| |d@2|2| @15
+| +1&&@9|a+0&&@2|3| |b@2|3| |c@2|3| |d@2|3| @15
+| +1&&@9|a+0&&@2|4| |b@2|4| |c@2|4| |d@2|4| @15
+| +1&&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+|-+2#0000000&@1| |V|I|S|U|A|L| |-@1| +0&&@4|9| @18|2|,|1|4| @3
diff --git a/src/testdir/dumps/Test_tabpanel_visual_2.dump b/src/testdir/dumps/Test_tabpanel_visual_2.dump
new file mode 100644
index 0000000..9a307c1
--- /dev/null
+++ b/src/testdir/dumps/Test_tabpanel_visual_2.dump
@@ -0,0 +1,10 @@
+|[+8#0000001#e0e0e08|N|o| |N|a|m|e|]| |a+0#0000000#ffffff0@2|1| |b@2|1| |c@2|1| |d@2|1| @15
+|++2&&| |[|N|o| |N|a|m|e|a+0&&@2|2| >b@2|2| |c@2|2| |d@2|2| @15
+| +1&&@9|a+0&&@2|3| |b@2|3| |c@2|3| |d@2|3| @15
+| +1&&@9|a+0&&@2|4| |b@2|4| |c@2|4| |d@2|4| @15
+| +1&&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+| +1#0000000&@9|~+0#4040ff13&| @33
+|b+0#0000000&@2|2| |c@2|2| @27|2|,|6| @4
diff --git a/src/testdir/gen_opt_test.vim b/src/testdir/gen_opt_test.vim
index 3d798e9..1f15453 100644
--- a/src/testdir/gen_opt_test.vim
+++ b/src/testdir/gen_opt_test.vim
@@ -94,6 +94,7 @@
       \ 'scrolljump': [[-100, -1, 0, 1, 2, 15], [-101, 999]],
       \ 'scrolloff': [[0, 1, 8, 999], [-1]],
       \ 'shiftwidth': [[0, 1, 8, 999], [-1]],
+      \ 'showtabpanel': [[0, 1, 2], []],
       \ 'sidescroll': [[0, 1, 8, 999], [-1]],
       \ 'sidescrolloff': [[0, 1, 8, 999], [-1]],
       \ 'tabstop': [[1, 4, 8, 12, 9999], [-1, 0, 10000]],
@@ -301,6 +302,11 @@
       \		['xxx']],
       \ 'tabclose': [['', 'left', 'uselast', 'left,uselast'], ['xxx']],
       \ 'tabline': [['', 'xxx'], ['%$', '%{', '%{%', '%{%}', '%(', '%)']],
+      \ 'tabpanel': [['', 'aaa', 'bbb'], []],
+      \ 'tabpanelopt': [['', 'align:left', 'align:right', 'vert', 'columns:0',
+      \		'columns:20', 'columns:999'],
+      \		['xxx', 'align:', 'align:middle', 'colomns:', 'cols:10',
+      \		'cols:-1']],
       \ 'tagcase': [['followic', 'followscs', 'ignore', 'match', 'smart'],
       \		['', 'xxx', 'smart,match']],
       \ 'termencoding': [has('gui_gtk') ? [] : ['', 'utf-8'], ['xxx']],
@@ -373,8 +379,17 @@
       \ 'verbosefile': [[], ['call delete("Xfile")']],
       \}
 
-const invalid_options = test_values->keys()
+let invalid_options = test_values->keys()
       \->filter({-> v:val !~# '^other' && !exists($"&{v:val}")})
+for s:skip_option in [
+  \ [!has('tabpanel'), 'tabpanel'],
+  \ [!has('tabpanel'), 'tabpanelopt'],
+  \ [!has('tabpanel'), 'showtabpanel'],
+  \ ]
+  if s:skip_option[0]
+    call remove(invalid_options, s:skip_option[1])
+  endif
+endfor
 if !empty(invalid_options)
   throw $"Invalid option name in test_values: '{invalid_options->join("', '")}'"
 endif
@@ -406,6 +421,8 @@
   let [pre_processing, post_processing] = get(test_prepost, fullname, [[], []])
   let script += pre_processing
 
+  " Setting an option can only fail when it's implemented.
+  call add(script, $"if exists('+{fullname}')")
   if line =~ 'P_BOOL'
     for opt in [fullname, shortname]
       for cmd in ['set', 'setlocal', 'setglobal']
@@ -439,8 +456,6 @@
     endfor
 
     " Failure tests
-    " Setting an option can only fail when it's implemented.
-    call add(script, $"if exists('+{fullname}')")
     for opt in [fullname, shortname]
       for cmd in ['set', 'setlocal', 'setglobal']
 	for val in invalid_values
@@ -464,7 +479,6 @@
 	endfor
       endfor
     endfor
-    call add(script, "endif")
   endif
 
   " Cannot change 'termencoding' in GTK
@@ -476,6 +490,8 @@
     call add(script, 'endif')
   endif
 
+  call add(script, "endif")
+
   let script += post_processing
   call add(script, 'endfunc')
 endwhile
diff --git a/src/testdir/test_cmdline.vim b/src/testdir/test_cmdline.vim
index 68933a3..9a3fe20 100644
--- a/src/testdir/test_cmdline.vim
+++ b/src/testdir/test_cmdline.vim
@@ -4345,4 +4345,9 @@
   set wildoptions&
 endfunc
 
+func Test_redrawtabpanel_error()
+  CheckNotFeature tabpanel
+  call assert_fails(':redrawtabpanel', 'E1547:')
+endfunc
+
 " vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/testdir/test_tabpanel.vim b/src/testdir/test_tabpanel.vim
new file mode 100644
index 0000000..630226f
--- /dev/null
+++ b/src/testdir/test_tabpanel.vim
@@ -0,0 +1,480 @@
+" Tests for tabpanel
+
+source check.vim
+source screendump.vim
+CheckFeature tabpanel
+
+function! s:reset()
+  set tabpanel&
+  set tabpanelopt&
+  set showtabpanel&
+endfunc
+
+function! Test_tabpanel_mouse()
+  let save_showtabline = &showtabline
+  let save_mouse = &mouse
+  set showtabline=0 mouse=a
+
+  tabnew
+  tabnew
+
+  call test_setmouse(1, 1)
+  call feedkeys("\<LeftMouse>", 'xt')
+  call assert_equal(3, tabpagenr())
+
+  set showtabpanel=2 tabpanelopt=columns:10
+
+  call test_setmouse(1, 1)
+  call feedkeys("\<LeftMouse>", 'xt')
+  call assert_equal(1, tabpagenr())
+  call test_setmouse(2, 1)
+  call feedkeys("\<LeftMouse>", 'xt')
+  call assert_equal(2, tabpagenr())
+  call test_setmouse(3, 1)
+  call feedkeys("\<LeftMouse>", 'xt')
+  call assert_equal(3, tabpagenr())
+
+  call feedkeys("\<LeftMouse>", 'xt')
+  call test_setmouse(2, 3)
+  let pos = getmousepos()
+  call assert_equal(2, pos['winrow'])
+  call assert_equal(0, pos['wincol'])
+  call assert_equal(2, pos['screenrow'])
+  call assert_equal(3, pos['screencol'])
+
+  call test_setmouse(1, 11)
+  call feedkeys("\<LeftMouse>", 'xt')
+  let pos = getmousepos()
+  call assert_equal(1, pos['winrow'])
+  call assert_equal(1, pos['wincol'])
+  call assert_equal(1, pos['screenrow'])
+  call assert_equal(11, pos['screencol'])
+
+  new
+  wincmd x
+
+  call test_setmouse(10, 11)
+  call feedkeys("\<LeftMouse>", 'xt')
+  let pos = getmousepos()
+  call assert_equal(10, pos['winrow'])
+  call assert_equal(1, pos['wincol'])
+  call assert_equal(10, pos['screenrow'])
+  call assert_equal(11, pos['screencol'])
+
+  tabonly!
+  call s:reset()
+  let &mouse = save_mouse
+  let &showtabline = save_showtabline
+endfunc
+
+function! Test_tabpanel_drawing()
+  CheckScreendump
+
+  let lines =<< trim END
+    function! MyTabPanel()
+      let n = g:actual_curtabpage
+      let hi = n == tabpagenr() ? 'TabLineSel' : 'TabLine'
+      let label = printf("\n%%#%sTabNumber#%d:%%#%s#", hi, n, hi)
+      let label ..= '%1*%f%*'
+      return label
+    endfunction
+    hi User1 ctermfg=12
+
+    set showtabline=0
+    set showtabpanel=0
+    set tabpanelopt=columns:16
+    set tabpanel=
+    silent edit Xtabpanel1
+
+    nnoremap \01 <Cmd>set showtabpanel=2<CR>
+    nnoremap \02 <C-w>v
+    nnoremap \03 <Cmd>call setline(1, ['a', 'b', 'c'])<CR>
+    nnoremap \04 <Cmd>silent tabnew Xtabpanel2<CR><Cmd>call setline(1, ['d', 'e', 'f'])<CR>
+    nnoremap \05 <Cmd>set tabpanel=%!MyTabPanel()<CR>
+    nnoremap \06 <Cmd>set tabpanelopt+=align:right<CR>
+    nnoremap \07 <Cmd>tab terminal NONE<CR><C-w>N
+    nnoremap \08 <Cmd>tabclose!<CR><Cmd>tabclose!<CR>
+  END
+  call writefile(lines, 'XTest_tabpanel', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel', {'rows': 6, 'cols': 45})
+
+  call VerifyScreenDump(buf, 'Test_tabpanel_drawing_00', {})
+
+  for i in range(1, 8)
+    let n = printf('%02d', i)
+    call term_sendkeys(buf, '\' .. n)
+    call VerifyScreenDump(buf, 'Test_tabpanel_drawing_' .. n, {})
+  endfor
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_drawing_with_popupwin()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:20
+    set showtabline=0
+    tabnew
+    setlocal buftype=nofile
+    call setbufline(bufnr(), 1, repeat([repeat('.', &columns - 20)], &lines))
+    highlight TestingForTabPanelPopupwin guibg=#7777ff guifg=#000000
+    for line in [1, &lines]
+      for col in [1, &columns - 20 - 2]
+        call popup_create([
+          \   '@',
+          \ ], {
+          \   'line': line,
+          \   'col': col,
+          \   'border': [],
+          \   'highlight': 'TestingForTabPanelPopupwin',
+          \ })
+      endfor
+    endfor
+    call cursor(4, 10)
+    call popup_atcursor('atcursor', {
+      \   'highlight': 'TestingForTabPanelPopupwin',
+      \ })
+  END
+  call writefile(lines, 'XTest_tabpanel_with_popupwin', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_with_popupwin', {'rows': 10, 'cols': 45})
+
+  call VerifyScreenDump(buf, 'Test_tabpanel_drawing_with_popupwin_0', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_drawing_fill_tailing()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:20
+    set showtabline=0
+    e aaa.txt
+    tabnew
+    e bbb.txt
+    let &tabpanel = "abc"
+    redraw!
+    " Check whether "abc" is cleared
+    let &tabpanel = "\nTOP\n%f\nBOTTOM"
+  END
+  call writefile(lines, 'XTest_tabpanel_fill_tailing', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_fill_tailing', {'rows': 10, 'cols': 45})
+
+  call VerifyScreenDump(buf, 'Test_tabpanel_drawing_fill_tailing_0', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_drawing_pum()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:20
+    set showtabline=0
+    e aaa.txt
+    tabnew
+    e bbb.txt
+  END
+  call writefile(lines, 'XTest_tabpanel_pum', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_pum', {'rows': 10, 'cols': 45})
+
+  call term_sendkeys(buf, "i\<C-x>\<C-v>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_drawing_pum_0', {})
+
+  call term_sendkeys(buf, "\<cr>  ab\<C-x>\<C-v>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_drawing_pum_1', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_scrolling()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:20
+    set showtabline=0
+    set nowrap
+    set number
+    e aaa.txt
+    tabnew
+    e bbb.txt
+    vsplit
+    call setbufline(bufnr(), 1, repeat(['text text text text'], 100))
+    wincmd =
+  END
+  call writefile(lines, 'XTest_tabpanel_scrolling', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_scrolling', {'rows': 10, 'cols': 45})
+  let n = 0
+  for c in ['H', 'J', 'K', 'L']
+    call term_sendkeys(buf, ":wincmd " .. c ..  "\<cr>")
+    call term_sendkeys(buf, "\<C-d>\<C-d>")
+    call term_sendkeys(buf, "r@")
+    call VerifyScreenDump(buf, 'Test_tabpanel_drawing_scrolling_' .. n, {})
+    let n += 1
+  endfor
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_many_tabpages()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:10
+    set showtabline=0
+    set tabpanel=%{g:actual_curtabpage}:tab
+    execute join(repeat(['tabnew'], 20), ' | ')
+  END
+  call writefile(lines, 'XTest_tabpanel_many_tabpages', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_many_tabpages', {'rows': 10, 'cols': 45})
+  for n in range(0, 3)
+    call term_sendkeys(buf, "gt")
+    call VerifyScreenDump(buf, 'Test_tabpanel_many_tabpages_' .. n, {})
+  endfor
+  call term_sendkeys(buf, ":tabnext +10\<cr>")
+  call term_sendkeys(buf, ":tabnext -3\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_many_tabpages_4', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_visual()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:10
+    set showtabline=0
+    tabnew
+    call setbufline(bufnr(), 1, ['aaa1 bbb1 ccc1 ddd1', 'aaa2 bbb2 ccc2 ddd2', 'aaa3 bbb3 ccc3 ddd3', 'aaa4 bbb4 ccc4 ddd4'])
+  END
+  call writefile(lines, 'XTest_tabpanel_visual', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_visual', {'rows': 10, 'cols': 45})
+  call term_sendkeys(buf, "v2w")
+  call VerifyScreenDump(buf, 'Test_tabpanel_visual_0', {})
+  call term_sendkeys(buf, "\<esc>0jw")
+  call term_sendkeys(buf, "v2wge")
+  call VerifyScreenDump(buf, 'Test_tabpanel_visual_1', {})
+  call term_sendkeys(buf, "y:echo @\"\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_visual_2', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_commandline()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:10
+    set showtabline=0
+    tabnew
+  END
+  call writefile(lines, 'XTest_tabpanel_commandline', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_commandline', {'rows': 10, 'cols': 45})
+  call term_sendkeys(buf, ":ab\<tab>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_commandline_0', {})
+
+  call term_sendkeys(buf, "\<esc>")
+  call term_sendkeys(buf, ":set wildoptions=pum\<cr>")
+  call term_sendkeys(buf, ":ab\<tab>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_commandline_1', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_tabline_and_tabpanel()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:10,vert
+    set fillchars=tpl_vert:│
+    set showtabline=2
+    e aaa.txt
+    tabnew
+    e bbb.txt
+    tabnew
+    e ccc.txt
+  END
+  call writefile(lines, 'XTest_tabpanel_tabline_and_tabpanel', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_tabline_and_tabpanel', {'rows': 10, 'cols': 45})
+  call VerifyScreenDump(buf, 'Test_tabpanel_tabline_and_tabpanel_0', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_dont_overflow_into_tabpanel()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:10
+    set showtabline=2
+    tabnew
+    call setline(1, repeat('x', 100))
+    set wrap
+  END
+  call writefile(lines, 'XTest_tabpanel_dont_overflow_into_tabpanel', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_dont_overflow_into_tabpanel', {'rows': 10, 'cols': 45})
+  call VerifyScreenDump(buf, 'Test_tabpanel_dont_overflow_into_tabpanel_0', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_dont_vert_is_multibytes_left()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=columns:10,vert
+    set fillchars=tpl_vert:│
+    set showtabline=2
+    tabnew
+  END
+  call writefile(lines, 'XTest_tabpanel_vert_is_multibyte_lefts', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_vert_is_multibyte_lefts', {'rows': 10, 'cols': 45})
+  call VerifyScreenDump(buf, 'Test_tabpanel_vert_is_multibytes_left_0', {})
+
+  call term_sendkeys(buf, ":set tabpanelopt=columns:1,vert\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_vert_is_multibytes_left_1', {})
+
+  call term_sendkeys(buf, ":set tabpanelopt=columns:10,vert\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_vert_is_multibytes_left_2', {})
+
+  call term_sendkeys(buf, ":set tabpanelopt=columns:2,vert\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_vert_is_multibytes_left_3', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_dont_vert_is_multibytes_right()
+  CheckScreendump
+
+  let lines =<< trim END
+    set showtabpanel=2
+    set tabpanelopt=align:right,columns:10,vert
+    set fillchars=tpl_vert:│
+    set showtabline=2
+    tabnew
+  END
+  call writefile(lines, 'XTest_tabpanel_vert_is_multibytes_right', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_vert_is_multibytes_right', {'rows': 10, 'cols': 45})
+  call VerifyScreenDump(buf, 'Test_tabpanel_vert_is_multibytes_right_0', {})
+
+  call term_sendkeys(buf, ":set tabpanelopt=align:right,columns:1,vert\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_vert_is_multibytes_right_1', {})
+
+  call term_sendkeys(buf, ":set tabpanelopt=align:right,columns:10,vert\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_vert_is_multibytes_right_2', {})
+
+  call term_sendkeys(buf, ":set tabpanelopt=align:right,columns:2,vert\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_vert_is_multibytes_right_3', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_eval_tabpanel_statusline_tabline()
+  CheckScreendump
+
+  let lines =<< trim END
+    function! Expr()
+      return "$%=[%f]%=$"
+    endfunction
+    set laststatus=2
+    set showtabline=2
+    set showtabpanel=2
+    set statusline=%!Expr()
+    set tabline=%!Expr()
+    set tabpanel=%!Expr()
+    set tabpanelopt=columns:10,vert
+    set fillchars=tpl_vert:│
+    e aaa
+    tabnew
+    e bbb
+    tabnew
+    e ccc
+  END
+  call writefile(lines, 'XTest_tabpanel_eval_tabpanel_statusline_tabline', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_eval_tabpanel_statusline_tabline', {'rows': 10, 'cols': 45})
+  call VerifyScreenDump(buf, 'Test_tabpanel_eval_tabpanel_statusline_tabline_0', {})
+  call term_sendkeys(buf, ":set tabpanelopt+=align:right\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_eval_tabpanel_statusline_tabline_1', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_noeval_tabpanel_statusline_tabline()
+  CheckScreendump
+
+  let lines =<< trim END
+    set laststatus=2
+    set showtabline=2
+    set showtabpanel=2
+    set statusline=$%=[%f]%=$
+    set tabline=$%=[%f]%=$
+    set tabpanel=$%=[%f]%=$
+    set tabpanelopt=columns:10,vert
+    set fillchars=tpl_vert:│
+    e aaa
+    tabnew
+    e bbb
+    tabnew
+    e ccc
+  END
+  call writefile(lines, 'XTest_tabpanel_noeval_tabpanel_statusline_tabline', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_noeval_tabpanel_statusline_tabline', {'rows': 10, 'cols': 45})
+  call VerifyScreenDump(buf, 'Test_tabpanel_noeval_tabpanel_statusline_tabline_0', {})
+  call term_sendkeys(buf, ":set tabpanelopt+=align:right\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_noeval_tabpanel_statusline_tabline_1', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+function! Test_tabpanel_eval_tabpanel_with_linebreaks()
+  CheckScreendump
+
+  let lines =<< trim END
+    function! Expr()
+      return "top\n$%=[%f]%=$\nbottom"
+    endfunction
+    set showtabpanel=2
+    set tabpanel=%!Expr()
+    set tabpanelopt=columns:10
+    e aaa
+    tabnew
+    e bbb
+    tabnew
+    e ccc
+  END
+  call writefile(lines, 'XTest_tabpanel_eval_tabpanel_with_linebreaks', 'D')
+
+  let buf = RunVimInTerminal('-S XTest_tabpanel_eval_tabpanel_with_linebreaks', {'rows': 10, 'cols': 45})
+  call VerifyScreenDump(buf, 'Test_tabpanel_eval_tabpanel_with_linebreaks_0', {})
+  call term_sendkeys(buf, ":set tabpanelopt+=align:right\<cr>")
+  call VerifyScreenDump(buf, 'Test_tabpanel_eval_tabpanel_with_linebreaks_1', {})
+
+  call StopVimInTerminal(buf)
+endfunc
+
+" vim: shiftwidth=2 sts=2 expandtab
diff --git a/src/version.c b/src/version.c
index 5475e0a..88653f8 100644
--- a/src/version.c
+++ b/src/version.c
@@ -555,6 +555,11 @@
 #if defined(USE_SYSTEM) && defined(UNIX)
 	"+system()",
 #endif
+#if defined(FEAT_TABPANEL)
+	"+tabpanel",
+#else
+	"-tabpanel",
+#endif
 	"+tag_binary",
 	"-tag_old_static",
 	"-tag_any_white",
@@ -4037,7 +4042,7 @@
 
     // start displaying the message lines after half of the blank lines
     row = blanklines / 2;
-    if ((row >= 2 && Columns >= 50) || colon)
+    if ((row >= 2 && COLUMNS_WITHOUT_TPL() >= 50) || colon)
     {
 	for (i = 0; i < (int)ARRAY_LENGTH(lines); ++i)
 	{
@@ -4120,7 +4125,7 @@
 	}
 	col += (int)STRLEN(vers);
     }
-    col = (Columns - col) / 2;
+    col = (COLUMNS_WITHOUT_TPL() - col) / 2;
     if (col < 0)
 	col = 0;
 
@@ -4139,13 +4144,14 @@
 	    else
 		clen += byte2cells(p[l]);
 	}
-	screen_puts_len(p, l, row, col, *p == '<' ? HL_ATTR(HLF_8) : attr);
+	screen_puts_len(p, l, row, col + TPL_LCOL(NULL),
+		*p == '<' ? HL_ATTR(HLF_8) : attr);
 	col += clen;
     }
 
     // Add the version number to the version line.
     if (add_version)
-	screen_puts(vers, row, col, 0);
+	screen_puts(vers, row, col + TPL_LCOL(NULL), 0);
 }
 
 /*
@@ -4155,6 +4161,9 @@
 ex_intro(exarg_T *eap UNUSED)
 {
     screenclear();
+#if defined(FEAT_TABPANEL)
+    draw_tabpanel();
+#endif
     intro_message(TRUE);
     wait_return(TRUE);
 }
diff --git a/src/vim.h b/src/vim.h
index fbe5c34..26adc18 100644
--- a/src/vim.h
+++ b/src/vim.h
@@ -919,6 +919,14 @@
 #define FINDFILE_DIR	1	// only directories
 #define FINDFILE_BOTH	2	// files and directories
 
+#if defined(FEAT_TABPANEL)
+# define COLUMNS_WITHOUT_TPL()		(Columns - tabpanel_width())
+# define TPL_LCOL(W)			tabpanel_leftcol(W)
+#else
+# define COLUMNS_WITHOUT_TPL()		Columns
+# define TPL_LCOL(W)			0
+#endif
+
 #define W_ENDCOL(wp)	((wp)->w_wincol + (wp)->w_width)
 #ifdef FEAT_MENU
 # define W_WINROW(wp)	((wp)->w_winrow + (wp)->w_winbar_height)
@@ -1547,6 +1555,9 @@
     , HLF_ST	    // status lines of terminal windows
     , HLF_STNC	    // status lines of not-current terminal windows
     , HLF_MSG	    // message area
+    , HLF_TPL	    // tabpanel
+    , HLF_TPLS	    // tabpanel selected
+    , HLF_TPLF	    // tabpanel filler
     , HLF_COUNT	    // MUST be the last one
 } hlf_T;
 
@@ -1558,7 +1569,8 @@
 		  'B', 'P', 'R', 'L', \
 		  '+', '=', 'k', '<','[', ']', '{', '}', 'x', 'X', \
 		  '*', '#', '_', '!', '.', 'o', 'q', \
-		  'z', 'Z', 'g'}
+		  'z', 'Z', 'g', \
+		  '%', '^', '&' }
 
 /*
  * Values for behaviour in spell_move_to
@@ -2077,6 +2089,7 @@
 #define IN_STATUS_LINE		2	// on status or command line
 #define IN_SEP_LINE		4	// on vertical separator line
 #define IN_OTHER_WIN		8	// in other window but can't go there
+#define IN_TABPANEL		16	// in tabpanel
 #define CURSOR_MOVED		0x100
 #define MOUSE_FOLD_CLOSE	0x200	// clicked on '-' in fold column
 #define MOUSE_FOLD_OPEN		0x400	// clicked on '+' in fold column
diff --git a/src/window.c b/src/window.c
index 1eb32bc..c7fea12 100644
--- a/src/window.c
+++ b/src/window.c
@@ -1386,7 +1386,7 @@
 	if (flags & (WSP_TOP | WSP_BOT))
 	{
 	    wp->w_wincol = 0;
-	    win_new_width(wp, Columns);
+	    win_new_width(wp, COLUMNS_WITHOUT_TPL());
 	    wp->w_vsep_width = 0;
 	}
 	else
@@ -2086,7 +2086,7 @@
 	dir = *p_ead;
     win_equal_rec(next_curwin == NULL ? curwin : next_curwin, current,
 		      topframe, dir, 0, tabline_height(),
-					   (int)Columns, topframe->fr_height);
+					   (int)COLUMNS_WITHOUT_TPL(), topframe->fr_height);
     if (!is_aucmd_win(next_curwin))
 	win_fix_scroll(TRUE);
 }
@@ -2144,7 +2144,7 @@
 	    // frame.
 	    n = frame_minwidth(topfr, NOWIN);
 	    // add one for the rightmost window, it doesn't have a separator
-	    if (col + width == Columns)
+	    if (col + width == COLUMNS_WITHOUT_TPL())
 		extra_sep = 1;
 	    else
 		extra_sep = 0;
@@ -2623,6 +2623,10 @@
     apply_autocmds(EVENT_TABENTER, NULL, NULL, FALSE, curbuf);
     if (old_curbuf != curbuf)
 	apply_autocmds(EVENT_BUFENTER, NULL, NULL, FALSE, curbuf);
+#if defined(FEAT_TABPANEL)
+    if (p_stpl > 0)
+	shell_new_columns();
+#endif
     return TRUE;
 }
 
@@ -4558,7 +4562,7 @@
     if (curwin->w_frame == NULL)
 	return FAIL;
     topframe = curwin->w_frame;
-    topframe->fr_width = Columns;
+    topframe->fr_width = COLUMNS_WITHOUT_TPL();
     topframe->fr_height = Rows - p_ch;
 
     return OK;
@@ -4588,8 +4592,8 @@
     firstwin->w_height = ROWS_AVAIL;
     firstwin->w_prev_height = ROWS_AVAIL;
     topframe->fr_height = ROWS_AVAIL;
-    firstwin->w_width = Columns;
-    topframe->fr_width = Columns;
+    firstwin->w_width = COLUMNS_WITHOUT_TPL();
+    topframe->fr_width = COLUMNS_WITHOUT_TPL();
 }
 
 /*
@@ -4963,7 +4967,7 @@
     tp->tp_lastwin = lastwin;
     tp->tp_old_Rows = Rows;
     if (tp->tp_old_Columns != -1)
-	tp->tp_old_Columns = Columns;
+	tp->tp_old_Columns = COLUMNS_WITHOUT_TPL();
     firstwin = NULL;
     lastwin = NULL;
     return OK;
@@ -5026,12 +5030,12 @@
 #endif
 		))
 	shell_new_rows();
-    if (curtab->tp_old_Columns != Columns)
+    if (curtab->tp_old_Columns != COLUMNS_WITHOUT_TPL())
     {
 	if (starting == 0)
 	{
 	    shell_new_columns();	// update window widths
-	    curtab->tp_old_Columns = Columns;
+	    curtab->tp_old_Columns = COLUMNS_WITHOUT_TPL();
 	}
 	else
 	    curtab->tp_old_Columns = -1;  // update window widths later
@@ -5244,6 +5248,9 @@
 
     // Need to redraw the tabline.  Tab page contents doesn't change.
     redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
 }
 
 
@@ -5667,6 +5674,9 @@
 	redraw_mode = TRUE;
 #endif
     redraw_tabline = TRUE;
+#if defined(FEAT_TABPANEL)
+    redraw_tabpanel = TRUE;
+#endif
     if (restart_edit)
 	redraw_later(UPD_VALID);	// causes status line redraw
 
@@ -5792,7 +5802,7 @@
     if (!hidden)
 	win_append(after, new_wp);
     new_wp->w_wincol = 0;
-    new_wp->w_width = Columns;
+    new_wp->w_width = COLUMNS_WITHOUT_TPL();
 
     // position the display and the cursor at the top of the file.
     new_wp->w_topline = 1;
@@ -6181,9 +6191,9 @@
 
     // First try setting the widths of windows with 'winfixwidth'.  If that
     // doesn't result in the right width, forget about that option.
-    frame_new_width(topframe, (int)Columns, FALSE, TRUE);
-    if (!frame_check_width(topframe, Columns))
-	frame_new_width(topframe, (int)Columns, FALSE, FALSE);
+    frame_new_width(topframe, COLUMNS_WITHOUT_TPL(), FALSE, TRUE);
+    if (!frame_check_width(topframe, COLUMNS_WITHOUT_TPL()))
+	frame_new_width(topframe, COLUMNS_WITHOUT_TPL(), FALSE, FALSE);
 
     (void)win_comp_pos();		// recompute w_winrow and w_wincol
 #if 0
@@ -6425,7 +6435,7 @@
 		if (frp != curfrp)
 		    room -= frame_minheight(frp, NULL);
 	    }
-	    if (curfrp->fr_width != Columns)
+	    if (curfrp->fr_width != COLUMNS_WITHOUT_TPL())
 		room_cmdline = 0;
 	    else
 	    {
@@ -6438,7 +6448,7 @@
 
 	    if (height <= room + room_cmdline)
 		break;
-	    if (run == 2 || curfrp->fr_width == Columns)
+	    if (run == 2 || curfrp->fr_width == COLUMNS_WITHOUT_TPL())
 	    {
 		height = room + room_cmdline;
 		break;
@@ -7333,7 +7343,7 @@
 
     // Find bottom frame with width of screen.
     frame_T *frp = lastwin->w_frame;
-    while (frp->fr_width != Columns && frp->fr_parent != NULL)
+    while (frp->fr_width != COLUMNS_WITHOUT_TPL() && frp->fr_parent != NULL)
 	frp = frp->fr_parent;
 
     // Avoid changing the height of a window with 'winfixheight' set.