blob: 3845faa8fc468fceb98805edd78ec9d1a11ba520 [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();
109 redraw_tabpanel = TRUE;
110
111 if (do_equal)
112 win_equal(curwin, FALSE, 0);
113
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200114 return OK;
115}
116
117/*
118 * Return the width of tabpanel.
119 */
120 int
121tabpanel_width(void)
122{
123 if (msg_scrolled != 0)
124 return 0;
125
126 switch (p_stpl)
127 {
128 case 0:
129 return 0;
130 case 1:
131 if (first_tabpage->tp_next == NULL)
132 return 0;
133 }
134 if (Columns < tpl_columns)
135 return 0;
136 else
137 return tpl_columns;
138}
139
140/*
141 * Return the offset of a window considering the width of tabpanel.
142 */
143 int
144tabpanel_leftcol(win_T *wp)
145{
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200146 if (cmdline_pum_active() || (wp != NULL && WIN_IS_POPUP(wp)))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200147 return 0;
148 else
149 return tpl_align == ALIGN_RIGHT ? 0 : tabpanel_width();
150}
151
152/*
153 * draw the tabpanel.
154 */
155 void
156draw_tabpanel(void)
157{
158 int saved_KeyTyped = KeyTyped;
159 int saved_got_int = got_int;
160 int maxwidth = tabpanel_width();
161 int vs_attr = HL_ATTR(HLF_C);
162 int curtab_row = 0;
163#ifndef MSWIN
164 int row = 0;
165 int off = 0;
166#endif
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200167 int vsrow = 0;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200168 int is_right = tpl_align == ALIGN_RIGHT;
169
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200170 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200171 return;
172
173#ifndef MSWIN
174 // We need this section only for the Vim running on WSL.
175 for (row = 0; row < cmdline_row; row++)
176 {
177 if (is_right)
178 off = LineOffset[row] + Columns - maxwidth;
179 else
180 off = LineOffset[row];
181
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200182 vim_memset(ScreenLines + off, ' ', (size_t)maxwidth * sizeof(schar_T));
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200183 if (enc_utf8)
184 vim_memset(ScreenLinesUC + off, -1,
185 (size_t)maxwidth * sizeof(u8char_T));
186 }
187#endif
188
189 // Reset got_int to avoid build_stl_str_hl() isn't evaluted.
190 got_int = FALSE;
191
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200192 if (tpl_is_vert)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200193 {
194 if (is_right)
195 {
196 // draw main contents in tabpanel
197 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, VERT_LEN,
198 maxwidth - VERT_LEN, &curtab_row, NULL);
199 do_by_tplmode(TPLMODE_REDRAW, VERT_LEN, maxwidth, &curtab_row,
200 NULL);
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200201 // draw vert separator in tabpanel
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200202 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
203 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200204 topframe->fr_width, vs_attr);
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200205 }
206 else
207 {
208 // draw main contents in tabpanel
209 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth - VERT_LEN,
210 &curtab_row, NULL);
211 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth - VERT_LEN,
212 &curtab_row, NULL);
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200213 // draw vert separator in tabpanel
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200214 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
215 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
216 maxwidth - VERT_LEN, vs_attr);
217 }
218 }
219 else
220 {
221 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
222 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth, &curtab_row, NULL);
223 }
224
225 got_int |= saved_got_int;
226
227 // A user function may reset KeyTyped, restore it.
228 KeyTyped = saved_KeyTyped;
229
230 redraw_tabpanel = FALSE;
231}
232
233/*
234 * Return tabpagenr when clicking and dragging in tabpanel.
235 */
236 int
237get_tabpagenr_on_tabpanel(void)
238{
239 int maxwidth = tabpanel_width();
240 int curtab_row = 0;
241 int tabpagenr = 0;
242
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200243 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200244 return -1;
245
246 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
247 do_by_tplmode(TPLMODE_GET_TABPAGENR, 0, maxwidth, &curtab_row,
248 &tabpagenr);
249
250 return tabpagenr;
251}
252
253/*
254 * Fill tailing area between {start_row} and {end_row - 1}.
255 */
256 static void
257screen_fill_tailing_area(
258 int tplmode,
259 int row_start,
260 int row_end,
261 int col_start,
262 int col_end,
263 int attr)
264{
265 int is_right = tpl_align == ALIGN_RIGHT;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200266 if (tplmode == TPLMODE_REDRAW)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200267 screen_fill(row_start, row_end,
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200268 (is_right ? topframe->fr_width : 0) + col_start,
269 (is_right ? topframe->fr_width : 0) + col_end,
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200270 TPL_FILLCHAR, TPL_FILLCHAR, attr);
271}
272
273/*
274 * screen_puts_len() for tabpanel.
275 */
276 static void
277screen_puts_len_for_tabpanel(
278 int tplmode,
279 char_u *p,
280 int len,
281 int attr,
282 tabpanel_T *pargs)
283{
284 int j, k;
285 int chlen;
286 int chcells;
287 char_u buf[IOSIZE];
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200288 char_u *temp;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200289
290 for (j = 0; j < len;)
291 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200292 if (tplmode != TPLMODE_GET_CURTAB_ROW
293 && pargs->maxrow <= *pargs->prow - pargs->offsetrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200294 break;
295
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200296 if (p[j] == '\n' || p[j] == '\r')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200297 {
298 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200299 if (*pargs->prow - pargs->offsetrow >= 0
300 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200301 screen_fill_tailing_area(tplmode,
302 *pargs->prow - pargs->offsetrow,
303 *pargs->prow - pargs->offsetrow + 1,
304 *pargs->pcol, pargs->col_end, attr);
305 (*pargs->prow)++;
306 *pargs->pcol = pargs->col_start;
307 j++;
308 }
309 else
310 {
311 if (has_mbyte)
312 chlen = (*mb_ptr2len)(p + j);
313 else
314 chlen = (int)STRLEN(p + j);
315
316 for (k = 0; k < chlen; k++)
317 buf[k] = p[j + k];
318 buf[chlen] = NUL;
319 j += chlen;
320
321 // Make all characters printable.
322 temp = transstr(buf);
323 if (temp != NULL)
324 {
325 vim_strncpy(buf, temp, sizeof(buf) - 1);
326 vim_free(temp);
327 }
328
329 if (has_mbyte)
330 chcells = (*mb_ptr2cells)(buf);
331 else
332 chcells = 1;
333
334 if (pargs->col_end < (*pargs->pcol) + chcells)
335 {
336 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200337 if (*pargs->prow - pargs->offsetrow >= 0
338 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200339 screen_fill_tailing_area(tplmode,
340 *pargs->prow - pargs->offsetrow,
341 *pargs->prow - pargs->offsetrow + 1,
342 *pargs->pcol, pargs->col_end, attr);
343 *pargs->pcol = pargs->col_end;
344
345 if (pargs->col_end < chcells)
346 break;
347 }
348
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200349 if (*pargs->pcol + chcells <= pargs->col_end)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200350 {
351 int off = (tpl_align == ALIGN_RIGHT)
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200352 ? topframe->fr_width
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200353 : 0;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200354 if (TPLMODE_REDRAW == tplmode
355 && (*pargs->prow - pargs->offsetrow >= 0
356 && *pargs->prow - pargs->offsetrow < pargs->maxrow))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200357 screen_puts(buf, *pargs->prow - pargs->offsetrow,
358 *pargs->pcol + off, attr);
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200359 *pargs->pcol += chcells;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200360 }
361 }
362 }
363}
364
365/*
366 * default tabpanel drawing behavior if 'tabpanel' option is empty.
367 */
368 static void
369draw_tabpanel_default(int tplmode, tabpanel_T *pargs)
370{
371 int modified;
372 int wincount;
373 int len = 0;
374 char_u buf[2] = { NUL, NUL };
375
376 modified = FALSE;
377 for (wincount = 0; pargs->wp != NULL;
378 pargs->wp = pargs->wp->w_next, ++wincount)
379 if (bufIsChanged(pargs->wp->w_buffer))
380 modified = TRUE;
381
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200382 if (modified || wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200383 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200384 if (wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200385 {
386 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
387 len = (int)STRLEN(NameBuff);
388 screen_puts_len_for_tabpanel(tplmode, NameBuff, len,
389#if defined(FEAT_SYN_HL)
390 hl_combine_attr(pargs->attr, HL_ATTR(HLF_T)),
391#else
392 pargs->attr,
393#endif
394 pargs);
395 }
396 if (modified)
397 {
398 buf[0] = '+';
399 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
400 }
401
402 buf[0] = TPL_FILLCHAR;
403 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
404 }
405
406 get_trans_bufname(pargs->cwp->w_buffer);
407 shorten_dir(NameBuff);
408 len = (int)STRLEN(NameBuff);
409 screen_puts_len_for_tabpanel(tplmode, NameBuff, len, pargs->attr, pargs);
410
411 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200412 if (*pargs->prow - pargs->offsetrow >= 0
413 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200414 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
415 *pargs->prow - pargs->offsetrow + 1,
416 *pargs->pcol, pargs->col_end, pargs->attr);
417 *pargs->pcol = pargs->col_end;
418}
419
420/*
421 * default tabpanel drawing behavior if 'tabpanel' option is NOT empty.
422 */
423 static void
424draw_tabpanel_userdefined(int tplmode, tabpanel_T *pargs)
425{
426 char_u *p;
427 int p_crb_save;
428 char_u buf[IOSIZE];
429 stl_hlrec_T *hltab;
430 stl_hlrec_T *tabtab;
431 int curattr;
432 int n;
433
434 // Temporarily reset 'cursorbind', we don't want a side effect from moving
435 // the cursor away and back.
436 p_crb_save = pargs->cwp->w_p_crb;
437 pargs->cwp->w_p_crb = FALSE;
438
439 // Make a copy, because the statusline may include a function call that
440 // might change the option value and free the memory.
441 p = vim_strsave(pargs->user_defined);
442
443 build_stl_str_hl(pargs->cwp, buf, sizeof(buf),
444 p, opt_name, opt_scope,
445 TPL_FILLCHAR, pargs->col_end - pargs->col_start, &hltab, &tabtab);
446
447 vim_free(p);
448 pargs->cwp->w_p_crb = p_crb_save;
449
450 curattr = pargs->attr;
451 p = buf;
452 for (n = 0; hltab[n].start != NULL; n++)
453 {
454 screen_puts_len_for_tabpanel(tplmode, p, (int)(hltab[n].start - p),
455 curattr, pargs);
456 p = hltab[n].start;
457 if (hltab[n].userhl == 0)
458 curattr = pargs->attr;
459 else if (hltab[n].userhl < 0)
460 curattr = syn_id2attr(-hltab[n].userhl);
461#ifdef FEAT_TERMINAL
462 else if (pargs->wp != NULL && pargs->wp != curwin
463 && bt_terminal(pargs->wp->w_buffer)
464 && pargs->wp->w_status_height != 0)
465 curattr = highlight_stltermnc[hltab[n].userhl - 1];
466 else if (pargs->wp != NULL && bt_terminal(pargs->wp->w_buffer)
467 && pargs->wp->w_status_height != 0)
468 curattr = highlight_stlterm[hltab[n].userhl - 1];
469#endif
470 else if (pargs->wp != NULL && pargs->wp != curwin
471 && pargs->wp->w_status_height != 0)
472 curattr = highlight_stlnc[hltab[n].userhl - 1];
473 else
474 curattr = highlight_user[hltab[n].userhl - 1];
475 }
476 screen_puts_len_for_tabpanel(tplmode, p, (int)STRLEN(p), curattr, pargs);
477
478 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200479 if (*pargs->prow - pargs->offsetrow >= 0
480 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200481 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
482 *pargs->prow - pargs->offsetrow + 1, *pargs->pcol,
483 pargs->col_end, curattr);
484 *pargs->pcol = pargs->col_end;
485}
486
487 static char_u *
488starts_with_percent_and_bang(tabpanel_T *pargs)
489{
490 int len = 0;
491 char_u *usefmt = p_tpl;
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200492 int did_emsg_before = did_emsg;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200493
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);
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200522
523 if (did_emsg > did_emsg_before)
524 {
525 usefmt = NULL;
Christian Brabandtac83b3c2025-05-27 20:49:34 +0200526 set_string_option_direct(opt_name, -1, (char_u *)"",
527 OPT_FREE | opt_scope, SID_ERROR);
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200528 }
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200529 }
530#endif
531
532 return usefmt;
533}
534
535/*
536 * do something by tplmode for drawing tabpanel.
537 */
538 static void
539do_by_tplmode(
540 int tplmode,
541 int col_start,
542 int col_end,
543 int *pcurtab_row,
544 int *ptabpagenr)
545{
546 int attr_tplf = HL_ATTR(HLF_TPLF);
547 int attr_tpls = HL_ATTR(HLF_TPLS);
548 int attr_tpl = HL_ATTR(HLF_TPL);
549 int col = col_start;
550 int row = 0;
551 tabpage_T *tp = NULL;
552 typval_T v;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200553 tabpanel_T args;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200554
555 args.maxrow = cmdline_row;
556 args.offsetrow = 0;
557 args.col_start = col_start;
558 args.col_end = col_end;
559
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200560 if (tplmode != TPLMODE_GET_CURTAB_ROW && args.maxrow > 0)
561 while (args.offsetrow + args.maxrow <= *pcurtab_row)
562 args.offsetrow += args.maxrow;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200563
564 tp = first_tabpage;
565
566 for (row = 0; tp != NULL; row++)
567 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200568 if (tplmode != TPLMODE_GET_CURTAB_ROW
569 && args.maxrow <= row - args.offsetrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200570 break;
571
572 col = col_start;
573
574 v.v_type = VAR_NUMBER;
575 v.vval.v_number = tabpage_index(tp);
576 set_var((char_u *)"g:actual_curtabpage", &v, TRUE);
577
578 if (tp->tp_topframe == topframe)
579 {
580 args.attr = attr_tpls;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200581 if (tplmode == TPLMODE_GET_CURTAB_ROW)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200582 {
583 *pcurtab_row = row;
584 break;
585 }
586 }
587 else
588 args.attr = attr_tpl;
589
590 if (tp == curtab)
591 {
592 args.cwp = curwin;
593 args.wp = firstwin;
594 }
595 else
596 {
597 args.cwp = tp->tp_curwin;
598 args.wp = tp->tp_firstwin;
599 }
600
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200601 char_u *usefmt = starts_with_percent_and_bang(&args);
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200602 if (usefmt != NULL)
603 {
604 char_u buf[IOSIZE];
605 char_u *p = usefmt;
606 size_t i = 0;
607
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200608 while (p[i] != NUL)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200609 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200610 while (p[i] == '\n' || p[i] == '\r')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200611 {
612 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200613 if (row - args.offsetrow >= 0
614 && row - args.offsetrow < args.maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200615 screen_fill_tailing_area(tplmode,
616 row - args.offsetrow,
617 row - args.offsetrow + 1,
618 col, args.col_end, args.attr);
619 row++;
620 col = col_start;
621 p++;
622 }
623
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200624 while (p[i] != '\n' && p[i] != '\r' && p[i] != NUL)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200625 {
626 if (i + 1 >= sizeof(buf))
627 break;
628 buf[i] = p[i];
629 i++;
630 }
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200631 buf[i] = NUL;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200632
633 args.user_defined = buf;
634 args.prow = &row;
635 args.pcol = &col;
636 draw_tabpanel_userdefined(tplmode, &args);
Christian Brabandtac83b3c2025-05-27 20:49:34 +0200637 // p_tpl could have been freed in build_stl_str_hl()
638 if (p_tpl == NULL || *p_tpl == NUL)
639 {
640 usefmt = NULL;
641 break;
642 }
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200643
644 p += i;
645 i = 0;
646 }
647 if (usefmt != p_tpl)
648 VIM_CLEAR(usefmt);
649 }
650 else
651 {
652 args.user_defined = NULL;
653 args.prow = &row;
654 args.pcol = &col;
655 draw_tabpanel_default(tplmode, &args);
656 }
657
658 do_unlet((char_u *)"g:actual_curtabpage", TRUE);
659
660 tp = tp->tp_next;
661
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200662 if ((tplmode == TPLMODE_GET_TABPAGENR)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200663 && (mouse_row <= (row - args.offsetrow)))
664 {
665 *ptabpagenr = v.vval.v_number;
666 break;
667 }
668 }
669
670 // fill the area of TabPanelFill.
671 screen_fill_tailing_area(tplmode, row - args.offsetrow, args.maxrow,
672 args.col_start, args.col_end, attr_tplf);
673}
674
675#endif // FEAT_TABPANEL