blob: 260768a3d5675198448826026e7bb3ef60acf1c9 [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{
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200123 switch (p_stpl)
124 {
125 case 0:
126 return 0;
127 case 1:
128 if (first_tabpage->tp_next == NULL)
129 return 0;
130 }
131 if (Columns < tpl_columns)
132 return 0;
133 else
134 return tpl_columns;
135}
136
137/*
138 * Return the offset of a window considering the width of tabpanel.
139 */
140 int
141tabpanel_leftcol(win_T *wp)
142{
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200143 if (cmdline_pum_active() || (wp != NULL && WIN_IS_POPUP(wp)))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200144 return 0;
145 else
146 return tpl_align == ALIGN_RIGHT ? 0 : tabpanel_width();
147}
148
149/*
150 * draw the tabpanel.
151 */
152 void
153draw_tabpanel(void)
154{
155 int saved_KeyTyped = KeyTyped;
156 int saved_got_int = got_int;
157 int maxwidth = tabpanel_width();
158 int vs_attr = HL_ATTR(HLF_C);
159 int curtab_row = 0;
160#ifndef MSWIN
161 int row = 0;
162 int off = 0;
163#endif
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200164 int vsrow = 0;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200165 int is_right = tpl_align == ALIGN_RIGHT;
166
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200167 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200168 return;
169
170#ifndef MSWIN
171 // We need this section only for the Vim running on WSL.
172 for (row = 0; row < cmdline_row; row++)
173 {
174 if (is_right)
175 off = LineOffset[row] + Columns - maxwidth;
176 else
177 off = LineOffset[row];
178
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200179 vim_memset(ScreenLines + off, ' ', (size_t)maxwidth * sizeof(schar_T));
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200180 if (enc_utf8)
181 vim_memset(ScreenLinesUC + off, -1,
182 (size_t)maxwidth * sizeof(u8char_T));
183 }
184#endif
185
186 // Reset got_int to avoid build_stl_str_hl() isn't evaluted.
187 got_int = FALSE;
188
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200189 if (tpl_is_vert)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200190 {
191 if (is_right)
192 {
193 // draw main contents in tabpanel
194 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, VERT_LEN,
195 maxwidth - VERT_LEN, &curtab_row, NULL);
196 do_by_tplmode(TPLMODE_REDRAW, VERT_LEN, maxwidth, &curtab_row,
197 NULL);
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200198 // draw vert separator in tabpanel
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200199 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
200 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200201 topframe->fr_width, vs_attr);
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200202 }
203 else
204 {
205 // draw main contents in tabpanel
206 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth - VERT_LEN,
207 &curtab_row, NULL);
208 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth - VERT_LEN,
209 &curtab_row, NULL);
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200210 // draw vert separator in tabpanel
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200211 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
212 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
213 maxwidth - VERT_LEN, vs_attr);
214 }
215 }
216 else
217 {
218 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
219 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth, &curtab_row, NULL);
220 }
221
222 got_int |= saved_got_int;
223
224 // A user function may reset KeyTyped, restore it.
225 KeyTyped = saved_KeyTyped;
226
227 redraw_tabpanel = FALSE;
228}
229
230/*
231 * Return tabpagenr when clicking and dragging in tabpanel.
232 */
233 int
234get_tabpagenr_on_tabpanel(void)
235{
236 int maxwidth = tabpanel_width();
237 int curtab_row = 0;
238 int tabpagenr = 0;
239
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200240 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200241 return -1;
242
243 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
244 do_by_tplmode(TPLMODE_GET_TABPAGENR, 0, maxwidth, &curtab_row,
245 &tabpagenr);
246
247 return tabpagenr;
248}
249
250/*
251 * Fill tailing area between {start_row} and {end_row - 1}.
252 */
253 static void
254screen_fill_tailing_area(
255 int tplmode,
256 int row_start,
257 int row_end,
258 int col_start,
259 int col_end,
260 int attr)
261{
262 int is_right = tpl_align == ALIGN_RIGHT;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200263 if (tplmode == TPLMODE_REDRAW)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200264 screen_fill(row_start, row_end,
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200265 (is_right ? topframe->fr_width : 0) + col_start,
266 (is_right ? topframe->fr_width : 0) + col_end,
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200267 TPL_FILLCHAR, TPL_FILLCHAR, attr);
268}
269
270/*
271 * screen_puts_len() for tabpanel.
272 */
273 static void
274screen_puts_len_for_tabpanel(
275 int tplmode,
276 char_u *p,
277 int len,
278 int attr,
279 tabpanel_T *pargs)
280{
281 int j, k;
282 int chlen;
283 int chcells;
284 char_u buf[IOSIZE];
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200285 char_u *temp;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200286
287 for (j = 0; j < len;)
288 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200289 if (tplmode != TPLMODE_GET_CURTAB_ROW
290 && pargs->maxrow <= *pargs->prow - pargs->offsetrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200291 break;
292
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200293 if (p[j] == '\n' || p[j] == '\r')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200294 {
295 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200296 if (*pargs->prow - pargs->offsetrow >= 0
297 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200298 screen_fill_tailing_area(tplmode,
299 *pargs->prow - pargs->offsetrow,
300 *pargs->prow - pargs->offsetrow + 1,
301 *pargs->pcol, pargs->col_end, attr);
302 (*pargs->prow)++;
303 *pargs->pcol = pargs->col_start;
304 j++;
305 }
306 else
307 {
308 if (has_mbyte)
309 chlen = (*mb_ptr2len)(p + j);
310 else
311 chlen = (int)STRLEN(p + j);
312
313 for (k = 0; k < chlen; k++)
314 buf[k] = p[j + k];
315 buf[chlen] = NUL;
316 j += chlen;
317
318 // Make all characters printable.
319 temp = transstr(buf);
320 if (temp != NULL)
321 {
322 vim_strncpy(buf, temp, sizeof(buf) - 1);
323 vim_free(temp);
324 }
325
326 if (has_mbyte)
327 chcells = (*mb_ptr2cells)(buf);
328 else
329 chcells = 1;
330
331 if (pargs->col_end < (*pargs->pcol) + chcells)
332 {
333 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200334 if (*pargs->prow - pargs->offsetrow >= 0
335 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200336 screen_fill_tailing_area(tplmode,
337 *pargs->prow - pargs->offsetrow,
338 *pargs->prow - pargs->offsetrow + 1,
339 *pargs->pcol, pargs->col_end, attr);
340 *pargs->pcol = pargs->col_end;
341
342 if (pargs->col_end < chcells)
343 break;
344 }
345
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200346 if (*pargs->pcol + chcells <= pargs->col_end)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200347 {
348 int off = (tpl_align == ALIGN_RIGHT)
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200349 ? topframe->fr_width
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200350 : 0;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200351 if (TPLMODE_REDRAW == tplmode
352 && (*pargs->prow - pargs->offsetrow >= 0
353 && *pargs->prow - pargs->offsetrow < pargs->maxrow))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200354 screen_puts(buf, *pargs->prow - pargs->offsetrow,
355 *pargs->pcol + off, attr);
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200356 *pargs->pcol += chcells;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200357 }
358 }
359 }
360}
361
362/*
363 * default tabpanel drawing behavior if 'tabpanel' option is empty.
364 */
365 static void
366draw_tabpanel_default(int tplmode, tabpanel_T *pargs)
367{
368 int modified;
369 int wincount;
370 int len = 0;
371 char_u buf[2] = { NUL, NUL };
372
373 modified = FALSE;
374 for (wincount = 0; pargs->wp != NULL;
375 pargs->wp = pargs->wp->w_next, ++wincount)
376 if (bufIsChanged(pargs->wp->w_buffer))
377 modified = TRUE;
378
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200379 if (modified || wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200380 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200381 if (wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200382 {
383 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
384 len = (int)STRLEN(NameBuff);
385 screen_puts_len_for_tabpanel(tplmode, NameBuff, len,
386#if defined(FEAT_SYN_HL)
387 hl_combine_attr(pargs->attr, HL_ATTR(HLF_T)),
388#else
389 pargs->attr,
390#endif
391 pargs);
392 }
393 if (modified)
394 {
395 buf[0] = '+';
396 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
397 }
398
399 buf[0] = TPL_FILLCHAR;
400 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
401 }
402
403 get_trans_bufname(pargs->cwp->w_buffer);
404 shorten_dir(NameBuff);
405 len = (int)STRLEN(NameBuff);
406 screen_puts_len_for_tabpanel(tplmode, NameBuff, len, pargs->attr, pargs);
407
408 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200409 if (*pargs->prow - pargs->offsetrow >= 0
410 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200411 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
412 *pargs->prow - pargs->offsetrow + 1,
413 *pargs->pcol, pargs->col_end, pargs->attr);
414 *pargs->pcol = pargs->col_end;
415}
416
417/*
418 * default tabpanel drawing behavior if 'tabpanel' option is NOT empty.
419 */
420 static void
421draw_tabpanel_userdefined(int tplmode, tabpanel_T *pargs)
422{
423 char_u *p;
424 int p_crb_save;
425 char_u buf[IOSIZE];
426 stl_hlrec_T *hltab;
427 stl_hlrec_T *tabtab;
428 int curattr;
429 int n;
430
431 // Temporarily reset 'cursorbind', we don't want a side effect from moving
432 // the cursor away and back.
433 p_crb_save = pargs->cwp->w_p_crb;
434 pargs->cwp->w_p_crb = FALSE;
435
436 // Make a copy, because the statusline may include a function call that
437 // might change the option value and free the memory.
438 p = vim_strsave(pargs->user_defined);
439
440 build_stl_str_hl(pargs->cwp, buf, sizeof(buf),
441 p, opt_name, opt_scope,
442 TPL_FILLCHAR, pargs->col_end - pargs->col_start, &hltab, &tabtab);
443
444 vim_free(p);
445 pargs->cwp->w_p_crb = p_crb_save;
446
447 curattr = pargs->attr;
448 p = buf;
449 for (n = 0; hltab[n].start != NULL; n++)
450 {
451 screen_puts_len_for_tabpanel(tplmode, p, (int)(hltab[n].start - p),
452 curattr, pargs);
453 p = hltab[n].start;
454 if (hltab[n].userhl == 0)
455 curattr = pargs->attr;
456 else if (hltab[n].userhl < 0)
457 curattr = syn_id2attr(-hltab[n].userhl);
458#ifdef FEAT_TERMINAL
459 else if (pargs->wp != NULL && pargs->wp != curwin
460 && bt_terminal(pargs->wp->w_buffer)
461 && pargs->wp->w_status_height != 0)
462 curattr = highlight_stltermnc[hltab[n].userhl - 1];
463 else if (pargs->wp != NULL && bt_terminal(pargs->wp->w_buffer)
464 && pargs->wp->w_status_height != 0)
465 curattr = highlight_stlterm[hltab[n].userhl - 1];
466#endif
467 else if (pargs->wp != NULL && pargs->wp != curwin
468 && pargs->wp->w_status_height != 0)
469 curattr = highlight_stlnc[hltab[n].userhl - 1];
470 else
471 curattr = highlight_user[hltab[n].userhl - 1];
472 }
473 screen_puts_len_for_tabpanel(tplmode, p, (int)STRLEN(p), curattr, pargs);
474
475 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200476 if (*pargs->prow - pargs->offsetrow >= 0
477 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200478 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
479 *pargs->prow - pargs->offsetrow + 1, *pargs->pcol,
480 pargs->col_end, curattr);
481 *pargs->pcol = pargs->col_end;
482}
483
484 static char_u *
485starts_with_percent_and_bang(tabpanel_T *pargs)
486{
487 int len = 0;
488 char_u *usefmt = p_tpl;
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200489 int did_emsg_before = did_emsg;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200490
491 if (usefmt == NULL)
492 return NULL;
493
494 len = (int)STRLEN(usefmt);
495
496 if (len == 0)
497 return NULL;
498
499#ifdef FEAT_EVAL
500 // if "fmt" was set insecurely it needs to be evaluated in the sandbox
501 int use_sandbox = was_set_insecurely(opt_name, opt_scope);
502
503 // When the format starts with "%!" then evaluate it as an expression and
504 // use the result as the actual format string.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200505 if (len > 1 && usefmt[0] == '%' && usefmt[1] == '!')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200506 {
507 typval_T tv;
508 char_u *p = NULL;
509
510 tv.v_type = VAR_NUMBER;
511 tv.vval.v_number = pargs->cwp->w_id;
512 set_var((char_u *)"g:tabpanel_winid", &tv, FALSE);
513
514 p = eval_to_string_safe(usefmt + 2, use_sandbox, FALSE, FALSE);
515 if (p != NULL)
516 usefmt = p;
517
518 do_unlet((char_u *)"g:tabpanel_winid", TRUE);
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200519
520 if (did_emsg > did_emsg_before)
521 {
522 usefmt = NULL;
Christian Brabandtac83b3c2025-05-27 20:49:34 +0200523 set_string_option_direct(opt_name, -1, (char_u *)"",
524 OPT_FREE | opt_scope, SID_ERROR);
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200525 }
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200526 }
527#endif
528
529 return usefmt;
530}
531
532/*
533 * do something by tplmode for drawing tabpanel.
534 */
535 static void
536do_by_tplmode(
537 int tplmode,
538 int col_start,
539 int col_end,
540 int *pcurtab_row,
541 int *ptabpagenr)
542{
543 int attr_tplf = HL_ATTR(HLF_TPLF);
544 int attr_tpls = HL_ATTR(HLF_TPLS);
545 int attr_tpl = HL_ATTR(HLF_TPL);
546 int col = col_start;
547 int row = 0;
548 tabpage_T *tp = NULL;
549 typval_T v;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200550 tabpanel_T args;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200551
552 args.maxrow = cmdline_row;
553 args.offsetrow = 0;
554 args.col_start = col_start;
555 args.col_end = col_end;
556
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200557 if (tplmode != TPLMODE_GET_CURTAB_ROW && args.maxrow > 0)
558 while (args.offsetrow + args.maxrow <= *pcurtab_row)
559 args.offsetrow += args.maxrow;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200560
561 tp = first_tabpage;
562
563 for (row = 0; tp != NULL; row++)
564 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200565 if (tplmode != TPLMODE_GET_CURTAB_ROW
566 && args.maxrow <= row - args.offsetrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200567 break;
568
569 col = col_start;
570
571 v.v_type = VAR_NUMBER;
572 v.vval.v_number = tabpage_index(tp);
573 set_var((char_u *)"g:actual_curtabpage", &v, TRUE);
574
575 if (tp->tp_topframe == topframe)
576 {
577 args.attr = attr_tpls;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200578 if (tplmode == TPLMODE_GET_CURTAB_ROW)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200579 {
580 *pcurtab_row = row;
581 break;
582 }
583 }
584 else
585 args.attr = attr_tpl;
586
587 if (tp == curtab)
588 {
589 args.cwp = curwin;
590 args.wp = firstwin;
591 }
592 else
593 {
594 args.cwp = tp->tp_curwin;
595 args.wp = tp->tp_firstwin;
596 }
597
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200598 char_u *usefmt = starts_with_percent_and_bang(&args);
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200599 if (usefmt != NULL)
600 {
601 char_u buf[IOSIZE];
602 char_u *p = usefmt;
603 size_t i = 0;
604
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200605 while (p[i] != NUL)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200606 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200607 while (p[i] == '\n' || p[i] == '\r')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200608 {
609 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200610 if (row - args.offsetrow >= 0
611 && row - args.offsetrow < args.maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200612 screen_fill_tailing_area(tplmode,
613 row - args.offsetrow,
614 row - args.offsetrow + 1,
615 col, args.col_end, args.attr);
616 row++;
617 col = col_start;
618 p++;
619 }
620
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200621 while (p[i] != '\n' && p[i] != '\r' && p[i] != NUL)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200622 {
623 if (i + 1 >= sizeof(buf))
624 break;
625 buf[i] = p[i];
626 i++;
627 }
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200628 buf[i] = NUL;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200629
630 args.user_defined = buf;
631 args.prow = &row;
632 args.pcol = &col;
633 draw_tabpanel_userdefined(tplmode, &args);
Christian Brabandtac83b3c2025-05-27 20:49:34 +0200634 // p_tpl could have been freed in build_stl_str_hl()
635 if (p_tpl == NULL || *p_tpl == NUL)
636 {
637 usefmt = NULL;
638 break;
639 }
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200640
641 p += i;
642 i = 0;
643 }
644 if (usefmt != p_tpl)
645 VIM_CLEAR(usefmt);
646 }
647 else
648 {
649 args.user_defined = NULL;
650 args.prow = &row;
651 args.pcol = &col;
652 draw_tabpanel_default(tplmode, &args);
653 }
654
655 do_unlet((char_u *)"g:actual_curtabpage", TRUE);
656
657 tp = tp->tp_next;
658
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200659 if ((tplmode == TPLMODE_GET_TABPAGENR)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200660 && (mouse_row <= (row - args.offsetrow)))
661 {
662 *ptabpagenr = v.vval.v_number;
663 break;
664 }
665 }
666
667 // fill the area of TabPanelFill.
668 screen_fill_tailing_area(tplmode, row - args.offsetrow, args.maxrow,
669 args.col_start, args.col_end, attr_tplf);
670}
671
672#endif // FEAT_TABPANEL