blob: fb5a957a3e7f1baa99e39e8b65e63f7b510baadc [file] [log] [blame]
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +02001/* vi:set ts=8 sts=4 sw=4 noet:
2 *
3 * VIM - Vi IMproved by Bram Moolenaar
4 *
5 * Do ":help uganda" in Vim to read copying and usage conditions.
6 * Do ":help credits" in Vim to see a list of people who contributed.
7 * See README.txt for an overview of the Vim source code.
8 */
9
10/*
11 * tabpanel.c:
12 */
13
14#include "vim.h"
15
16#if defined(FEAT_TABPANEL) || defined(PROTO)
17
18static void do_by_tplmode(int tplmode, int col_start, int col_end,
Hirohito Higashic659e4a2025-05-16 19:34:34 +020019 int *pcurtab_row, int *ptabpagenr);
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020020
21// set pcurtab_row. don't redraw tabpanel.
22#define TPLMODE_GET_CURTAB_ROW 0
23// set ptabpagenr. don't redraw tabpanel.
24#define TPLMODE_GET_TABPAGENR 1
25// redraw tabpanel.
26#define TPLMODE_REDRAW 2
27
28#define TPL_FILLCHAR ' '
29
30#define VERT_LEN 1
31
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020032// tpl_align's values
33#define ALIGN_LEFT 0
34#define ALIGN_RIGHT 1
35
36static char_u *opt_name = (char_u *)"tabpanel";
37static int opt_scope = OPT_LOCAL;
38static int tpl_align = ALIGN_LEFT;
39static int tpl_columns = 20;
Hirohito Higashic659e4a2025-05-16 19:34:34 +020040static int tpl_is_vert = FALSE;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020041
42typedef struct {
43 win_T *wp;
44 win_T *cwp;
45 char_u *user_defined;
46 int maxrow;
47 int offsetrow;
48 int *prow;
49 int *pcol;
50 int attr;
51 int col_start;
52 int col_end;
53} tabpanel_T;
54
55 int
56tabpanelopt_changed(void)
57{
58 char_u *p;
59 int new_align = ALIGN_LEFT;
60 int new_columns = 20;
Hirohito Higashic659e4a2025-05-16 19:34:34 +020061 int new_is_vert = FALSE;
Naruhiko Nishino2a1e2532025-05-17 16:19:24 +020062 int do_equal = 0;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020063
64 p = p_tplo;
65 while (*p != NUL)
66 {
67 if (STRNCMP(p, "align:left", 10) == 0)
68 {
69 p += 10;
70 new_align = ALIGN_LEFT;
71 }
72 else if (STRNCMP(p, "align:right", 11) == 0)
73 {
74 p += 11;
75 new_align = ALIGN_RIGHT;
76 }
77 else if (STRNCMP(p, "columns:", 8) == 0 && VIM_ISDIGIT(p[8]))
78 {
79 p += 8;
80 new_columns = getdigits(&p);
81 }
82 else if (STRNCMP(p, "vert", 4) == 0)
83 {
84 p += 4;
Hirohito Higashic659e4a2025-05-16 19:34:34 +020085 new_is_vert = TRUE;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020086 }
87
88 if (*p != ',' && *p != NUL)
89 return FAIL;
90 if (*p == ',')
91 ++p;
92 }
93
Naruhiko Nishino2a1e2532025-05-17 16:19:24 +020094 // Whether all the windows are automatically made the same size
95 // when tabpanel size is changed.
96 do_equal = p_ea && tpl_columns != new_columns;
97
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020098 tpl_align = new_align;
99 tpl_columns = new_columns;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200100 tpl_is_vert = new_is_vert;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200101
Naruhiko Nishino2a1e2532025-05-17 16:19:24 +0200102 shell_new_columns();
103 redraw_tabpanel = TRUE;
104
105 if (do_equal)
106 win_equal(curwin, FALSE, 0);
107
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200108 return OK;
109}
110
111/*
112 * Return the width of tabpanel.
113 */
114 int
115tabpanel_width(void)
116{
117 if (msg_scrolled != 0)
118 return 0;
119
120 switch (p_stpl)
121 {
122 case 0:
123 return 0;
124 case 1:
125 if (first_tabpage->tp_next == NULL)
126 return 0;
127 }
128 if (Columns < tpl_columns)
129 return 0;
130 else
131 return tpl_columns;
132}
133
134/*
135 * Return the offset of a window considering the width of tabpanel.
136 */
137 int
138tabpanel_leftcol(win_T *wp)
139{
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200140 if (cmdline_pum_active() || (wp != NULL && WIN_IS_POPUP(wp)))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200141 return 0;
142 else
143 return tpl_align == ALIGN_RIGHT ? 0 : tabpanel_width();
144}
145
146/*
147 * draw the tabpanel.
148 */
149 void
150draw_tabpanel(void)
151{
152 int saved_KeyTyped = KeyTyped;
153 int saved_got_int = got_int;
154 int maxwidth = tabpanel_width();
155 int vs_attr = HL_ATTR(HLF_C);
156 int curtab_row = 0;
157#ifndef MSWIN
158 int row = 0;
159 int off = 0;
160#endif
161int vsrow = 0;
162 int is_right = tpl_align == ALIGN_RIGHT;
163
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200164 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200165 return;
166
167#ifndef MSWIN
168 // We need this section only for the Vim running on WSL.
169 for (row = 0; row < cmdline_row; row++)
170 {
171 if (is_right)
172 off = LineOffset[row] + Columns - maxwidth;
173 else
174 off = LineOffset[row];
175
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200176 vim_memset(ScreenLines + off, ' ', (size_t)maxwidth * sizeof(schar_T));
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200177 if (enc_utf8)
178 vim_memset(ScreenLinesUC + off, -1,
179 (size_t)maxwidth * sizeof(u8char_T));
180 }
181#endif
182
183 // Reset got_int to avoid build_stl_str_hl() isn't evaluted.
184 got_int = FALSE;
185
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200186 if (tpl_is_vert)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200187 {
188 if (is_right)
189 {
190 // draw main contents in tabpanel
191 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, VERT_LEN,
192 maxwidth - VERT_LEN, &curtab_row, NULL);
193 do_by_tplmode(TPLMODE_REDRAW, VERT_LEN, maxwidth, &curtab_row,
194 NULL);
195 // clear for multi-byte vert separater
196 screen_fill(0, cmdline_row, COLUMNS_WITHOUT_TPL(),
197 COLUMNS_WITHOUT_TPL() + VERT_LEN,
198 TPL_FILLCHAR, TPL_FILLCHAR, vs_attr);
199 // draw vert separater in tabpanel
200 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
201 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
202 COLUMNS_WITHOUT_TPL(), vs_attr);
203 }
204 else
205 {
206 // draw main contents in tabpanel
207 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth - VERT_LEN,
208 &curtab_row, NULL);
209 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth - VERT_LEN,
210 &curtab_row, NULL);
211 // clear for multi-byte vert separater
212 screen_fill(0, cmdline_row, maxwidth - VERT_LEN,
213 maxwidth, TPL_FILLCHAR, TPL_FILLCHAR, vs_attr);
214 // draw vert separater in tabpanel
215 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
216 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
217 maxwidth - VERT_LEN, vs_attr);
218 }
219 }
220 else
221 {
222 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
223 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth, &curtab_row, NULL);
224 }
225
226 got_int |= saved_got_int;
227
228 // A user function may reset KeyTyped, restore it.
229 KeyTyped = saved_KeyTyped;
230
231 redraw_tabpanel = FALSE;
232}
233
234/*
235 * Return tabpagenr when clicking and dragging in tabpanel.
236 */
237 int
238get_tabpagenr_on_tabpanel(void)
239{
240 int maxwidth = tabpanel_width();
241 int curtab_row = 0;
242 int tabpagenr = 0;
243
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200244 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200245 return -1;
246
247 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
248 do_by_tplmode(TPLMODE_GET_TABPAGENR, 0, maxwidth, &curtab_row,
249 &tabpagenr);
250
251 return tabpagenr;
252}
253
254/*
255 * Fill tailing area between {start_row} and {end_row - 1}.
256 */
257 static void
258screen_fill_tailing_area(
259 int tplmode,
260 int row_start,
261 int row_end,
262 int col_start,
263 int col_end,
264 int attr)
265{
266 int is_right = tpl_align == ALIGN_RIGHT;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200267 if (tplmode == TPLMODE_REDRAW)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200268 screen_fill(row_start, row_end,
269 (is_right ? COLUMNS_WITHOUT_TPL() : 0) + col_start,
270 (is_right ? COLUMNS_WITHOUT_TPL() : 0) + col_end,
271 TPL_FILLCHAR, TPL_FILLCHAR, attr);
272}
273
274/*
275 * screen_puts_len() for tabpanel.
276 */
277 static void
278screen_puts_len_for_tabpanel(
279 int tplmode,
280 char_u *p,
281 int len,
282 int attr,
283 tabpanel_T *pargs)
284{
285 int j, k;
286 int chlen;
287 int chcells;
288 char_u buf[IOSIZE];
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200289 char_u *temp;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200290
291 for (j = 0; j < len;)
292 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200293 if (tplmode != TPLMODE_GET_CURTAB_ROW
294 && pargs->maxrow <= *pargs->prow - pargs->offsetrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200295 break;
296
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200297 if (p[j] == '\n' || p[j] == '\r')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200298 {
299 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200300 if (*pargs->prow - pargs->offsetrow >= 0
301 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200302 screen_fill_tailing_area(tplmode,
303 *pargs->prow - pargs->offsetrow,
304 *pargs->prow - pargs->offsetrow + 1,
305 *pargs->pcol, pargs->col_end, attr);
306 (*pargs->prow)++;
307 *pargs->pcol = pargs->col_start;
308 j++;
309 }
310 else
311 {
312 if (has_mbyte)
313 chlen = (*mb_ptr2len)(p + j);
314 else
315 chlen = (int)STRLEN(p + j);
316
317 for (k = 0; k < chlen; k++)
318 buf[k] = p[j + k];
319 buf[chlen] = NUL;
320 j += chlen;
321
322 // Make all characters printable.
323 temp = transstr(buf);
324 if (temp != NULL)
325 {
326 vim_strncpy(buf, temp, sizeof(buf) - 1);
327 vim_free(temp);
328 }
329
330 if (has_mbyte)
331 chcells = (*mb_ptr2cells)(buf);
332 else
333 chcells = 1;
334
335 if (pargs->col_end < (*pargs->pcol) + chcells)
336 {
337 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200338 if (*pargs->prow - pargs->offsetrow >= 0
339 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200340 screen_fill_tailing_area(tplmode,
341 *pargs->prow - pargs->offsetrow,
342 *pargs->prow - pargs->offsetrow + 1,
343 *pargs->pcol, pargs->col_end, attr);
344 *pargs->pcol = pargs->col_end;
345
346 if (pargs->col_end < chcells)
347 break;
348 }
349
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200350 if (*pargs->pcol + chcells <= pargs->col_end)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200351 {
352 int off = (tpl_align == ALIGN_RIGHT)
353 ? COLUMNS_WITHOUT_TPL()
354 : 0;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200355 if (TPLMODE_REDRAW == tplmode
356 && (*pargs->prow - pargs->offsetrow >= 0
357 && *pargs->prow - pargs->offsetrow < pargs->maxrow))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200358 screen_puts(buf, *pargs->prow - pargs->offsetrow,
359 *pargs->pcol + off, attr);
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200360 *pargs->pcol += chcells;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200361 }
362 }
363 }
364}
365
366/*
367 * default tabpanel drawing behavior if 'tabpanel' option is empty.
368 */
369 static void
370draw_tabpanel_default(int tplmode, tabpanel_T *pargs)
371{
372 int modified;
373 int wincount;
374 int len = 0;
375 char_u buf[2] = { NUL, NUL };
376
377 modified = FALSE;
378 for (wincount = 0; pargs->wp != NULL;
379 pargs->wp = pargs->wp->w_next, ++wincount)
380 if (bufIsChanged(pargs->wp->w_buffer))
381 modified = TRUE;
382
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200383 if (modified || wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200384 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200385 if (wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200386 {
387 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
388 len = (int)STRLEN(NameBuff);
389 screen_puts_len_for_tabpanel(tplmode, NameBuff, len,
390#if defined(FEAT_SYN_HL)
391 hl_combine_attr(pargs->attr, HL_ATTR(HLF_T)),
392#else
393 pargs->attr,
394#endif
395 pargs);
396 }
397 if (modified)
398 {
399 buf[0] = '+';
400 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
401 }
402
403 buf[0] = TPL_FILLCHAR;
404 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
405 }
406
407 get_trans_bufname(pargs->cwp->w_buffer);
408 shorten_dir(NameBuff);
409 len = (int)STRLEN(NameBuff);
410 screen_puts_len_for_tabpanel(tplmode, NameBuff, len, pargs->attr, pargs);
411
412 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200413 if (*pargs->prow - pargs->offsetrow >= 0
414 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200415 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
416 *pargs->prow - pargs->offsetrow + 1,
417 *pargs->pcol, pargs->col_end, pargs->attr);
418 *pargs->pcol = pargs->col_end;
419}
420
421/*
422 * default tabpanel drawing behavior if 'tabpanel' option is NOT empty.
423 */
424 static void
425draw_tabpanel_userdefined(int tplmode, tabpanel_T *pargs)
426{
427 char_u *p;
428 int p_crb_save;
429 char_u buf[IOSIZE];
430 stl_hlrec_T *hltab;
431 stl_hlrec_T *tabtab;
432 int curattr;
433 int n;
434
435 // Temporarily reset 'cursorbind', we don't want a side effect from moving
436 // the cursor away and back.
437 p_crb_save = pargs->cwp->w_p_crb;
438 pargs->cwp->w_p_crb = FALSE;
439
440 // Make a copy, because the statusline may include a function call that
441 // might change the option value and free the memory.
442 p = vim_strsave(pargs->user_defined);
443
444 build_stl_str_hl(pargs->cwp, buf, sizeof(buf),
445 p, opt_name, opt_scope,
446 TPL_FILLCHAR, pargs->col_end - pargs->col_start, &hltab, &tabtab);
447
448 vim_free(p);
449 pargs->cwp->w_p_crb = p_crb_save;
450
451 curattr = pargs->attr;
452 p = buf;
453 for (n = 0; hltab[n].start != NULL; n++)
454 {
455 screen_puts_len_for_tabpanel(tplmode, p, (int)(hltab[n].start - p),
456 curattr, pargs);
457 p = hltab[n].start;
458 if (hltab[n].userhl == 0)
459 curattr = pargs->attr;
460 else if (hltab[n].userhl < 0)
461 curattr = syn_id2attr(-hltab[n].userhl);
462#ifdef FEAT_TERMINAL
463 else if (pargs->wp != NULL && pargs->wp != curwin
464 && bt_terminal(pargs->wp->w_buffer)
465 && pargs->wp->w_status_height != 0)
466 curattr = highlight_stltermnc[hltab[n].userhl - 1];
467 else if (pargs->wp != NULL && bt_terminal(pargs->wp->w_buffer)
468 && pargs->wp->w_status_height != 0)
469 curattr = highlight_stlterm[hltab[n].userhl - 1];
470#endif
471 else if (pargs->wp != NULL && pargs->wp != curwin
472 && pargs->wp->w_status_height != 0)
473 curattr = highlight_stlnc[hltab[n].userhl - 1];
474 else
475 curattr = highlight_user[hltab[n].userhl - 1];
476 }
477 screen_puts_len_for_tabpanel(tplmode, p, (int)STRLEN(p), curattr, pargs);
478
479 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200480 if (*pargs->prow - pargs->offsetrow >= 0
481 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200482 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
483 *pargs->prow - pargs->offsetrow + 1, *pargs->pcol,
484 pargs->col_end, curattr);
485 *pargs->pcol = pargs->col_end;
486}
487
488 static char_u *
489starts_with_percent_and_bang(tabpanel_T *pargs)
490{
491 int len = 0;
492 char_u *usefmt = p_tpl;
493
494 if (usefmt == NULL)
495 return NULL;
496
497 len = (int)STRLEN(usefmt);
498
499 if (len == 0)
500 return NULL;
501
502#ifdef FEAT_EVAL
503 // if "fmt" was set insecurely it needs to be evaluated in the sandbox
504 int use_sandbox = was_set_insecurely(opt_name, opt_scope);
505
506 // When the format starts with "%!" then evaluate it as an expression and
507 // use the result as the actual format string.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200508 if (len > 1 && usefmt[0] == '%' && usefmt[1] == '!')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200509 {
510 typval_T tv;
511 char_u *p = NULL;
512
513 tv.v_type = VAR_NUMBER;
514 tv.vval.v_number = pargs->cwp->w_id;
515 set_var((char_u *)"g:tabpanel_winid", &tv, FALSE);
516
517 p = eval_to_string_safe(usefmt + 2, use_sandbox, FALSE, FALSE);
518 if (p != NULL)
519 usefmt = p;
520
521 do_unlet((char_u *)"g:tabpanel_winid", TRUE);
522 }
523#endif
524
525 return usefmt;
526}
527
528/*
529 * do something by tplmode for drawing tabpanel.
530 */
531 static void
532do_by_tplmode(
533 int tplmode,
534 int col_start,
535 int col_end,
536 int *pcurtab_row,
537 int *ptabpagenr)
538{
539 int attr_tplf = HL_ATTR(HLF_TPLF);
540 int attr_tpls = HL_ATTR(HLF_TPLS);
541 int attr_tpl = HL_ATTR(HLF_TPL);
542 int col = col_start;
543 int row = 0;
544 tabpage_T *tp = NULL;
545 typval_T v;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200546 tabpanel_T args;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200547
548 args.maxrow = cmdline_row;
549 args.offsetrow = 0;
550 args.col_start = col_start;
551 args.col_end = col_end;
552
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200553 if (tplmode != TPLMODE_GET_CURTAB_ROW && args.maxrow > 0)
554 while (args.offsetrow + args.maxrow <= *pcurtab_row)
555 args.offsetrow += args.maxrow;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200556
557 tp = first_tabpage;
558
559 for (row = 0; tp != NULL; row++)
560 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200561 if (tplmode != TPLMODE_GET_CURTAB_ROW
562 && args.maxrow <= row - args.offsetrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200563 break;
564
565 col = col_start;
566
567 v.v_type = VAR_NUMBER;
568 v.vval.v_number = tabpage_index(tp);
569 set_var((char_u *)"g:actual_curtabpage", &v, TRUE);
570
571 if (tp->tp_topframe == topframe)
572 {
573 args.attr = attr_tpls;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200574 if (tplmode == TPLMODE_GET_CURTAB_ROW)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200575 {
576 *pcurtab_row = row;
577 break;
578 }
579 }
580 else
581 args.attr = attr_tpl;
582
583 if (tp == curtab)
584 {
585 args.cwp = curwin;
586 args.wp = firstwin;
587 }
588 else
589 {
590 args.cwp = tp->tp_curwin;
591 args.wp = tp->tp_firstwin;
592 }
593
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200594 char_u *usefmt = starts_with_percent_and_bang(&args);
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200595 if (usefmt != NULL)
596 {
597 char_u buf[IOSIZE];
598 char_u *p = usefmt;
599 size_t i = 0;
600
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200601 while (p[i] != NUL)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200602 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200603 while (p[i] == '\n' || p[i] == '\r')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200604 {
605 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200606 if (row - args.offsetrow >= 0
607 && row - args.offsetrow < args.maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200608 screen_fill_tailing_area(tplmode,
609 row - args.offsetrow,
610 row - args.offsetrow + 1,
611 col, args.col_end, args.attr);
612 row++;
613 col = col_start;
614 p++;
615 }
616
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200617 while (p[i] != '\n' && p[i] != '\r' && (p[i] != NUL))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200618 {
619 if (i + 1 >= sizeof(buf))
620 break;
621 buf[i] = p[i];
622 i++;
623 }
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200624 buf[i] = NUL;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200625
626 args.user_defined = buf;
627 args.prow = &row;
628 args.pcol = &col;
629 draw_tabpanel_userdefined(tplmode, &args);
630
631 p += i;
632 i = 0;
633 }
634 if (usefmt != p_tpl)
635 VIM_CLEAR(usefmt);
636 }
637 else
638 {
639 args.user_defined = NULL;
640 args.prow = &row;
641 args.pcol = &col;
642 draw_tabpanel_default(tplmode, &args);
643 }
644
645 do_unlet((char_u *)"g:actual_curtabpage", TRUE);
646
647 tp = tp->tp_next;
648
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200649 if ((tplmode == TPLMODE_GET_TABPAGENR)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200650 && (mouse_row <= (row - args.offsetrow)))
651 {
652 *ptabpagenr = v.vval.v_number;
653 break;
654 }
655 }
656
657 // fill the area of TabPanelFill.
658 screen_fill_tailing_area(tplmode, row - args.offsetrow, args.maxrow,
659 args.col_start, args.col_end, attr_tplf);
660}
661
662#endif // FEAT_TABPANEL