blob: d0f2d151a7fe84e8b3f09e85f3ec96098374fa41 [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 {
Hirohito Higashi598bbb12025-05-22 22:41:05 +020067 if (STRNCMP(p, "align:", 6) == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020068 {
Hirohito Higashi598bbb12025-05-22 22:41:05 +020069 p += 6;
70 if (STRNCMP(p, "left", 4) == 0)
71 {
72 p += 4;
73 new_align = ALIGN_LEFT;
74 }
75 else if (STRNCMP(p, "right", 5) == 0)
76 {
77 p += 5;
78 new_align = ALIGN_RIGHT;
79 }
80 else
81 return FAIL;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020082 }
83 else if (STRNCMP(p, "columns:", 8) == 0 && VIM_ISDIGIT(p[8]))
84 {
85 p += 8;
86 new_columns = getdigits(&p);
87 }
88 else if (STRNCMP(p, "vert", 4) == 0)
89 {
90 p += 4;
Hirohito Higashic659e4a2025-05-16 19:34:34 +020091 new_is_vert = TRUE;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +020092 }
93
94 if (*p != ',' && *p != NUL)
95 return FAIL;
96 if (*p == ',')
97 ++p;
98 }
99
Naruhiko Nishino2a1e2532025-05-17 16:19:24 +0200100 // Whether all the windows are automatically made the same size
101 // when tabpanel size is changed.
102 do_equal = p_ea && tpl_columns != new_columns;
103
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200104 tpl_align = new_align;
105 tpl_columns = new_columns;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200106 tpl_is_vert = new_is_vert;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200107
Naruhiko Nishino2a1e2532025-05-17 16:19:24 +0200108 shell_new_columns();
Naruhiko Nishino2a1e2532025-05-17 16:19:24 +0200109
110 if (do_equal)
111 win_equal(curwin, FALSE, 0);
112
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200113 return OK;
114}
115
116/*
117 * Return the width of tabpanel.
118 */
119 int
120tabpanel_width(void)
121{
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200122 switch (p_stpl)
123 {
124 case 0:
125 return 0;
126 case 1:
127 if (first_tabpage->tp_next == NULL)
128 return 0;
129 }
130 if (Columns < tpl_columns)
131 return 0;
132 else
133 return tpl_columns;
134}
135
136/*
137 * Return the offset of a window considering the width of tabpanel.
138 */
139 int
140tabpanel_leftcol(win_T *wp)
141{
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200142 if (cmdline_pum_active() || (wp != NULL && WIN_IS_POPUP(wp)))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200143 return 0;
144 else
145 return tpl_align == ALIGN_RIGHT ? 0 : tabpanel_width();
146}
147
148/*
149 * draw the tabpanel.
150 */
151 void
152draw_tabpanel(void)
153{
154 int saved_KeyTyped = KeyTyped;
155 int saved_got_int = got_int;
156 int maxwidth = tabpanel_width();
157 int vs_attr = HL_ATTR(HLF_C);
158 int curtab_row = 0;
159#ifndef MSWIN
160 int row = 0;
161 int off = 0;
162#endif
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200163 int vsrow = 0;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200164 int is_right = tpl_align == ALIGN_RIGHT;
165
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200166 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200167 return;
168
169#ifndef MSWIN
170 // We need this section only for the Vim running on WSL.
171 for (row = 0; row < cmdline_row; row++)
172 {
173 if (is_right)
174 off = LineOffset[row] + Columns - maxwidth;
175 else
176 off = LineOffset[row];
177
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200178 vim_memset(ScreenLines + off, ' ', (size_t)maxwidth * sizeof(schar_T));
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200179 if (enc_utf8)
180 vim_memset(ScreenLinesUC + off, -1,
181 (size_t)maxwidth * sizeof(u8char_T));
182 }
183#endif
184
185 // Reset got_int to avoid build_stl_str_hl() isn't evaluted.
186 got_int = FALSE;
187
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200188 if (tpl_is_vert)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200189 {
190 if (is_right)
191 {
192 // draw main contents in tabpanel
193 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, VERT_LEN,
194 maxwidth - VERT_LEN, &curtab_row, NULL);
195 do_by_tplmode(TPLMODE_REDRAW, VERT_LEN, maxwidth, &curtab_row,
196 NULL);
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200197 // draw vert separator in tabpanel
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200198 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
199 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200200 topframe->fr_width, vs_attr);
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200201 }
202 else
203 {
204 // draw main contents in tabpanel
205 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth - VERT_LEN,
206 &curtab_row, NULL);
207 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth - VERT_LEN,
208 &curtab_row, NULL);
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200209 // draw vert separator in tabpanel
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200210 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
211 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
212 maxwidth - VERT_LEN, vs_attr);
213 }
214 }
215 else
216 {
217 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
218 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth, &curtab_row, NULL);
219 }
220
221 got_int |= saved_got_int;
222
223 // A user function may reset KeyTyped, restore it.
224 KeyTyped = saved_KeyTyped;
225
226 redraw_tabpanel = FALSE;
227}
228
229/*
230 * Return tabpagenr when clicking and dragging in tabpanel.
231 */
232 int
233get_tabpagenr_on_tabpanel(void)
234{
235 int maxwidth = tabpanel_width();
236 int curtab_row = 0;
237 int tabpagenr = 0;
238
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200239 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200240 return -1;
241
242 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
243 do_by_tplmode(TPLMODE_GET_TABPAGENR, 0, maxwidth, &curtab_row,
244 &tabpagenr);
245
246 return tabpagenr;
247}
248
249/*
250 * Fill tailing area between {start_row} and {end_row - 1}.
251 */
252 static void
253screen_fill_tailing_area(
254 int tplmode,
255 int row_start,
256 int row_end,
257 int col_start,
258 int col_end,
259 int attr)
260{
261 int is_right = tpl_align == ALIGN_RIGHT;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200262 if (tplmode == TPLMODE_REDRAW)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200263 screen_fill(row_start, row_end,
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200264 (is_right ? topframe->fr_width : 0) + col_start,
265 (is_right ? topframe->fr_width : 0) + col_end,
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200266 TPL_FILLCHAR, TPL_FILLCHAR, attr);
267}
268
269/*
270 * screen_puts_len() for tabpanel.
271 */
272 static void
273screen_puts_len_for_tabpanel(
274 int tplmode,
275 char_u *p,
276 int len,
277 int attr,
278 tabpanel_T *pargs)
279{
280 int j, k;
281 int chlen;
282 int chcells;
283 char_u buf[IOSIZE];
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200284 char_u *temp;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200285
286 for (j = 0; j < len;)
287 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200288 if (tplmode != TPLMODE_GET_CURTAB_ROW
289 && pargs->maxrow <= *pargs->prow - pargs->offsetrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200290 break;
291
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200292 if (p[j] == '\n' || p[j] == '\r')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200293 {
294 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200295 if (*pargs->prow - pargs->offsetrow >= 0
296 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200297 screen_fill_tailing_area(tplmode,
298 *pargs->prow - pargs->offsetrow,
299 *pargs->prow - pargs->offsetrow + 1,
300 *pargs->pcol, pargs->col_end, attr);
301 (*pargs->prow)++;
302 *pargs->pcol = pargs->col_start;
303 j++;
304 }
305 else
306 {
307 if (has_mbyte)
308 chlen = (*mb_ptr2len)(p + j);
309 else
310 chlen = (int)STRLEN(p + j);
311
312 for (k = 0; k < chlen; k++)
313 buf[k] = p[j + k];
314 buf[chlen] = NUL;
315 j += chlen;
316
317 // Make all characters printable.
318 temp = transstr(buf);
319 if (temp != NULL)
320 {
321 vim_strncpy(buf, temp, sizeof(buf) - 1);
322 vim_free(temp);
323 }
324
325 if (has_mbyte)
326 chcells = (*mb_ptr2cells)(buf);
327 else
328 chcells = 1;
329
330 if (pargs->col_end < (*pargs->pcol) + chcells)
331 {
332 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200333 if (*pargs->prow - pargs->offsetrow >= 0
334 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200335 screen_fill_tailing_area(tplmode,
336 *pargs->prow - pargs->offsetrow,
337 *pargs->prow - pargs->offsetrow + 1,
338 *pargs->pcol, pargs->col_end, attr);
339 *pargs->pcol = pargs->col_end;
340
341 if (pargs->col_end < chcells)
342 break;
343 }
344
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200345 if (*pargs->pcol + chcells <= pargs->col_end)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200346 {
347 int off = (tpl_align == ALIGN_RIGHT)
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200348 ? topframe->fr_width
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200349 : 0;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200350 if (TPLMODE_REDRAW == tplmode
351 && (*pargs->prow - pargs->offsetrow >= 0
352 && *pargs->prow - pargs->offsetrow < pargs->maxrow))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200353 screen_puts(buf, *pargs->prow - pargs->offsetrow,
354 *pargs->pcol + off, attr);
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200355 *pargs->pcol += chcells;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200356 }
357 }
358 }
359}
360
361/*
362 * default tabpanel drawing behavior if 'tabpanel' option is empty.
363 */
364 static void
365draw_tabpanel_default(int tplmode, tabpanel_T *pargs)
366{
367 int modified;
368 int wincount;
369 int len = 0;
370 char_u buf[2] = { NUL, NUL };
371
372 modified = FALSE;
373 for (wincount = 0; pargs->wp != NULL;
374 pargs->wp = pargs->wp->w_next, ++wincount)
375 if (bufIsChanged(pargs->wp->w_buffer))
376 modified = TRUE;
377
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200378 if (modified || wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200379 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200380 if (wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200381 {
382 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
383 len = (int)STRLEN(NameBuff);
384 screen_puts_len_for_tabpanel(tplmode, NameBuff, len,
385#if defined(FEAT_SYN_HL)
386 hl_combine_attr(pargs->attr, HL_ATTR(HLF_T)),
387#else
388 pargs->attr,
389#endif
390 pargs);
391 }
392 if (modified)
393 {
394 buf[0] = '+';
395 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
396 }
397
398 buf[0] = TPL_FILLCHAR;
399 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
400 }
401
402 get_trans_bufname(pargs->cwp->w_buffer);
403 shorten_dir(NameBuff);
404 len = (int)STRLEN(NameBuff);
405 screen_puts_len_for_tabpanel(tplmode, NameBuff, len, pargs->attr, pargs);
406
407 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200408 if (*pargs->prow - pargs->offsetrow >= 0
409 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200410 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
411 *pargs->prow - pargs->offsetrow + 1,
412 *pargs->pcol, pargs->col_end, pargs->attr);
413 *pargs->pcol = pargs->col_end;
414}
415
416/*
417 * default tabpanel drawing behavior if 'tabpanel' option is NOT empty.
418 */
419 static void
420draw_tabpanel_userdefined(int tplmode, tabpanel_T *pargs)
421{
422 char_u *p;
423 int p_crb_save;
424 char_u buf[IOSIZE];
425 stl_hlrec_T *hltab;
426 stl_hlrec_T *tabtab;
427 int curattr;
428 int n;
429
430 // Temporarily reset 'cursorbind', we don't want a side effect from moving
431 // the cursor away and back.
432 p_crb_save = pargs->cwp->w_p_crb;
433 pargs->cwp->w_p_crb = FALSE;
434
435 // Make a copy, because the statusline may include a function call that
436 // might change the option value and free the memory.
437 p = vim_strsave(pargs->user_defined);
438
439 build_stl_str_hl(pargs->cwp, buf, sizeof(buf),
440 p, opt_name, opt_scope,
441 TPL_FILLCHAR, pargs->col_end - pargs->col_start, &hltab, &tabtab);
442
443 vim_free(p);
444 pargs->cwp->w_p_crb = p_crb_save;
445
446 curattr = pargs->attr;
447 p = buf;
448 for (n = 0; hltab[n].start != NULL; n++)
449 {
450 screen_puts_len_for_tabpanel(tplmode, p, (int)(hltab[n].start - p),
451 curattr, pargs);
452 p = hltab[n].start;
453 if (hltab[n].userhl == 0)
454 curattr = pargs->attr;
455 else if (hltab[n].userhl < 0)
456 curattr = syn_id2attr(-hltab[n].userhl);
457#ifdef FEAT_TERMINAL
458 else if (pargs->wp != NULL && pargs->wp != curwin
459 && bt_terminal(pargs->wp->w_buffer)
460 && pargs->wp->w_status_height != 0)
461 curattr = highlight_stltermnc[hltab[n].userhl - 1];
462 else if (pargs->wp != NULL && bt_terminal(pargs->wp->w_buffer)
463 && pargs->wp->w_status_height != 0)
464 curattr = highlight_stlterm[hltab[n].userhl - 1];
465#endif
466 else if (pargs->wp != NULL && pargs->wp != curwin
467 && pargs->wp->w_status_height != 0)
468 curattr = highlight_stlnc[hltab[n].userhl - 1];
469 else
470 curattr = highlight_user[hltab[n].userhl - 1];
471 }
472 screen_puts_len_for_tabpanel(tplmode, p, (int)STRLEN(p), curattr, pargs);
473
474 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200475 if (*pargs->prow - pargs->offsetrow >= 0
476 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200477 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
478 *pargs->prow - pargs->offsetrow + 1, *pargs->pcol,
479 pargs->col_end, curattr);
480 *pargs->pcol = pargs->col_end;
481}
482
483 static char_u *
484starts_with_percent_and_bang(tabpanel_T *pargs)
485{
486 int len = 0;
487 char_u *usefmt = p_tpl;
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200488 int did_emsg_before = did_emsg;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200489
490 if (usefmt == NULL)
491 return NULL;
492
493 len = (int)STRLEN(usefmt);
494
495 if (len == 0)
496 return NULL;
497
498#ifdef FEAT_EVAL
499 // if "fmt" was set insecurely it needs to be evaluated in the sandbox
500 int use_sandbox = was_set_insecurely(opt_name, opt_scope);
501
502 // When the format starts with "%!" then evaluate it as an expression and
503 // use the result as the actual format string.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200504 if (len > 1 && usefmt[0] == '%' && usefmt[1] == '!')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200505 {
506 typval_T tv;
507 char_u *p = NULL;
508
509 tv.v_type = VAR_NUMBER;
510 tv.vval.v_number = pargs->cwp->w_id;
511 set_var((char_u *)"g:tabpanel_winid", &tv, FALSE);
512
513 p = eval_to_string_safe(usefmt + 2, use_sandbox, FALSE, FALSE);
514 if (p != NULL)
515 usefmt = p;
516
517 do_unlet((char_u *)"g:tabpanel_winid", TRUE);
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200518
519 if (did_emsg > did_emsg_before)
520 {
521 usefmt = NULL;
Christian Brabandtac83b3c2025-05-27 20:49:34 +0200522 set_string_option_direct(opt_name, -1, (char_u *)"",
523 OPT_FREE | opt_scope, SID_ERROR);
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200524 }
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200525 }
526#endif
527
528 return usefmt;
529}
530
531/*
532 * do something by tplmode for drawing tabpanel.
533 */
534 static void
535do_by_tplmode(
536 int tplmode,
537 int col_start,
538 int col_end,
539 int *pcurtab_row,
540 int *ptabpagenr)
541{
542 int attr_tplf = HL_ATTR(HLF_TPLF);
543 int attr_tpls = HL_ATTR(HLF_TPLS);
544 int attr_tpl = HL_ATTR(HLF_TPL);
545 int col = col_start;
546 int row = 0;
547 tabpage_T *tp = NULL;
548 typval_T v;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200549 tabpanel_T args;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200550
551 args.maxrow = cmdline_row;
552 args.offsetrow = 0;
553 args.col_start = col_start;
554 args.col_end = col_end;
555
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200556 if (tplmode != TPLMODE_GET_CURTAB_ROW && args.maxrow > 0)
557 while (args.offsetrow + args.maxrow <= *pcurtab_row)
558 args.offsetrow += args.maxrow;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200559
560 tp = first_tabpage;
561
562 for (row = 0; tp != NULL; row++)
563 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200564 if (tplmode != TPLMODE_GET_CURTAB_ROW
565 && args.maxrow <= row - args.offsetrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200566 break;
567
568 col = col_start;
569
570 v.v_type = VAR_NUMBER;
571 v.vval.v_number = tabpage_index(tp);
572 set_var((char_u *)"g:actual_curtabpage", &v, TRUE);
573
574 if (tp->tp_topframe == topframe)
575 {
576 args.attr = attr_tpls;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200577 if (tplmode == TPLMODE_GET_CURTAB_ROW)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200578 {
579 *pcurtab_row = row;
580 break;
581 }
582 }
583 else
584 args.attr = attr_tpl;
585
586 if (tp == curtab)
587 {
588 args.cwp = curwin;
589 args.wp = firstwin;
590 }
591 else
592 {
593 args.cwp = tp->tp_curwin;
594 args.wp = tp->tp_firstwin;
595 }
596
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200597 char_u *usefmt = starts_with_percent_and_bang(&args);
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200598 if (usefmt != NULL)
599 {
600 char_u buf[IOSIZE];
601 char_u *p = usefmt;
602 size_t i = 0;
603
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200604 while (p[i] != NUL)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200605 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200606 while (p[i] == '\n' || p[i] == '\r')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200607 {
608 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200609 if (row - args.offsetrow >= 0
610 && row - args.offsetrow < args.maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200611 screen_fill_tailing_area(tplmode,
612 row - args.offsetrow,
613 row - args.offsetrow + 1,
614 col, args.col_end, args.attr);
615 row++;
616 col = col_start;
617 p++;
618 }
619
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200620 while (p[i] != '\n' && p[i] != '\r' && p[i] != NUL)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200621 {
622 if (i + 1 >= sizeof(buf))
623 break;
624 buf[i] = p[i];
625 i++;
626 }
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200627 buf[i] = NUL;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200628
629 args.user_defined = buf;
630 args.prow = &row;
631 args.pcol = &col;
632 draw_tabpanel_userdefined(tplmode, &args);
Christian Brabandtac83b3c2025-05-27 20:49:34 +0200633 // p_tpl could have been freed in build_stl_str_hl()
634 if (p_tpl == NULL || *p_tpl == NUL)
635 {
636 usefmt = NULL;
637 break;
638 }
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200639
640 p += i;
641 i = 0;
642 }
643 if (usefmt != p_tpl)
644 VIM_CLEAR(usefmt);
645 }
646 else
647 {
648 args.user_defined = NULL;
649 args.prow = &row;
650 args.pcol = &col;
651 draw_tabpanel_default(tplmode, &args);
652 }
653
654 do_unlet((char_u *)"g:actual_curtabpage", TRUE);
655
656 tp = tp->tp_next;
657
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200658 if ((tplmode == TPLMODE_GET_TABPAGENR)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200659 && (mouse_row <= (row - args.offsetrow)))
660 {
661 *ptabpagenr = v.vval.v_number;
662 break;
663 }
664 }
665
666 // fill the area of TabPanelFill.
667 screen_fill_tailing_area(tplmode, row - args.offsetrow, args.maxrow,
668 args.col_start, args.col_end, attr_tplf);
669}
670
671#endif // FEAT_TABPANEL