tmux  3.2a
About: tmux is a terminal multiplexer that lets you switch easily between several programs in one terminal.
  Fossies Dox: tmux-3.2a.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

grid.c
Go to the documentation of this file.
1 /* $OpenBSD$ */
2 
3 /*
4  * Copyright (c) 2008 Nicholas Marriott <nicholas.marriott@gmail.com>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
15  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
16  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/types.h>
20 
21 #include <stdlib.h>
22 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /*
27  * Grid data. This is the basic data structure that represents what is shown on
28  * screen.
29  *
30  * A grid is a grid of cells (struct grid_cell). Lines are not allocated until
31  * cells in that line are written to. The grid is split into history and
32  * viewable data with the history starting at row (line) 0 and extending to
33  * (hsize - 1); from hsize to hsize + (sy - 1) is the viewable data. All
34  * functions in this file work on absolute coordinates, grid-view.c has
35  * functions which work on the screen data.
36  */
37 
38 /* Default grid cell data. */
39 const struct grid_cell grid_default_cell = {
40  { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0
41 };
42 
43 /*
44  * Padding grid cell data. Padding cells are the only zero width cell that
45  * appears in the grid - because of this, they are always extended cells.
46  */
47 static const struct grid_cell grid_padding_cell = {
48  { { '!' }, 0, 0, 0 }, 0, GRID_FLAG_PADDING, 8, 8, 0
49 };
50 
51 /* Cleared grid cell data. */
52 static const struct grid_cell grid_cleared_cell = {
53  { { ' ' }, 0, 1, 1 }, 0, GRID_FLAG_CLEARED, 8, 8, 0
54 };
55 static const struct grid_cell_entry grid_cleared_entry = {
56  GRID_FLAG_CLEARED, { .data = { 0, 8, 8, ' ' } }
57 };
58 
59 /* Store cell in entry. */
60 static void
61 grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc,
62  u_char c)
63 {
64  gce->flags = (gc->flags & ~~GRID_FLAG_CLEARED);
65 
66  gce->data.fg = gc->fg & 0xff;
67  if (gc->fg & COLOUR_FLAG_256)
68  gce->flags |= GRID_FLAG_FG256;
69 
70  gce->data.bg = gc->bg & 0xff;
71  if (gc->bg & COLOUR_FLAG_256)
72  gce->flags |= GRID_FLAG_BG256;
73 
74  gce->data.attr = gc->attr;
75  gce->data.data = c;
76 }
77 
78 /* Check if a cell should be an extended cell. */
79 static int
81  const struct grid_cell *gc)
82 {
83  if (gce->flags & GRID_FLAG_EXTENDED)
84  return (1);
85  if (gc->attr > 0xff)
86  return (1);
87  if (gc->data.size != 1 || gc->data.width != 1)
88  return (1);
89  if ((gc->fg & COLOUR_FLAG_RGB) || (gc->bg & COLOUR_FLAG_RGB))
90  return (1);
91  if (gc->us != 0) /* only supports 256 or RGB */
92  return (1);
93  return (0);
94 }
95 
96 /* Get an extended cell. */
97 static void
99  int flags)
100 {
101  u_int at = gl->extdsize + 1;
102 
103  gl->extddata = xreallocarray(gl->extddata, at, sizeof *gl->extddata);
104  gl->extdsize = at;
105 
106  gce->offset = at - 1;
107  gce->flags = (flags | GRID_FLAG_EXTENDED);
108 }
109 
110 /* Set cell as extended. */
111 static struct grid_extd_entry *
113  const struct grid_cell *gc)
114 {
115  struct grid_extd_entry *gee;
116  int flags = (gc->flags & ~~GRID_FLAG_CLEARED);
117  utf8_char uc;
118 
119  if (~gce->flags & GRID_FLAG_EXTENDED)
120  grid_get_extended_cell(gl, gce, flags);
121  else if (gce->offset >= gl->extdsize)
122  fatalx("offset too big");
123  gl->flags |= GRID_LINE_EXTENDED;
124 
125  utf8_from_data(&gc->data, &uc);
126 
127  gee = &gl->extddata[gce->offset];
128  gee->data = uc;
129  gee->attr = gc->attr;
130  gee->flags = flags;
131  gee->fg = gc->fg;
132  gee->bg = gc->bg;
133  gee->us = gc->us;
134  return (gee);
135 }
136 
137 /* Free up unused extended cells. */
138 static void
140 {
141  int new_extdsize = 0;
142  struct grid_extd_entry *new_extddata;
143  struct grid_cell_entry *gce;
144  struct grid_extd_entry *gee;
145  u_int px, idx;
146 
147  if (gl->extdsize == 0)
148  return;
149 
150  for (px = 0; px < gl->cellsize; px++) {
151  gce = &gl->celldata[px];
152  if (gce->flags & GRID_FLAG_EXTENDED)
153  new_extdsize++;
154  }
155 
156  if (new_extdsize == 0) {
157  free(gl->extddata);
158  gl->extddata = NULL;
159  gl->extdsize = 0;
160  return;
161  }
162  new_extddata = xreallocarray(NULL, new_extdsize, sizeof *gl->extddata);
163 
164  idx = 0;
165  for (px = 0; px < gl->cellsize; px++) {
166  gce = &gl->celldata[px];
167  if (gce->flags & GRID_FLAG_EXTENDED) {
168  gee = &gl->extddata[gce->offset];
169  memcpy(&new_extddata[idx], gee, sizeof *gee);
170  gce->offset = idx++;
171  }
172  }
173 
174  free(gl->extddata);
175  gl->extddata = new_extddata;
176  gl->extdsize = new_extdsize;
177 }
178 
179 /* Get line data. */
180 struct grid_line *
181 grid_get_line(struct grid *gd, u_int line)
182 {
183  return (&gd->linedata[line]);
184 }
185 
186 /* Adjust number of lines. */
187 void
188 grid_adjust_lines(struct grid *gd, u_int lines)
189 {
190  gd->linedata = xreallocarray(gd->linedata, lines, sizeof *gd->linedata);
191 }
192 
193 /* Copy default into a cell. */
194 static void
195 grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
196 {
197  struct grid_line *gl = &gd->linedata[py];
198  struct grid_cell_entry *gce = &gl->celldata[px];
199  struct grid_extd_entry *gee;
200 
201  memcpy(gce, &grid_cleared_entry, sizeof *gce);
202  if (bg != 8) {
203  if (bg & COLOUR_FLAG_RGB) {
204  grid_get_extended_cell(gl, gce, gce->flags);
205  gee = grid_extended_cell(gl, gce, &grid_cleared_cell);
206  gee->bg = bg;
207  } else {
208  if (bg & COLOUR_FLAG_256)
209  gce->flags |= GRID_FLAG_BG256;
210  gce->data.bg = bg;
211  }
212  }
213 }
214 
215 /* Check grid y position. */
216 static int
217 grid_check_y(struct grid *gd, const char *from, u_int py)
218 {
219  if (py >= gd->hsize + gd->sy) {
220  log_debug("%s: y out of range: %u", from, py);
221  return (-1);
222  }
223  return (0);
224 }
225 
226 /* Check if two styles are (visibly) the same. */
227 int
228 grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
229 {
230  if (gc1->fg != gc2->fg || gc1->bg != gc2->bg)
231  return (0);
232  if (gc1->attr != gc2->attr || gc1->flags != gc2->flags)
233  return (0);
234  return (1);
235 }
236 
237 /* Compare grid cells. Return 1 if equal, 0 if not. */
238 int
239 grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
240 {
241  if (!grid_cells_look_equal(gc1, gc2))
242  return (0);
243  if (gc1->data.width != gc2->data.width)
244  return (0);
245  if (gc1->data.size != gc2->data.size)
246  return (0);
247  return (memcmp(gc1->data.data, gc2->data.data, gc1->data.size) == 0);
248 }
249 
250 /* Free one line. */
251 static void
252 grid_free_line(struct grid *gd, u_int py)
253 {
254  free(gd->linedata[py].celldata);
255  gd->linedata[py].celldata = NULL;
256  free(gd->linedata[py].extddata);
257  gd->linedata[py].extddata = NULL;
258 }
259 
260 /* Free several lines. */
261 static void
262 grid_free_lines(struct grid *gd, u_int py, u_int ny)
263 {
264  u_int yy;
265 
266  for (yy = py; yy < py + ny; yy++)
267  grid_free_line(gd, yy);
268 }
269 
270 /* Create a new grid. */
271 struct grid *
272 grid_create(u_int sx, u_int sy, u_int hlimit)
273 {
274  struct grid *gd;
275 
276  gd = xmalloc(sizeof *gd);
277  gd->sx = sx;
278  gd->sy = sy;
279 
280  if (hlimit != 0)
281  gd->flags = GRID_HISTORY;
282  else
283  gd->flags = 0;
284 
285  gd->hscrolled = 0;
286  gd->hsize = 0;
287  gd->hlimit = hlimit;
288 
289  if (gd->sy != 0)
290  gd->linedata = xcalloc(gd->sy, sizeof *gd->linedata);
291  else
292  gd->linedata = NULL;
293 
294  return (gd);
295 }
296 
297 /* Destroy grid. */
298 void
299 grid_destroy(struct grid *gd)
300 {
301  grid_free_lines(gd, 0, gd->hsize + gd->sy);
302 
303  free(gd->linedata);
304 
305  free(gd);
306 }
307 
308 /* Compare grids. */
309 int
310 grid_compare(struct grid *ga, struct grid *gb)
311 {
312  struct grid_line *gla, *glb;
313  struct grid_cell gca, gcb;
314  u_int xx, yy;
315 
316  if (ga->sx != gb->sx || ga->sy != gb->sy)
317  return (1);
318 
319  for (yy = 0; yy < ga->sy; yy++) {
320  gla = &ga->linedata[yy];
321  glb = &gb->linedata[yy];
322  if (gla->cellsize != glb->cellsize)
323  return (1);
324  for (xx = 0; xx < gla->cellsize; xx++) {
325  grid_get_cell(ga, xx, yy, &gca);
326  grid_get_cell(gb, xx, yy, &gcb);
327  if (!grid_cells_equal(&gca, &gcb))
328  return (1);
329  }
330  }
331 
332  return (0);
333 }
334 
335 /* Trim lines from the history. */
336 static void
337 grid_trim_history(struct grid *gd, u_int ny)
338 {
339  grid_free_lines(gd, 0, ny);
340  memmove(&gd->linedata[0], &gd->linedata[ny],
341  (gd->hsize + gd->sy - ny) * (sizeof *gd->linedata));
342 }
343 
344 /*
345  * Collect lines from the history if at the limit. Free the top (oldest) 10%
346  * and shift up.
347  */
348 void
350 {
351  u_int ny;
352 
353  if (gd->hsize == 0 || gd->hsize < gd->hlimit)
354  return;
355 
356  ny = gd->hlimit / 10;
357  if (ny < 1)
358  ny = 1;
359  if (ny > gd->hsize)
360  ny = gd->hsize;
361 
362  /*
363  * Free the lines from 0 to ny then move the remaining lines over
364  * them.
365  */
366  grid_trim_history(gd, ny);
367 
368  gd->hsize -= ny;
369  if (gd->hscrolled > gd->hsize)
370  gd->hscrolled = gd->hsize;
371 }
372 
373 /* Remove lines from the bottom of the history. */
374 void
375 grid_remove_history(struct grid *gd, u_int ny)
376 {
377  u_int yy;
378 
379  if (ny > gd->hsize)
380  return;
381  for (yy = 0; yy < ny; yy++)
382  grid_free_line(gd, gd->hsize + gd->sy - 1 - yy);
383  gd->hsize -= ny;
384 }
385 
386 /*
387  * Scroll the entire visible screen, moving one line into the history. Just
388  * allocate a new line at the bottom and move the history size indicator.
389  */
390 void
391 grid_scroll_history(struct grid *gd, u_int bg)
392 {
393  u_int yy;
394 
395  yy = gd->hsize + gd->sy;
396  gd->linedata = xreallocarray(gd->linedata, yy + 1,
397  sizeof *gd->linedata);
398  grid_empty_line(gd, yy, bg);
399 
400  gd->hscrolled++;
401  grid_compact_line(&gd->linedata[gd->hsize]);
402  gd->hsize++;
403 }
404 
405 /* Clear the history. */
406 void
408 {
409  grid_trim_history(gd, gd->hsize);
410 
411  gd->hscrolled = 0;
412  gd->hsize = 0;
413 
414  gd->linedata = xreallocarray(gd->linedata, gd->sy,
415  sizeof *gd->linedata);
416 }
417 
418 /* Scroll a region up, moving the top line into the history. */
419 void
420 grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
421 {
422  struct grid_line *gl_history, *gl_upper;
423  u_int yy;
424 
425  /* Create a space for a new line. */
426  yy = gd->hsize + gd->sy;
427  gd->linedata = xreallocarray(gd->linedata, yy + 1,
428  sizeof *gd->linedata);
429 
430  /* Move the entire screen down to free a space for this line. */
431  gl_history = &gd->linedata[gd->hsize];
432  memmove(gl_history + 1, gl_history, gd->sy * sizeof *gl_history);
433 
434  /* Adjust the region and find its start and end. */
435  upper++;
436  gl_upper = &gd->linedata[upper];
437  lower++;
438 
439  /* Move the line into the history. */
440  memcpy(gl_history, gl_upper, sizeof *gl_history);
441 
442  /* Then move the region up and clear the bottom line. */
443  memmove(gl_upper, gl_upper + 1, (lower - upper) * sizeof *gl_upper);
444  grid_empty_line(gd, lower, bg);
445 
446  /* Move the history offset down over the line. */
447  gd->hscrolled++;
448  gd->hsize++;
449 }
450 
451 /* Expand line to fit to cell. */
452 static void
453 grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
454 {
455  struct grid_line *gl;
456  u_int xx;
457 
458  gl = &gd->linedata[py];
459  if (sx <= gl->cellsize)
460  return;
461 
462  if (sx < gd->sx / 4)
463  sx = gd->sx / 4;
464  else if (sx < gd->sx / 2)
465  sx = gd->sx / 2;
466  else if (gd->sx > sx)
467  sx = gd->sx;
468 
469  gl->celldata = xreallocarray(gl->celldata, sx, sizeof *gl->celldata);
470  for (xx = gl->cellsize; xx < sx; xx++)
471  grid_clear_cell(gd, xx, py, bg);
472  gl->cellsize = sx;
473 }
474 
475 /* Empty a line and set background colour if needed. */
476 void
477 grid_empty_line(struct grid *gd, u_int py, u_int bg)
478 {
479  memset(&gd->linedata[py], 0, sizeof gd->linedata[py]);
480  if (!COLOUR_DEFAULT(bg))
481  grid_expand_line(gd, py, gd->sx, bg);
482 }
483 
484 /* Peek at grid line. */
485 const struct grid_line *
486 grid_peek_line(struct grid *gd, u_int py)
487 {
488  if (grid_check_y(gd, __func__, py) != 0)
489  return (NULL);
490  return (&gd->linedata[py]);
491 }
492 
493 /* Get cell from line. */
494 static void
495 grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
496 {
497  struct grid_cell_entry *gce = &gl->celldata[px];
498  struct grid_extd_entry *gee;
499 
500  if (gce->flags & GRID_FLAG_EXTENDED) {
501  if (gce->offset >= gl->extdsize)
502  memcpy(gc, &grid_default_cell, sizeof *gc);
503  else {
504  gee = &gl->extddata[gce->offset];
505  gc->flags = gee->flags;
506  gc->attr = gee->attr;
507  gc->fg = gee->fg;
508  gc->bg = gee->bg;
509  gc->us = gee->us;
510  utf8_to_data(gee->data, &gc->data);
511  }
512  return;
513  }
514 
515  gc->flags = gce->flags & ~(GRID_FLAG_FG256|GRID_FLAG_BG256);
516  gc->attr = gce->data.attr;
517  gc->fg = gce->data.fg;
518  if (gce->flags & GRID_FLAG_FG256)
519  gc->fg |= COLOUR_FLAG_256;
520  gc->bg = gce->data.bg;
521  if (gce->flags & GRID_FLAG_BG256)
522  gc->bg |= COLOUR_FLAG_256;
523  gc->us = 0;
524  utf8_set(&gc->data, gce->data.data);
525 }
526 
527 /* Get cell for reading. */
528 void
529 grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
530 {
531  if (grid_check_y(gd, __func__, py) != 0 ||
532  px >= gd->linedata[py].cellsize)
533  memcpy(gc, &grid_default_cell, sizeof *gc);
534  else
535  grid_get_cell1(&gd->linedata[py], px, gc);
536 }
537 
538 /* Set cell at position. */
539 void
540 grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
541 {
542  struct grid_line *gl;
543  struct grid_cell_entry *gce;
544 
545  if (grid_check_y(gd, __func__, py) != 0)
546  return;
547 
548  grid_expand_line(gd, py, px + 1, 8);
549 
550  gl = &gd->linedata[py];
551  if (px + 1 > gl->cellused)
552  gl->cellused = px + 1;
553 
554  gce = &gl->celldata[px];
555  if (grid_need_extended_cell(gce, gc))
556  grid_extended_cell(gl, gce, gc);
557  else
558  grid_store_cell(gce, gc, gc->data.data[0]);
559 }
560 
561 /* Set padding at position. */
562 void
563 grid_set_padding(struct grid *gd, u_int px, u_int py)
564 {
565  grid_set_cell(gd, px, py, &grid_padding_cell);
566 }
567 
568 /* Set cells at position. */
569 void
570 grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc,
571  const char *s, size_t slen)
572 {
573  struct grid_line *gl;
574  struct grid_cell_entry *gce;
575  struct grid_extd_entry *gee;
576  u_int i;
577 
578  if (grid_check_y(gd, __func__, py) != 0)
579  return;
580 
581  grid_expand_line(gd, py, px + slen, 8);
582 
583  gl = &gd->linedata[py];
584  if (px + slen > gl->cellused)
585  gl->cellused = px + slen;
586 
587  for (i = 0; i < slen; i++) {
588  gce = &gl->celldata[px + i];
589  if (grid_need_extended_cell(gce, gc)) {
590  gee = grid_extended_cell(gl, gce, gc);
591  gee->data = utf8_build_one(s[i]);
592  } else
593  grid_store_cell(gce, gc, s[i]);
594  }
595 }
596 
597 /* Clear area. */
598 void
599 grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
600 {
601  struct grid_line *gl;
602  u_int xx, yy, ox, sx;
603 
604  if (nx == 0 || ny == 0)
605  return;
606 
607  if (px == 0 && nx == gd->sx) {
608  grid_clear_lines(gd, py, ny, bg);
609  return;
610  }
611 
612  if (grid_check_y(gd, __func__, py) != 0)
613  return;
614  if (grid_check_y(gd, __func__, py + ny - 1) != 0)
615  return;
616 
617  for (yy = py; yy < py + ny; yy++) {
618  gl = &gd->linedata[yy];
619 
620  sx = gd->sx;
621  if (sx > gl->cellsize)
622  sx = gl->cellsize;
623  ox = nx;
624  if (COLOUR_DEFAULT(bg)) {
625  if (px > sx)
626  continue;
627  if (px + nx > sx)
628  ox = sx - px;
629  }
630 
631  grid_expand_line(gd, yy, px + ox, 8); /* default bg first */
632  for (xx = px; xx < px + ox; xx++)
633  grid_clear_cell(gd, xx, yy, bg);
634  }
635 }
636 
637 /* Clear lines. This just frees and truncates the lines. */
638 void
639 grid_clear_lines(struct grid *gd, u_int py, u_int ny, u_int bg)
640 {
641  u_int yy;
642 
643  if (ny == 0)
644  return;
645 
646  if (grid_check_y(gd, __func__, py) != 0)
647  return;
648  if (grid_check_y(gd, __func__, py + ny - 1) != 0)
649  return;
650 
651  for (yy = py; yy < py + ny; yy++) {
652  grid_free_line(gd, yy);
653  grid_empty_line(gd, yy, bg);
654  }
655  if (py != 0)
656  gd->linedata[py - 1].flags &= ~~GRID_LINE_WRAPPED;
657 }
658 
659 /* Move a group of lines. */
660 void
661 grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny, u_int bg)
662 {
663  u_int yy;
664 
665  if (ny == 0 || py == dy)
666  return;
667 
668  if (grid_check_y(gd, __func__, py) != 0)
669  return;
670  if (grid_check_y(gd, __func__, py + ny - 1) != 0)
671  return;
672  if (grid_check_y(gd, __func__, dy) != 0)
673  return;
674  if (grid_check_y(gd, __func__, dy + ny - 1) != 0)
675  return;
676 
677  /* Free any lines which are being replaced. */
678  for (yy = dy; yy < dy + ny; yy++) {
679  if (yy >= py && yy < py + ny)
680  continue;
681  grid_free_line(gd, yy);
682  }
683  if (dy != 0)
684  gd->linedata[dy - 1].flags &= ~~GRID_LINE_WRAPPED;
685 
686  memmove(&gd->linedata[dy], &gd->linedata[py],
687  ny * (sizeof *gd->linedata));
688 
689  /*
690  * Wipe any lines that have been moved (without freeing them - they are
691  * still present).
692  */
693  for (yy = py; yy < py + ny; yy++) {
694  if (yy < dy || yy >= dy + ny)
695  grid_empty_line(gd, yy, bg);
696  }
697  if (py != 0 && (py < dy || py >= dy + ny))
698  gd->linedata[py - 1].flags &= ~~GRID_LINE_WRAPPED;
699 }
700 
701 /* Move a group of cells. */
702 void
703 grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx,
704  u_int bg)
705 {
706  struct grid_line *gl;
707  u_int xx;
708 
709  if (nx == 0 || px == dx)
710  return;
711 
712  if (grid_check_y(gd, __func__, py) != 0)
713  return;
714  gl = &gd->linedata[py];
715 
716  grid_expand_line(gd, py, px + nx, 8);
717  grid_expand_line(gd, py, dx + nx, 8);
718  memmove(&gl->celldata[dx], &gl->celldata[px],
719  nx * sizeof *gl->celldata);
720  if (dx + nx > gl->cellused)
721  gl->cellused = dx + nx;
722 
723  /* Wipe any cells that have been moved. */
724  for (xx = px; xx < px + nx; xx++) {
725  if (xx >= dx && xx < dx + nx)
726  continue;
727  grid_clear_cell(gd, xx, py, bg);
728  }
729 }
730 
731 /* Get ANSI foreground sequence. */
732 static size_t
733 grid_string_cells_fg(const struct grid_cell *gc, int *values)
734 {
735  size_t n;
736  u_char r, g, b;
737 
738  n = 0;
739  if (gc->fg & COLOUR_FLAG_256) {
740  values[n++] = 38;
741  values[n++] = 5;
742  values[n++] = gc->fg & 0xff;
743  } else if (gc->fg & COLOUR_FLAG_RGB) {
744  values[n++] = 38;
745  values[n++] = 2;
746  colour_split_rgb(gc->fg, &r, &g, &b);
747  values[n++] = r;
748  values[n++] = g;
749  values[n++] = b;
750  } else {
751  switch (gc->fg) {
752  case 0:
753  case 1:
754  case 2:
755  case 3:
756  case 4:
757  case 5:
758  case 6:
759  case 7:
760  values[n++] = gc->fg + 30;
761  break;
762  case 8:
763  values[n++] = 39;
764  break;
765  case 90:
766  case 91:
767  case 92:
768  case 93:
769  case 94:
770  case 95:
771  case 96:
772  case 97:
773  values[n++] = gc->fg;
774  break;
775  }
776  }
777  return (n);
778 }
779 
780 /* Get ANSI background sequence. */
781 static size_t
782 grid_string_cells_bg(const struct grid_cell *gc, int *values)
783 {
784  size_t n;
785  u_char r, g, b;
786 
787  n = 0;
788  if (gc->bg & COLOUR_FLAG_256) {
789  values[n++] = 48;
790  values[n++] = 5;
791  values[n++] = gc->bg & 0xff;
792  } else if (gc->bg & COLOUR_FLAG_RGB) {
793  values[n++] = 48;
794  values[n++] = 2;
795  colour_split_rgb(gc->bg, &r, &g, &b);
796  values[n++] = r;
797  values[n++] = g;
798  values[n++] = b;
799  } else {
800  switch (gc->bg) {
801  case 0:
802  case 1:
803  case 2:
804  case 3:
805  case 4:
806  case 5:
807  case 6:
808  case 7:
809  values[n++] = gc->bg + 40;
810  break;
811  case 8:
812  values[n++] = 49;
813  break;
814  case 90:
815  case 91:
816  case 92:
817  case 93:
818  case 94:
819  case 95:
820  case 96:
821  case 97:
822  values[n++] = gc->bg + 10;
823  break;
824  }
825  }
826  return (n);
827 }
828 
829 /*
830  * Returns ANSI code to set particular attributes (colour, bold and so on)
831  * given a current state.
832  */
833 static void
834 grid_string_cells_code(const struct grid_cell *lastgc,
835  const struct grid_cell *gc, char *buf, size_t len, int escape_c0)
836 {
837  int oldc[64], newc[64], s[128];
838  size_t noldc, nnewc, n, i;
839  u_int attr = gc->attr, lastattr = lastgc->attr;
840  char tmp[64];
841 
842  struct {
843  u_int mask;
844  u_int code;
845  } attrs[] = {
846  { GRID_ATTR_BRIGHT, 1 },
847  { GRID_ATTR_DIM, 2 },
848  { GRID_ATTR_ITALICS, 3 },
849  { GRID_ATTR_UNDERSCORE, 4 },
850  { GRID_ATTR_BLINK, 5 },
851  { GRID_ATTR_REVERSE, 7 },
852  { GRID_ATTR_HIDDEN, 8 },
854  { GRID_ATTR_UNDERSCORE_2, 42 },
855  { GRID_ATTR_UNDERSCORE_3, 43 },
856  { GRID_ATTR_UNDERSCORE_4, 44 },
857  { GRID_ATTR_UNDERSCORE_5, 45 },
858  { GRID_ATTR_OVERLINE, 53 },
859  };
860  n = 0;
861 
862  /* If any attribute is removed, begin with 0. */
863  for (i = 0; i < nitems(attrs); i++) {
864  if (!(attr & attrs[i].mask) && (lastattr & attrs[i].mask)) {
865  s[n++] = 0;
866  lastattr &= GRID_ATTR_CHARSET;
867  break;
868  }
869  }
870  /* For each attribute that is newly set, add its code. */
871  for (i = 0; i < nitems(attrs); i++) {
872  if ((attr & attrs[i].mask) && !(lastattr & attrs[i].mask))
873  s[n++] = attrs[i].code;
874  }
875 
876  /* Write the attributes. */
877  *buf = '\0';
878  if (n > 0) {
879  if (escape_c0)
880  strlcat(buf, "\\033[", len);
881  else
882  strlcat(buf, "\033[", len);
883  for (i = 0; i < n; i++) {
884  if (s[i] < 10)
885  xsnprintf(tmp, sizeof tmp, "%d", s[i]);
886  else {
887  xsnprintf(tmp, sizeof tmp, "%d:%d", s[i] / 10,
888  s[i] % 10);
889  }
890  strlcat(buf, tmp, len);
891  if (i + 1 < n)
892  strlcat(buf, ";", len);
893  }
894  strlcat(buf, "m", len);
895  }
896 
897  /* If the foreground colour changed, write its parameters. */
898  nnewc = grid_string_cells_fg(gc, newc);
899  noldc = grid_string_cells_fg(lastgc, oldc);
900  if (nnewc != noldc ||
901  memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 ||
902  (n != 0 && s[0] == 0)) {
903  if (escape_c0)
904  strlcat(buf, "\\033[", len);
905  else
906  strlcat(buf, "\033[", len);
907  for (i = 0; i < nnewc; i++) {
908  if (i + 1 < nnewc)
909  xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
910  else
911  xsnprintf(tmp, sizeof tmp, "%d", newc[i]);
912  strlcat(buf, tmp, len);
913  }
914  strlcat(buf, "m", len);
915  }
916 
917  /* If the background colour changed, append its parameters. */
918  nnewc = grid_string_cells_bg(gc, newc);
919  noldc = grid_string_cells_bg(lastgc, oldc);
920  if (nnewc != noldc ||
921  memcmp(newc, oldc, nnewc * sizeof newc[0]) != 0 ||
922  (n != 0 && s[0] == 0)) {
923  if (escape_c0)
924  strlcat(buf, "\\033[", len);
925  else
926  strlcat(buf, "\033[", len);
927  for (i = 0; i < nnewc; i++) {
928  if (i + 1 < nnewc)
929  xsnprintf(tmp, sizeof tmp, "%d;", newc[i]);
930  else
931  xsnprintf(tmp, sizeof tmp, "%d", newc[i]);
932  strlcat(buf, tmp, len);
933  }
934  strlcat(buf, "m", len);
935  }
936 
937  /* Append shift in/shift out if needed. */
938  if ((attr & GRID_ATTR_CHARSET) && !(lastattr & GRID_ATTR_CHARSET)) {
939  if (escape_c0)
940  strlcat(buf, "\\016", len); /* SO */
941  else
942  strlcat(buf, "\016", len); /* SO */
943  }
944  if (!(attr & GRID_ATTR_CHARSET) && (lastattr & GRID_ATTR_CHARSET)) {
945  if (escape_c0)
946  strlcat(buf, "\\017", len); /* SI */
947  else
948  strlcat(buf, "\017", len); /* SI */
949  }
950 }
951 
952 /* Convert cells into a string. */
953 char *
954 grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx,
955  struct grid_cell **lastgc, int with_codes, int escape_c0, int trim)
956 {
957  struct grid_cell gc;
958  static struct grid_cell lastgc1;
959  const char *data;
960  char *buf, code[128];
961  size_t len, off, size, codelen;
962  u_int xx;
963  const struct grid_line *gl;
964 
965  if (lastgc != NULL && *lastgc == NULL) {
966  memcpy(&lastgc1, &grid_default_cell, sizeof lastgc1);
967  *lastgc = &lastgc1;
968  }
969 
970  len = 128;
971  buf = xmalloc(len);
972  off = 0;
973 
974  gl = grid_peek_line(gd, py);
975  for (xx = px; xx < px + nx; xx++) {
976  if (gl == NULL || xx >= gl->cellsize)
977  break;
978  grid_get_cell(gd, xx, py, &gc);
979  if (gc.flags & GRID_FLAG_PADDING)
980  continue;
981 
982  if (with_codes) {
983  grid_string_cells_code(*lastgc, &gc, code, sizeof code,
984  escape_c0);
985  codelen = strlen(code);
986  memcpy(*lastgc, &gc, sizeof **lastgc);
987  } else
988  codelen = 0;
989 
990  data = gc.data.data;
991  size = gc.data.size;
992  if (escape_c0 && size == 1 && *data == '\\') {
993  data = "\\\\";
994  size = 2;
995  }
996 
997  while (len < off + size + codelen + 1) {
998  buf = xreallocarray(buf, 2, len);
999  len *= 2;
1000  }
1001 
1002  if (codelen != 0) {
1003  memcpy(buf + off, code, codelen);
1004  off += codelen;
1005  }
1006  memcpy(buf + off, data, size);
1007  off += size;
1008  }
1009 
1010  if (trim) {
1011  while (off > 0 && buf[off - 1] == ' ')
1012  off--;
1013  }
1014  buf[off] = '\0';
1015 
1016  return (buf);
1017 }
1018 
1019 /*
1020  * Duplicate a set of lines between two grids. Both source and destination
1021  * should be big enough.
1022  */
1023 void
1024 grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy,
1025  u_int ny)
1026 {
1027  struct grid_line *dstl, *srcl;
1028  u_int yy;
1029 
1030  if (dy + ny > dst->hsize + dst->sy)
1031  ny = dst->hsize + dst->sy - dy;
1032  if (sy + ny > src->hsize + src->sy)
1033  ny = src->hsize + src->sy - sy;
1034  grid_free_lines(dst, dy, ny);
1035 
1036  for (yy = 0; yy < ny; yy++) {
1037  srcl = &src->linedata[sy];
1038  dstl = &dst->linedata[dy];
1039 
1040  memcpy(dstl, srcl, sizeof *dstl);
1041  if (srcl->cellsize != 0) {
1042  dstl->celldata = xreallocarray(NULL,
1043  srcl->cellsize, sizeof *dstl->celldata);
1044  memcpy(dstl->celldata, srcl->celldata,
1045  srcl->cellsize * sizeof *dstl->celldata);
1046  } else
1047  dstl->celldata = NULL;
1048  if (srcl->extdsize != 0) {
1049  dstl->extdsize = srcl->extdsize;
1050  dstl->extddata = xreallocarray(NULL, dstl->extdsize,
1051  sizeof *dstl->extddata);
1052  memcpy(dstl->extddata, srcl->extddata, dstl->extdsize *
1053  sizeof *dstl->extddata);
1054  } else
1055  dstl->extddata = NULL;
1056 
1057  sy++;
1058  dy++;
1059  }
1060 }
1061 
1062 /* Mark line as dead. */
1063 static void
1065 {
1066  memset(gl, 0, sizeof *gl);
1067  gl->flags = GRID_LINE_DEAD;
1068 }
1069 
1070 /* Add lines, return the first new one. */
1071 static struct grid_line *
1072 grid_reflow_add(struct grid *gd, u_int n)
1073 {
1074  struct grid_line *gl;
1075  u_int sy = gd->sy + n;
1076 
1077  gd->linedata = xreallocarray(gd->linedata, sy, sizeof *gd->linedata);
1078  gl = &gd->linedata[gd->sy];
1079  memset(gl, 0, n * (sizeof *gl));
1080  gd->sy = sy;
1081  return (gl);
1082 }
1083 
1084 /* Move a line across. */
1085 static struct grid_line *
1086 grid_reflow_move(struct grid *gd, struct grid_line *from)
1087 {
1088  struct grid_line *to;
1089 
1090  to = grid_reflow_add(gd, 1);
1091  memcpy(to, from, sizeof *to);
1092  grid_reflow_dead(from);
1093  return (to);
1094 }
1095 
1096 /* Join line below onto this one. */
1097 static void
1098 grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy,
1099  u_int width, int already)
1100 {
1101  struct grid_line *gl, *from = NULL;
1102  struct grid_cell gc;
1103  u_int lines, left, i, to, line, want = 0;
1104  u_int at;
1105  int wrapped = 1;
1106 
1107  /*
1108  * Add a new target line.
1109  */
1110  if (!already) {
1111  to = target->sy;
1112  gl = grid_reflow_move(target, &gd->linedata[yy]);
1113  } else {
1114  to = target->sy - 1;
1115  gl = &target->linedata[to];
1116  }
1117  at = gl->cellused;
1118 
1119  /*
1120  * Loop until no more to consume or the target line is full.
1121  */
1122  lines = 0;
1123  for (;;) {
1124  /*
1125  * If this is now the last line, there is nothing more to be
1126  * done.
1127  */
1128  if (yy + 1 + lines == gd->hsize + gd->sy)
1129  break;
1130  line = yy + 1 + lines;
1131 
1132  /* If the next line is empty, skip it. */
1133  if (~gd->linedata[line].flags & GRID_LINE_WRAPPED)
1134  wrapped = 0;
1135  if (gd->linedata[line].cellused == 0) {
1136  if (!wrapped)
1137  break;
1138  lines++;
1139  continue;
1140  }
1141 
1142  /*
1143  * Is the destination line now full? Copy the first character
1144  * separately because we need to leave "from" set to the last
1145  * line if this line is full.
1146  */
1147  grid_get_cell1(&gd->linedata[line], 0, &gc);
1148  if (width + gc.data.width > sx)
1149  break;
1150  width += gc.data.width;
1151  grid_set_cell(target, at, to, &gc);
1152  at++;
1153 
1154  /* Join as much more as possible onto the current line. */
1155  from = &gd->linedata[line];
1156  for (want = 1; want < from->cellused; want++) {
1157  grid_get_cell1(from, want, &gc);
1158  if (width + gc.data.width > sx)
1159  break;
1160  width += gc.data.width;
1161 
1162  grid_set_cell(target, at, to, &gc);
1163  at++;
1164  }
1165  lines++;
1166 
1167  /*
1168  * If this line wasn't wrapped or we didn't consume the entire
1169  * line, don't try to join any further lines.
1170  */
1171  if (!wrapped || want != from->cellused || width == sx)
1172  break;
1173  }
1174  if (lines == 0)
1175  return;
1176 
1177  /*
1178  * If we didn't consume the entire final line, then remove what we did
1179  * consume. If we consumed the entire line and it wasn't wrapped,
1180  * remove the wrap flag from this line.
1181  */
1182  left = from->cellused - want;
1183  if (left != 0) {
1184  grid_move_cells(gd, 0, want, yy + lines, left, 8);
1185  from->cellsize = from->cellused = left;
1186  lines--;
1187  } else if (!wrapped)
1188  gl->flags &= ~~GRID_LINE_WRAPPED;
1189 
1190  /* Remove the lines that were completely consumed. */
1191  for (i = yy + 1; i < yy + 1 + lines; i++) {
1192  free(gd->linedata[i].celldata);
1193  free(gd->linedata[i].extddata);
1194  grid_reflow_dead(&gd->linedata[i]);
1195  }
1196 
1197  /* Adjust scroll position. */
1198  if (gd->hscrolled > to + lines)
1199  gd->hscrolled -= lines;
1200  else if (gd->hscrolled > to)
1201  gd->hscrolled = to;
1202 }
1203 
1204 /* Split this line into several new ones */
1205 static void
1206 grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy,
1207  u_int at)
1208 {
1209  struct grid_line *gl = &gd->linedata[yy], *first;
1210  struct grid_cell gc;
1211  u_int line, lines, width, i, xx;
1212  u_int used = gl->cellused;
1213  int flags = gl->flags;
1214 
1215  /* How many lines do we need to insert? We know we need at least two. */
1216  if (~gl->flags & GRID_LINE_EXTENDED)
1217  lines = 1 + (gl->cellused - 1) / sx;
1218  else {
1219  lines = 2;
1220  width = 0;
1221  for (i = at; i < used; i++) {
1222  grid_get_cell1(gl, i, &gc);
1223  if (width + gc.data.width > sx) {
1224  lines++;
1225  width = 0;
1226  }
1227  width += gc.data.width;
1228  }
1229  }
1230 
1231  /* Insert new lines. */
1232  line = target->sy + 1;
1233  first = grid_reflow_add(target, lines);
1234 
1235  /* Copy sections from the original line. */
1236  width = 0;
1237  xx = 0;
1238  for (i = at; i < used; i++) {
1239  grid_get_cell1(gl, i, &gc);
1240  if (width + gc.data.width > sx) {
1241  target->linedata[line].flags |= GRID_LINE_WRAPPED;
1242 
1243  line++;
1244  width = 0;
1245  xx = 0;
1246  }
1247  width += gc.data.width;
1248  grid_set_cell(target, xx, line, &gc);
1249  xx++;
1250  }
1251  if (flags & GRID_LINE_WRAPPED)
1252  target->linedata[line].flags |= GRID_LINE_WRAPPED;
1253 
1254  /* Move the remainder of the original line. */
1255  gl->cellsize = gl->cellused = at;
1256  gl->flags |= GRID_LINE_WRAPPED;
1257  memcpy(first, gl, sizeof *first);
1258  grid_reflow_dead(gl);
1259 
1260  /* Adjust the scroll position. */
1261  if (yy <= gd->hscrolled)
1262  gd->hscrolled += lines - 1;
1263 
1264  /*
1265  * If the original line had the wrapped flag and there is still space
1266  * in the last new line, try to join with the next lines.
1267  */
1268  if (width < sx && (flags & GRID_LINE_WRAPPED))
1269  grid_reflow_join(target, gd, sx, yy, width, 1);
1270 }
1271 
1272 /* Reflow lines on grid to new width. */
1273 void
1274 grid_reflow(struct grid *gd, u_int sx)
1275 {
1276  struct grid *target;
1277  struct grid_line *gl;
1278  struct grid_cell gc;
1279  u_int yy, width, i, at;
1280 
1281  /*
1282  * Create a destination grid. This is just used as a container for the
1283  * line data and may not be fully valid.
1284  */
1285  target = grid_create(gd->sx, 0, 0);
1286 
1287  /*
1288  * Loop over each source line.
1289  */
1290  for (yy = 0; yy < gd->hsize + gd->sy; yy++) {
1291  gl = &gd->linedata[yy];
1292  if (gl->flags & GRID_LINE_DEAD)
1293  continue;
1294 
1295  /*
1296  * Work out the width of this line. at is the point at which
1297  * the available width is hit, and width is the full line
1298  * width.
1299  */
1300  at = width = 0;
1301  if (~gl->flags & GRID_LINE_EXTENDED) {
1302  width = gl->cellused;
1303  if (width > sx)
1304  at = sx;
1305  else
1306  at = width;
1307  } else {
1308  for (i = 0; i < gl->cellused; i++) {
1309  grid_get_cell1(gl, i, &gc);
1310  if (at == 0 && width + gc.data.width > sx)
1311  at = i;
1312  width += gc.data.width;
1313  }
1314  }
1315 
1316  /*
1317  * If the line is exactly right, just move it across
1318  * unchanged.
1319  */
1320  if (width == sx) {
1321  grid_reflow_move(target, gl);
1322  continue;
1323  }
1324 
1325  /*
1326  * If the line is too big, it needs to be split, whether or not
1327  * it was previously wrapped.
1328  */
1329  if (width > sx) {
1330  grid_reflow_split(target, gd, sx, yy, at);
1331  continue;
1332  }
1333 
1334  /*
1335  * If the line was previously wrapped, join as much as possible
1336  * of the next line.
1337  */
1338  if (gl->flags & GRID_LINE_WRAPPED)
1339  grid_reflow_join(target, gd, sx, yy, width, 0);
1340  else
1341  grid_reflow_move(target, gl);
1342  }
1343 
1344  /*
1345  * Replace the old grid with the new.
1346  */
1347  if (target->sy < gd->sy)
1348  grid_reflow_add(target, gd->sy - target->sy);
1349  gd->hsize = target->sy - gd->sy;
1350  if (gd->hscrolled > gd->hsize)
1351  gd->hscrolled = gd->hsize;
1352  free(gd->linedata);
1353  gd->linedata = target->linedata;
1354  free(target);
1355 }
1356 
1357 /* Convert to position based on wrapped lines. */
1358 void
1359 grid_wrap_position(struct grid *gd, u_int px, u_int py, u_int *wx, u_int *wy)
1360 {
1361  u_int ax = 0, ay = 0, yy;
1362 
1363  for (yy = 0; yy < py; yy++) {
1364  if (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
1365  ax += gd->linedata[yy].cellused;
1366  else {
1367  ax = 0;
1368  ay++;
1369  }
1370  }
1371  if (px >= gd->linedata[yy].cellused)
1372  ax = UINT_MAX;
1373  else
1374  ax += px;
1375  *wx = ax;
1376  *wy = ay;
1377 }
1378 
1379 /* Convert position based on wrapped lines back. */
1380 void
1381 grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
1382 {
1383  u_int yy, ay = 0;
1384 
1385  for (yy = 0; yy < gd->hsize + gd->sy - 1; yy++) {
1386  if (ay == wy)
1387  break;
1388  if (~gd->linedata[yy].flags & GRID_LINE_WRAPPED)
1389  ay++;
1390  }
1391 
1392  /*
1393  * yy is now 0 on the unwrapped line which contains wx. Walk forwards
1394  * until we find the end or the line now containing wx.
1395  */
1396  if (wx == UINT_MAX) {
1397  while (gd->linedata[yy].flags & GRID_LINE_WRAPPED)
1398  yy++;
1399  wx = gd->linedata[yy].cellused;
1400  } else {
1401  while (gd->linedata[yy].flags & GRID_LINE_WRAPPED) {
1402  if (wx < gd->linedata[yy].cellused)
1403  break;
1404  wx -= gd->linedata[yy].cellused;
1405  yy++;
1406  }
1407  }
1408  *px = wx;
1409  *py = yy;
1410 }
1411 
1412 /* Get length of line. */
1413 u_int
1414 grid_line_length(struct grid *gd, u_int py)
1415 {
1416  struct grid_cell gc;
1417  u_int px;
1418 
1419  px = grid_get_line(gd, py)->cellsize;
1420  if (px > gd->sx)
1421  px = gd->sx;
1422  while (px > 0) {
1423  grid_get_cell(gd, px - 1, py, &gc);
1424  if ((gc.flags & GRID_FLAG_PADDING) ||
1425  gc.data.size != 1 ||
1426  *gc.data.data != ' ')
1427  break;
1428  px--;
1429  }
1430  return (px);
1431 }
void colour_split_rgb(int c, u_char *r, u_char *g, u_char *b)
Definition: colour.c:101
size_t strlcat(char *, const char *, size_t)
static void grid_free_lines(struct grid *gd, u_int py, u_int ny)
Definition: grid.c:262
static struct grid_extd_entry * grid_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce, const struct grid_cell *gc)
Definition: grid.c:112
void grid_clear_history(struct grid *gd)
Definition: grid.c:407
const struct grid_cell grid_default_cell
Definition: grid.c:39
static void grid_compact_line(struct grid_line *gl)
Definition: grid.c:139
int grid_compare(struct grid *ga, struct grid *gb)
Definition: grid.c:310
static void grid_expand_line(struct grid *gd, u_int py, u_int sx, u_int bg)
Definition: grid.c:453
static int grid_need_extended_cell(const struct grid_cell_entry *gce, const struct grid_cell *gc)
Definition: grid.c:80
static void grid_store_cell(struct grid_cell_entry *gce, const struct grid_cell *gc, u_char c)
Definition: grid.c:61
void grid_set_cells(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc, const char *s, size_t slen)
Definition: grid.c:570
void grid_clear_lines(struct grid *gd, u_int py, u_int ny, u_int bg)
Definition: grid.c:639
static void grid_trim_history(struct grid *gd, u_int ny)
Definition: grid.c:337
static struct grid_line * grid_reflow_add(struct grid *gd, u_int n)
Definition: grid.c:1072
void grid_scroll_history_region(struct grid *gd, u_int upper, u_int lower, u_int bg)
Definition: grid.c:420
void grid_empty_line(struct grid *gd, u_int py, u_int bg)
Definition: grid.c:477
void grid_destroy(struct grid *gd)
Definition: grid.c:299
static void grid_get_cell1(struct grid_line *gl, u_int px, struct grid_cell *gc)
Definition: grid.c:495
static const struct grid_cell_entry grid_cleared_entry
Definition: grid.c:55
static void grid_reflow_dead(struct grid_line *gl)
Definition: grid.c:1064
static size_t grid_string_cells_fg(const struct grid_cell *gc, int *values)
Definition: grid.c:733
int grid_cells_look_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
Definition: grid.c:228
void grid_adjust_lines(struct grid *gd, u_int lines)
Definition: grid.c:188
void grid_duplicate_lines(struct grid *dst, u_int dy, struct grid *src, u_int sy, u_int ny)
Definition: grid.c:1024
static void grid_reflow_split(struct grid *target, struct grid *gd, u_int sx, u_int yy, u_int at)
Definition: grid.c:1206
static void grid_free_line(struct grid *gd, u_int py)
Definition: grid.c:252
void grid_get_cell(struct grid *gd, u_int px, u_int py, struct grid_cell *gc)
Definition: grid.c:529
static const struct grid_cell grid_padding_cell
Definition: grid.c:47
char * grid_string_cells(struct grid *gd, u_int px, u_int py, u_int nx, struct grid_cell **lastgc, int with_codes, int escape_c0, int trim)
Definition: grid.c:954
static const struct grid_cell grid_cleared_cell
Definition: grid.c:52
static int grid_check_y(struct grid *gd, const char *from, u_int py)
Definition: grid.c:217
struct grid_line * grid_get_line(struct grid *gd, u_int line)
Definition: grid.c:181
void grid_set_cell(struct grid *gd, u_int px, u_int py, const struct grid_cell *gc)
Definition: grid.c:540
static struct grid_line * grid_reflow_move(struct grid *gd, struct grid_line *from)
Definition: grid.c:1086
static size_t grid_string_cells_bg(const struct grid_cell *gc, int *values)
Definition: grid.c:782
struct grid * grid_create(u_int sx, u_int sy, u_int hlimit)
Definition: grid.c:272
void grid_remove_history(struct grid *gd, u_int ny)
Definition: grid.c:375
static void grid_clear_cell(struct grid *gd, u_int px, u_int py, u_int bg)
Definition: grid.c:195
u_int grid_line_length(struct grid *gd, u_int py)
Definition: grid.c:1414
static void grid_get_extended_cell(struct grid_line *gl, struct grid_cell_entry *gce, int flags)
Definition: grid.c:98
void grid_scroll_history(struct grid *gd, u_int bg)
Definition: grid.c:391
int grid_cells_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
Definition: grid.c:239
static void grid_reflow_join(struct grid *target, struct grid *gd, u_int sx, u_int yy, u_int width, int already)
Definition: grid.c:1098
void grid_reflow(struct grid *gd, u_int sx)
Definition: grid.c:1274
void grid_move_cells(struct grid *gd, u_int dx, u_int px, u_int py, u_int nx, u_int bg)
Definition: grid.c:703
void grid_set_padding(struct grid *gd, u_int px, u_int py)
Definition: grid.c:563
void grid_unwrap_position(struct grid *gd, u_int *px, u_int *py, u_int wx, u_int wy)
Definition: grid.c:1381
void grid_clear(struct grid *gd, u_int px, u_int py, u_int nx, u_int ny, u_int bg)
Definition: grid.c:599
const struct grid_line * grid_peek_line(struct grid *gd, u_int py)
Definition: grid.c:486
void grid_collect_history(struct grid *gd)
Definition: grid.c:349
static void grid_string_cells_code(const struct grid_cell *lastgc, const struct grid_cell *gc, char *buf, size_t len, int escape_c0)
Definition: grid.c:834
void grid_wrap_position(struct grid *gd, u_int px, u_int py, u_int *wx, u_int *wy)
Definition: grid.c:1359
void grid_move_lines(struct grid *gd, u_int dy, u_int py, u_int ny, u_int bg)
Definition: grid.c:661
void fatalx(const char *msg,...)
Definition: log.c:159
void log_debug(const char *msg,...)
Definition: log.c:130
#define nitems(_a)
Definition: tmux.h:708
u_char flags
Definition: tmux.h:709
u_char data
Definition: tmux.h:716
u_int offset
Definition: tmux.h:711
u_char flags
Definition: tmux.h:691
int us
Definition: tmux.h:694
int bg
Definition: tmux.h:693
struct utf8_data data
Definition: tmux.h:689
u_short attr
Definition: tmux.h:690
int fg
Definition: tmux.h:692
Definition: tmux.h:698
int bg
Definition: tmux.h:703
u_short attr
Definition: tmux.h:700
u_char flags
Definition: tmux.h:701
int fg
Definition: tmux.h:702
utf8_char data
Definition: tmux.h:699
int us
Definition: tmux.h:704
u_int extdsize
Definition: tmux.h:727
u_int cellused
Definition: tmux.h:723
struct grid_cell_entry * celldata
Definition: tmux.h:725
struct grid_extd_entry * extddata
Definition: tmux.h:728
u_int cellsize
Definition: tmux.h:724
int flags
Definition: tmux.h:730
Definition: tmux.h:734
u_int hsize
Definition: tmux.h:742
u_int sy
Definition: tmux.h:739
u_int hlimit
Definition: tmux.h:743
struct grid_line * linedata
Definition: tmux.h:745
u_int hscrolled
Definition: tmux.h:741
int flags
Definition: tmux.h:735
u_int sx
Definition: tmux.h:738
u_char data[21]
Definition: tmux.h:629
u_char size
Definition: tmux.h:632
u_char width
Definition: tmux.h:634
#define GRID_FLAG_FG256
Definition: tmux.h:674
#define GRID_ATTR_UNDERSCORE_5
Definition: tmux.h:662
#define GRID_FLAG_CLEARED
Definition: tmux.h:680
#define GRID_FLAG_EXTENDED
Definition: tmux.h:677
u_int utf8_char
Definition: tmux.h:620
#define GRID_ATTR_CHARSET
Definition: tmux.h:657
#define GRID_ATTR_BLINK
Definition: tmux.h:653
#define GRID_ATTR_STRIKETHROUGH
Definition: tmux.h:658
#define COLOUR_DEFAULT(c)
Definition: tmux.h:647
#define GRID_LINE_DEAD
Definition: tmux.h:685
enum utf8_state utf8_from_data(const struct utf8_data *, utf8_char *)
Definition: utf8.c:127
utf8_char utf8_build_one(u_char)
Definition: utf8.c:186
#define GRID_ATTR_DIM
Definition: tmux.h:651
void utf8_to_data(utf8_char, struct utf8_data *)
Definition: utf8.c:159
#define GRID_ATTR_UNDERSCORE_2
Definition: tmux.h:659
#define GRID_ATTR_UNDERSCORE
Definition: tmux.h:652
void utf8_set(struct utf8_data *, u_char)
Definition: utf8.c:193
#define GRID_ATTR_BRIGHT
Definition: tmux.h:650
#define GRID_LINE_EXTENDED
Definition: tmux.h:684
#define GRID_FLAG_PADDING
Definition: tmux.h:676
#define GRID_HISTORY
Definition: tmux.h:736
#define GRID_FLAG_BG256
Definition: tmux.h:675
#define GRID_ATTR_REVERSE
Definition: tmux.h:654
#define COLOUR_FLAG_RGB
Definition: tmux.h:644
#define GRID_ATTR_HIDDEN
Definition: tmux.h:655
#define GRID_ATTR_UNDERSCORE_3
Definition: tmux.h:660
#define GRID_LINE_WRAPPED
Definition: tmux.h:683
#define GRID_ATTR_UNDERSCORE_4
Definition: tmux.h:661
#define GRID_ATTR_ITALICS
Definition: tmux.h:656
#define GRID_ATTR_OVERLINE
Definition: tmux.h:663
#define COLOUR_FLAG_256
Definition: tmux.h:643
void * xmalloc(size_t size)
Definition: xmalloc.c:27
int xsnprintf(char *str, size_t len, const char *fmt,...)
Definition: xmalloc.c:135
void * xreallocarray(void *ptr, size_t nmemb, size_t size)
Definition: xmalloc.c:61
void * xcalloc(size_t nmemb, size_t size)
Definition: xmalloc.c:41