blob: 77fe12f0f00b073da4f6270af8a95b3664259eb0 [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
Hirohito Higashie5c96e32025-06-16 19:39:24 +0200140tabpanel_leftcol(void)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200141{
Hirohito Higashie5c96e32025-06-16 19:39:24 +0200142 return tpl_align == ALIGN_RIGHT ? 0 : tabpanel_width();
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200143}
144
145/*
146 * draw the tabpanel.
147 */
148 void
149draw_tabpanel(void)
150{
151 int saved_KeyTyped = KeyTyped;
152 int saved_got_int = got_int;
153 int maxwidth = tabpanel_width();
154 int vs_attr = HL_ATTR(HLF_C);
155 int curtab_row = 0;
156#ifndef MSWIN
157 int row = 0;
158 int off = 0;
159#endif
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200160 int vsrow = 0;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200161 int is_right = tpl_align == ALIGN_RIGHT;
162
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200163 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200164 return;
165
166#ifndef MSWIN
167 // We need this section only for the Vim running on WSL.
168 for (row = 0; row < cmdline_row; row++)
169 {
170 if (is_right)
171 off = LineOffset[row] + Columns - maxwidth;
172 else
173 off = LineOffset[row];
174
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200175 vim_memset(ScreenLines + off, ' ', (size_t)maxwidth * sizeof(schar_T));
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200176 if (enc_utf8)
177 vim_memset(ScreenLinesUC + off, -1,
178 (size_t)maxwidth * sizeof(u8char_T));
179 }
180#endif
181
182 // Reset got_int to avoid build_stl_str_hl() isn't evaluted.
183 got_int = FALSE;
184
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200185 if (tpl_is_vert)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200186 {
187 if (is_right)
188 {
189 // draw main contents in tabpanel
190 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, VERT_LEN,
191 maxwidth - VERT_LEN, &curtab_row, NULL);
192 do_by_tplmode(TPLMODE_REDRAW, VERT_LEN, maxwidth, &curtab_row,
193 NULL);
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200194 // draw vert separator in tabpanel
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200195 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
196 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200197 topframe->fr_width, vs_attr);
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200198 }
199 else
200 {
201 // draw main contents in tabpanel
202 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth - VERT_LEN,
203 &curtab_row, NULL);
204 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth - VERT_LEN,
205 &curtab_row, NULL);
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200206 // draw vert separator in tabpanel
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200207 for (vsrow = 0; vsrow < cmdline_row; vsrow++)
208 screen_putchar(curwin->w_fill_chars.tpl_vert, vsrow,
209 maxwidth - VERT_LEN, vs_attr);
210 }
211 }
212 else
213 {
214 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
215 do_by_tplmode(TPLMODE_REDRAW, 0, maxwidth, &curtab_row, NULL);
216 }
217
218 got_int |= saved_got_int;
219
220 // A user function may reset KeyTyped, restore it.
221 KeyTyped = saved_KeyTyped;
222
223 redraw_tabpanel = FALSE;
224}
225
226/*
227 * Return tabpagenr when clicking and dragging in tabpanel.
228 */
229 int
230get_tabpagenr_on_tabpanel(void)
231{
232 int maxwidth = tabpanel_width();
233 int curtab_row = 0;
234 int tabpagenr = 0;
235
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200236 if (maxwidth == 0)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200237 return -1;
238
239 do_by_tplmode(TPLMODE_GET_CURTAB_ROW, 0, maxwidth, &curtab_row, NULL);
240 do_by_tplmode(TPLMODE_GET_TABPAGENR, 0, maxwidth, &curtab_row,
241 &tabpagenr);
242
243 return tabpagenr;
244}
245
246/*
247 * Fill tailing area between {start_row} and {end_row - 1}.
248 */
249 static void
250screen_fill_tailing_area(
251 int tplmode,
252 int row_start,
253 int row_end,
254 int col_start,
255 int col_end,
256 int attr)
257{
258 int is_right = tpl_align == ALIGN_RIGHT;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200259 if (tplmode == TPLMODE_REDRAW)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200260 screen_fill(row_start, row_end,
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200261 (is_right ? topframe->fr_width : 0) + col_start,
262 (is_right ? topframe->fr_width : 0) + col_end,
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200263 TPL_FILLCHAR, TPL_FILLCHAR, attr);
264}
265
266/*
267 * screen_puts_len() for tabpanel.
268 */
269 static void
270screen_puts_len_for_tabpanel(
271 int tplmode,
272 char_u *p,
273 int len,
274 int attr,
275 tabpanel_T *pargs)
276{
277 int j, k;
278 int chlen;
279 int chcells;
280 char_u buf[IOSIZE];
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200281 char_u *temp;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200282
283 for (j = 0; j < len;)
284 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200285 if (tplmode != TPLMODE_GET_CURTAB_ROW
286 && pargs->maxrow <= *pargs->prow - pargs->offsetrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200287 break;
288
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200289 if (p[j] == '\n' || p[j] == '\r')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200290 {
291 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200292 if (*pargs->prow - pargs->offsetrow >= 0
293 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200294 screen_fill_tailing_area(tplmode,
295 *pargs->prow - pargs->offsetrow,
296 *pargs->prow - pargs->offsetrow + 1,
297 *pargs->pcol, pargs->col_end, attr);
298 (*pargs->prow)++;
299 *pargs->pcol = pargs->col_start;
300 j++;
301 }
302 else
303 {
304 if (has_mbyte)
305 chlen = (*mb_ptr2len)(p + j);
306 else
307 chlen = (int)STRLEN(p + j);
308
309 for (k = 0; k < chlen; k++)
310 buf[k] = p[j + k];
311 buf[chlen] = NUL;
312 j += chlen;
313
314 // Make all characters printable.
315 temp = transstr(buf);
316 if (temp != NULL)
317 {
318 vim_strncpy(buf, temp, sizeof(buf) - 1);
319 vim_free(temp);
320 }
321
322 if (has_mbyte)
323 chcells = (*mb_ptr2cells)(buf);
324 else
325 chcells = 1;
326
327 if (pargs->col_end < (*pargs->pcol) + chcells)
328 {
329 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200330 if (*pargs->prow - pargs->offsetrow >= 0
331 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200332 screen_fill_tailing_area(tplmode,
333 *pargs->prow - pargs->offsetrow,
334 *pargs->prow - pargs->offsetrow + 1,
335 *pargs->pcol, pargs->col_end, attr);
336 *pargs->pcol = pargs->col_end;
337
338 if (pargs->col_end < chcells)
339 break;
340 }
341
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200342 if (*pargs->pcol + chcells <= pargs->col_end)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200343 {
344 int off = (tpl_align == ALIGN_RIGHT)
Hirohito Higashi3b9b95d2025-06-01 20:22:55 +0200345 ? topframe->fr_width
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200346 : 0;
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200347 if (TPLMODE_REDRAW == tplmode
348 && (*pargs->prow - pargs->offsetrow >= 0
349 && *pargs->prow - pargs->offsetrow < pargs->maxrow))
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200350 screen_puts(buf, *pargs->prow - pargs->offsetrow,
351 *pargs->pcol + off, attr);
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200352 *pargs->pcol += chcells;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200353 }
354 }
355 }
356}
357
358/*
359 * default tabpanel drawing behavior if 'tabpanel' option is empty.
360 */
361 static void
362draw_tabpanel_default(int tplmode, tabpanel_T *pargs)
363{
364 int modified;
365 int wincount;
366 int len = 0;
367 char_u buf[2] = { NUL, NUL };
368
369 modified = FALSE;
370 for (wincount = 0; pargs->wp != NULL;
371 pargs->wp = pargs->wp->w_next, ++wincount)
372 if (bufIsChanged(pargs->wp->w_buffer))
373 modified = TRUE;
374
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200375 if (modified || wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200376 {
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200377 if (wincount > 1)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200378 {
379 vim_snprintf((char *)NameBuff, MAXPATHL, "%d", wincount);
380 len = (int)STRLEN(NameBuff);
381 screen_puts_len_for_tabpanel(tplmode, NameBuff, len,
382#if defined(FEAT_SYN_HL)
383 hl_combine_attr(pargs->attr, HL_ATTR(HLF_T)),
384#else
385 pargs->attr,
386#endif
387 pargs);
388 }
389 if (modified)
390 {
391 buf[0] = '+';
392 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
393 }
394
395 buf[0] = TPL_FILLCHAR;
396 screen_puts_len_for_tabpanel(tplmode, buf, 1, pargs->attr, pargs);
397 }
398
399 get_trans_bufname(pargs->cwp->w_buffer);
400 shorten_dir(NameBuff);
401 len = (int)STRLEN(NameBuff);
402 screen_puts_len_for_tabpanel(tplmode, NameBuff, len, pargs->attr, pargs);
403
404 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200405 if (*pargs->prow - pargs->offsetrow >= 0
406 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200407 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
408 *pargs->prow - pargs->offsetrow + 1,
409 *pargs->pcol, pargs->col_end, pargs->attr);
410 *pargs->pcol = pargs->col_end;
411}
412
413/*
414 * default tabpanel drawing behavior if 'tabpanel' option is NOT empty.
415 */
416 static void
417draw_tabpanel_userdefined(int tplmode, tabpanel_T *pargs)
418{
419 char_u *p;
420 int p_crb_save;
421 char_u buf[IOSIZE];
422 stl_hlrec_T *hltab;
423 stl_hlrec_T *tabtab;
424 int curattr;
425 int n;
426
427 // Temporarily reset 'cursorbind', we don't want a side effect from moving
428 // the cursor away and back.
429 p_crb_save = pargs->cwp->w_p_crb;
430 pargs->cwp->w_p_crb = FALSE;
431
432 // Make a copy, because the statusline may include a function call that
433 // might change the option value and free the memory.
434 p = vim_strsave(pargs->user_defined);
435
436 build_stl_str_hl(pargs->cwp, buf, sizeof(buf),
437 p, opt_name, opt_scope,
438 TPL_FILLCHAR, pargs->col_end - pargs->col_start, &hltab, &tabtab);
439
440 vim_free(p);
441 pargs->cwp->w_p_crb = p_crb_save;
442
443 curattr = pargs->attr;
444 p = buf;
445 for (n = 0; hltab[n].start != NULL; n++)
446 {
447 screen_puts_len_for_tabpanel(tplmode, p, (int)(hltab[n].start - p),
448 curattr, pargs);
449 p = hltab[n].start;
450 if (hltab[n].userhl == 0)
451 curattr = pargs->attr;
452 else if (hltab[n].userhl < 0)
453 curattr = syn_id2attr(-hltab[n].userhl);
454#ifdef FEAT_TERMINAL
455 else if (pargs->wp != NULL && pargs->wp != curwin
456 && bt_terminal(pargs->wp->w_buffer)
457 && pargs->wp->w_status_height != 0)
458 curattr = highlight_stltermnc[hltab[n].userhl - 1];
459 else if (pargs->wp != NULL && bt_terminal(pargs->wp->w_buffer)
460 && pargs->wp->w_status_height != 0)
461 curattr = highlight_stlterm[hltab[n].userhl - 1];
462#endif
463 else if (pargs->wp != NULL && pargs->wp != curwin
464 && pargs->wp->w_status_height != 0)
465 curattr = highlight_stlnc[hltab[n].userhl - 1];
466 else
467 curattr = highlight_user[hltab[n].userhl - 1];
468 }
469 screen_puts_len_for_tabpanel(tplmode, p, (int)STRLEN(p), curattr, pargs);
470
471 // fill the tailing area of current row.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200472 if (*pargs->prow - pargs->offsetrow >= 0
473 && *pargs->prow - pargs->offsetrow < pargs->maxrow)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200474 screen_fill_tailing_area(tplmode, *pargs->prow - pargs->offsetrow,
475 *pargs->prow - pargs->offsetrow + 1, *pargs->pcol,
476 pargs->col_end, curattr);
477 *pargs->pcol = pargs->col_end;
478}
479
480 static char_u *
481starts_with_percent_and_bang(tabpanel_T *pargs)
482{
483 int len = 0;
484 char_u *usefmt = p_tpl;
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200485 int did_emsg_before = did_emsg;
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200486
487 if (usefmt == NULL)
488 return NULL;
489
490 len = (int)STRLEN(usefmt);
491
492 if (len == 0)
493 return NULL;
494
495#ifdef FEAT_EVAL
496 // if "fmt" was set insecurely it needs to be evaluated in the sandbox
497 int use_sandbox = was_set_insecurely(opt_name, opt_scope);
498
499 // When the format starts with "%!" then evaluate it as an expression and
500 // use the result as the actual format string.
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200501 if (len > 1 && usefmt[0] == '%' && usefmt[1] == '!')
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200502 {
503 typval_T tv;
504 char_u *p = NULL;
505
506 tv.v_type = VAR_NUMBER;
507 tv.vval.v_number = pargs->cwp->w_id;
508 set_var((char_u *)"g:tabpanel_winid", &tv, FALSE);
509
510 p = eval_to_string_safe(usefmt + 2, use_sandbox, FALSE, FALSE);
511 if (p != NULL)
512 usefmt = p;
513
514 do_unlet((char_u *)"g:tabpanel_winid", TRUE);
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200515
516 if (did_emsg > did_emsg_before)
517 {
518 usefmt = NULL;
Christian Brabandtac83b3c2025-05-27 20:49:34 +0200519 set_string_option_direct(opt_name, -1, (char_u *)"",
520 OPT_FREE | opt_scope, SID_ERROR);
Christian Brabandta88c5bd2025-05-26 19:51:03 +0200521 }
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200522 }
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 Higashi3b9b95d2025-06-01 20:22:55 +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);
Christian Brabandtac83b3c2025-05-27 20:49:34 +0200630 // p_tpl could have been freed in build_stl_str_hl()
631 if (p_tpl == NULL || *p_tpl == NUL)
632 {
633 usefmt = NULL;
634 break;
635 }
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200636
637 p += i;
638 i = 0;
639 }
640 if (usefmt != p_tpl)
641 VIM_CLEAR(usefmt);
642 }
643 else
644 {
645 args.user_defined = NULL;
646 args.prow = &row;
647 args.pcol = &col;
648 draw_tabpanel_default(tplmode, &args);
649 }
650
651 do_unlet((char_u *)"g:actual_curtabpage", TRUE);
652
653 tp = tp->tp_next;
654
Hirohito Higashic659e4a2025-05-16 19:34:34 +0200655 if ((tplmode == TPLMODE_GET_TABPAGENR)
Naruhiko Nishinobe5bd4d2025-05-14 21:20:28 +0200656 && (mouse_row <= (row - args.offsetrow)))
657 {
658 *ptabpagenr = v.vval.v_number;
659 break;
660 }
661 }
662
663 // fill the area of TabPanelFill.
664 screen_fill_tailing_area(tplmode, row - args.offsetrow, args.maxrow,
665 args.col_start, args.col_end, attr_tplf);
666}
667
668#endif // FEAT_TABPANEL