Mercurial > vim
comparison src/terminal.c @ 12009:0d9bfdb3f6f7 v8.0.0885
patch 8.0.0885: terminal window scrollback is stored inefficiently
commit https://github.com/vim/vim/commit/33a43bee9cdc62f9cd0999eb23c6eca01b4d2d67
Author: Bram Moolenaar <Bram@vim.org>
Date: Sun Aug 6 21:36:22 2017 +0200
patch 8.0.0885: terminal window scrollback is stored inefficiently
Problem: Terminal window scrollback is stored inefficiently.
Solution: Store the text in the Vim buffer.
author | Christian Brabandt <cb@256bit.org> |
---|---|
date | Sun, 06 Aug 2017 21:45:03 +0200 |
parents | 64b822c4f7ae |
children | 1f4e7361ce89 |
comparison
equal
deleted
inserted
replaced
12008:41ab44ba9753 | 12009:0d9bfdb3f6f7 |
---|---|
34 * | 34 * |
35 * When the job ends the text is put in a buffer. Redrawing then happens from | 35 * When the job ends the text is put in a buffer. Redrawing then happens from |
36 * that buffer, attributes come from the scrollback buffer tl_scrollback. | 36 * that buffer, attributes come from the scrollback buffer tl_scrollback. |
37 * | 37 * |
38 * TODO: | 38 * TODO: |
39 * - For the scrollback buffer store lines in the buffer, only attributes in | |
40 * tl_scrollback. | |
41 * - When the job ends: | 39 * - When the job ends: |
42 * - Need an option or argument to drop the window+buffer right away, to be | 40 * - Need an option or argument to drop the window+buffer right away, to be |
43 * used for a shell or Vim. 'termfinish'; "close", "open" (open window when | 41 * used for a shell or Vim. 'termfinish'; "close", "open" (open window when |
44 * job finishes). | 42 * job finishes). |
45 * - add option values to the command: | 43 * - add option values to the command: |
95 # define MAX(x,y) ((x) > (y) ? (x) : (y)) | 93 # define MAX(x,y) ((x) > (y) ? (x) : (y)) |
96 #endif | 94 #endif |
97 | 95 |
98 #include "libvterm/include/vterm.h" | 96 #include "libvterm/include/vterm.h" |
99 | 97 |
98 /* This is VTermScreenCell without the characters, thus much smaller. */ | |
99 typedef struct { | |
100 VTermScreenCellAttrs attrs; | |
101 char width; | |
102 VTermColor fg, bg; | |
103 } cellattr_T; | |
104 | |
100 typedef struct sb_line_S { | 105 typedef struct sb_line_S { |
101 int sb_cols; /* can differ per line */ | 106 int sb_cols; /* can differ per line */ |
102 VTermScreenCell *sb_cells; /* allocated */ | 107 cellattr_T *sb_cells; /* allocated */ |
103 } sb_line_T; | 108 } sb_line_T; |
104 | 109 |
105 /* typedef term_T in structs.h */ | 110 /* typedef term_T in structs.h */ |
106 struct terminal_S { | 111 struct terminal_S { |
107 term_T *tl_next; | 112 term_T *tl_next; |
686 | 691 |
687 /* | 692 /* |
688 * Add the last line of the scrollback buffer to the buffer in the window. | 693 * Add the last line of the scrollback buffer to the buffer in the window. |
689 */ | 694 */ |
690 static void | 695 static void |
691 add_scrollback_line_to_buffer(term_T *term) | 696 add_scrollback_line_to_buffer(term_T *term, char_u *text, int len) |
692 { | 697 { |
693 linenr_T lnum = term->tl_scrollback.ga_len - 1; | 698 linenr_T lnum = term->tl_scrollback.ga_len - 1; |
694 sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data + lnum; | 699 |
695 garray_T ga; | 700 ml_append_buf(term->tl_buffer, lnum, text, len + 1, FALSE); |
696 int c; | |
697 int col; | |
698 int i; | |
699 | |
700 ga_init2(&ga, 1, 100); | |
701 for (col = 0; col < line->sb_cols; col += line->sb_cells[col].width) | |
702 { | |
703 if (ga_grow(&ga, MB_MAXBYTES) == FAIL) | |
704 goto failed; | |
705 for (i = 0; (c = line->sb_cells[col].chars[i]) > 0 || i == 0; ++i) | |
706 ga.ga_len += mb_char2bytes(c == NUL ? ' ' : c, | |
707 (char_u *)ga.ga_data + ga.ga_len); | |
708 } | |
709 if (ga_grow(&ga, 1) == FAIL) | |
710 goto failed; | |
711 *((char_u *)ga.ga_data + ga.ga_len) = NUL; | |
712 ml_append_buf(term->tl_buffer, lnum, ga.ga_data, ga.ga_len + 1, FALSE); | |
713 | |
714 if (lnum == 0) | 701 if (lnum == 0) |
715 { | 702 { |
716 /* Delete the empty line that was in the empty buffer. */ | 703 /* Delete the empty line that was in the empty buffer. */ |
717 curbuf = term->tl_buffer; | 704 curbuf = term->tl_buffer; |
718 ml_delete(2, FALSE); | 705 ml_delete(2, FALSE); |
719 curbuf = curwin->w_buffer; | 706 curbuf = curwin->w_buffer; |
720 } | 707 } |
721 | |
722 failed: | |
723 ga_clear(&ga); | |
724 } | 708 } |
725 | 709 |
726 /* | 710 /* |
727 * Add the current lines of the terminal to scrollback and to the buffer. | 711 * Add the current lines of the terminal to scrollback and to the buffer. |
728 * Called after the job has ended and when switching to Terminal mode. | 712 * Called after the job has ended and when switching to Terminal-Normal mode. |
729 */ | 713 */ |
730 static void | 714 static void |
731 move_terminal_to_buffer(term_T *term) | 715 move_terminal_to_buffer(term_T *term) |
732 { | 716 { |
733 win_T *wp; | 717 win_T *wp; |
734 int len; | 718 int len; |
735 int lines_skipped = 0; | 719 int lines_skipped = 0; |
736 VTermPos pos; | 720 VTermPos pos; |
737 VTermScreenCell cell; | 721 VTermScreenCell cell; |
738 VTermScreenCell *p; | 722 cellattr_T *p; |
739 VTermScreen *screen; | 723 VTermScreen *screen; |
740 | 724 |
741 if (term->tl_vterm == NULL) | 725 if (term->tl_vterm == NULL) |
742 return; | 726 return; |
743 screen = vterm_obtain_screen(term->tl_vterm); | 727 screen = vterm_obtain_screen(term->tl_vterm); |
764 | 748 |
765 line->sb_cols = 0; | 749 line->sb_cols = 0; |
766 line->sb_cells = NULL; | 750 line->sb_cells = NULL; |
767 ++term->tl_scrollback.ga_len; | 751 ++term->tl_scrollback.ga_len; |
768 | 752 |
769 add_scrollback_line_to_buffer(term); | 753 add_scrollback_line_to_buffer(term, (char_u *)"", 0); |
770 } | 754 } |
771 } | 755 } |
772 | 756 |
773 p = (VTermScreenCell *)alloc((int)sizeof(VTermScreenCell) * len); | 757 p = (cellattr_T *)alloc((int)sizeof(cellattr_T) * len); |
774 if (p != NULL && ga_grow(&term->tl_scrollback, 1) == OK) | 758 if (p != NULL && ga_grow(&term->tl_scrollback, 1) == OK) |
775 { | 759 { |
776 sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data | 760 garray_T ga; |
761 int width; | |
762 sb_line_T *line = (sb_line_T *)term->tl_scrollback.ga_data | |
777 + term->tl_scrollback.ga_len; | 763 + term->tl_scrollback.ga_len; |
778 | 764 |
779 for (pos.col = 0; pos.col < len; ++pos.col) | 765 ga_init2(&ga, 1, 100); |
766 for (pos.col = 0; pos.col < len; pos.col += width) | |
780 { | 767 { |
781 if (vterm_screen_get_cell(screen, pos, &cell) == 0) | 768 if (vterm_screen_get_cell(screen, pos, &cell) == 0) |
782 vim_memset(p + pos.col, 0, sizeof(cell)); | 769 { |
770 width = 1; | |
771 vim_memset(p + pos.col, 0, sizeof(cellattr_T)); | |
772 if (ga_grow(&ga, 1) == OK) | |
773 ga.ga_len += mb_char2bytes(' ', | |
774 (char_u *)ga.ga_data + ga.ga_len); | |
775 } | |
783 else | 776 else |
784 p[pos.col] = cell; | 777 { |
778 width = cell.width; | |
779 | |
780 p[pos.col].width = cell.width; | |
781 p[pos.col].attrs = cell.attrs; | |
782 p[pos.col].fg = cell.fg; | |
783 p[pos.col].bg = cell.bg; | |
784 | |
785 if (ga_grow(&ga, MB_MAXBYTES) == OK) | |
786 { | |
787 int i; | |
788 int c; | |
789 | |
790 for (i = 0; (c = cell.chars[i]) > 0 || i == 0; ++i) | |
791 ga.ga_len += mb_char2bytes(c == NUL ? ' ' : c, | |
792 (char_u *)ga.ga_data + ga.ga_len); | |
793 } | |
794 } | |
785 } | 795 } |
786 line->sb_cols = len; | 796 line->sb_cols = len; |
787 line->sb_cells = p; | 797 line->sb_cells = p; |
788 ++term->tl_scrollback.ga_len; | 798 ++term->tl_scrollback.ga_len; |
789 | 799 |
790 add_scrollback_line_to_buffer(term); | 800 if (ga_grow(&ga, 1) == FAIL) |
801 add_scrollback_line_to_buffer(term, (char_u *)"", 0); | |
802 else | |
803 { | |
804 *((char_u *)ga.ga_data + ga.ga_len) = NUL; | |
805 add_scrollback_line_to_buffer(term, ga.ga_data, ga.ga_len); | |
806 } | |
807 ga_clear(&ga); | |
791 } | 808 } |
792 else | 809 else |
793 vim_free(p); | 810 vim_free(p); |
794 } | 811 } |
795 } | 812 } |
1310 handle_pushline(int cols, const VTermScreenCell *cells, void *user) | 1327 handle_pushline(int cols, const VTermScreenCell *cells, void *user) |
1311 { | 1328 { |
1312 term_T *term = (term_T *)user; | 1329 term_T *term = (term_T *)user; |
1313 | 1330 |
1314 /* TODO: Limit the number of lines that are stored. */ | 1331 /* TODO: Limit the number of lines that are stored. */ |
1315 /* TODO: put the text in the buffer. */ | |
1316 if (ga_grow(&term->tl_scrollback, 1) == OK) | 1332 if (ga_grow(&term->tl_scrollback, 1) == OK) |
1317 { | 1333 { |
1318 VTermScreenCell *p = NULL; | 1334 cellattr_T *p = NULL; |
1319 int len = 0; | 1335 int len = 0; |
1320 int i; | 1336 int i; |
1337 int c; | |
1338 int col; | |
1321 sb_line_T *line; | 1339 sb_line_T *line; |
1340 garray_T ga; | |
1322 | 1341 |
1323 /* do not store empty cells at the end */ | 1342 /* do not store empty cells at the end */ |
1324 for (i = 0; i < cols; ++i) | 1343 for (i = 0; i < cols; ++i) |
1325 if (cells[i].chars[0] != 0) | 1344 if (cells[i].chars[0] != 0) |
1326 len = i + 1; | 1345 len = i + 1; |
1327 | 1346 |
1328 if (len > 0) | 1347 if (len > 0) |
1329 p = (VTermScreenCell *)alloc((int)sizeof(VTermScreenCell) * len); | 1348 p = (cellattr_T *)alloc((int)sizeof(cellattr_T) * len); |
1330 if (p != NULL) | 1349 if (p != NULL) |
1331 mch_memmove(p, cells, sizeof(VTermScreenCell) * len); | 1350 { |
1351 ga_init2(&ga, 1, 100); | |
1352 for (col = 0; col < len; col += cells[col].width) | |
1353 { | |
1354 if (ga_grow(&ga, MB_MAXBYTES) == FAIL) | |
1355 { | |
1356 ga.ga_len = 0; | |
1357 break; | |
1358 } | |
1359 for (i = 0; (c = cells[col].chars[i]) > 0 || i == 0; ++i) | |
1360 ga.ga_len += mb_char2bytes(c == NUL ? ' ' : c, | |
1361 (char_u *)ga.ga_data + ga.ga_len); | |
1362 p[col].width = cells[col].width; | |
1363 p[col].attrs = cells[col].attrs; | |
1364 p[col].fg = cells[col].fg; | |
1365 p[col].bg = cells[col].bg; | |
1366 } | |
1367 } | |
1368 if (ga_grow(&ga, 1) == FAIL) | |
1369 add_scrollback_line_to_buffer(term, (char_u *)"", 0); | |
1370 else | |
1371 { | |
1372 *((char_u *)ga.ga_data + ga.ga_len) = NUL; | |
1373 add_scrollback_line_to_buffer(term, ga.ga_data, ga.ga_len); | |
1374 } | |
1375 ga_clear(&ga); | |
1332 | 1376 |
1333 line = (sb_line_T *)term->tl_scrollback.ga_data | 1377 line = (sb_line_T *)term->tl_scrollback.ga_data |
1334 + term->tl_scrollback.ga_len; | 1378 + term->tl_scrollback.ga_len; |
1335 line->sb_cols = len; | 1379 line->sb_cols = len; |
1336 line->sb_cells = p; | 1380 line->sb_cells = p; |
1337 ++term->tl_scrollback.ga_len; | 1381 ++term->tl_scrollback.ga_len; |
1338 ++term->tl_scrollback_scrolled; | 1382 ++term->tl_scrollback_scrolled; |
1339 | |
1340 add_scrollback_line_to_buffer(term); | |
1341 } | 1383 } |
1342 return 0; /* ignored */ | 1384 return 0; /* ignored */ |
1343 } | 1385 } |
1344 | 1386 |
1345 static VTermScreenCallbacks screen_callbacks = { | 1387 static VTermScreenCallbacks screen_callbacks = { |
1508 | 1550 |
1509 /* | 1551 /* |
1510 * Convert the attributes of a vterm cell into an attribute index. | 1552 * Convert the attributes of a vterm cell into an attribute index. |
1511 */ | 1553 */ |
1512 static int | 1554 static int |
1513 cell2attr(VTermScreenCell *cell) | 1555 cell2attr(VTermScreenCellAttrs cellattrs, VTermColor cellfg, VTermColor cellbg) |
1514 { | 1556 { |
1515 int attr = 0; | 1557 int attr = 0; |
1516 | 1558 |
1517 if (cell->attrs.bold) | 1559 if (cellattrs.bold) |
1518 attr |= HL_BOLD; | 1560 attr |= HL_BOLD; |
1519 if (cell->attrs.underline) | 1561 if (cellattrs.underline) |
1520 attr |= HL_UNDERLINE; | 1562 attr |= HL_UNDERLINE; |
1521 if (cell->attrs.italic) | 1563 if (cellattrs.italic) |
1522 attr |= HL_ITALIC; | 1564 attr |= HL_ITALIC; |
1523 if (cell->attrs.strike) | 1565 if (cellattrs.strike) |
1524 attr |= HL_STANDOUT; | 1566 attr |= HL_STANDOUT; |
1525 if (cell->attrs.reverse) | 1567 if (cellattrs.reverse) |
1526 attr |= HL_INVERSE; | 1568 attr |= HL_INVERSE; |
1527 | 1569 |
1528 #ifdef FEAT_GUI | 1570 #ifdef FEAT_GUI |
1529 if (gui.in_use) | 1571 if (gui.in_use) |
1530 { | 1572 { |
1531 guicolor_T fg, bg; | 1573 guicolor_T fg, bg; |
1532 | 1574 |
1533 fg = gui_mch_get_rgb_color(cell->fg.red, cell->fg.green, cell->fg.blue); | 1575 fg = gui_mch_get_rgb_color(cellfg.red, cellfg.green, cellfg.blue); |
1534 bg = gui_mch_get_rgb_color(cell->bg.red, cell->bg.green, cell->bg.blue); | 1576 bg = gui_mch_get_rgb_color(cellbg.red, cellbg.green, cellbg.blue); |
1535 return get_gui_attr_idx(attr, fg, bg); | 1577 return get_gui_attr_idx(attr, fg, bg); |
1536 } | 1578 } |
1537 else | 1579 else |
1538 #endif | 1580 #endif |
1539 #ifdef FEAT_TERMGUICOLORS | 1581 #ifdef FEAT_TERMGUICOLORS |
1540 if (p_tgc) | 1582 if (p_tgc) |
1541 { | 1583 { |
1542 guicolor_T fg, bg; | 1584 guicolor_T fg, bg; |
1543 | 1585 |
1544 fg = gui_get_rgb_color_cmn(cell->fg.red, cell->fg.green, cell->fg.blue); | 1586 fg = gui_get_rgb_color_cmn(cellfg.red, cellfg.green, cellfg.blue); |
1545 bg = gui_get_rgb_color_cmn(cell->bg.red, cell->bg.green, cell->bg.blue); | 1587 bg = gui_get_rgb_color_cmn(cellbg.red, cellbg.green, cellbg.blue); |
1546 | 1588 |
1547 return get_tgc_attr_idx(attr, fg, bg); | 1589 return get_tgc_attr_idx(attr, fg, bg); |
1548 } | 1590 } |
1549 else | 1591 else |
1550 #endif | 1592 #endif |
1551 { | 1593 { |
1552 int bold = MAYBE; | 1594 int bold = MAYBE; |
1553 int fg = color2index(&cell->fg, TRUE, &bold); | 1595 int fg = color2index(&cellfg, TRUE, &bold); |
1554 int bg = color2index(&cell->bg, FALSE, &bold); | 1596 int bg = color2index(&cellbg, FALSE, &bold); |
1555 | 1597 |
1556 /* with 8 colors set the bold attribute to get a bright foreground */ | 1598 /* with 8 colors set the bold attribute to get a bright foreground */ |
1557 if (bold == TRUE) | 1599 if (bold == TRUE) |
1558 attr |= HL_BOLD; | 1600 attr |= HL_BOLD; |
1559 return get_cterm_attr_idx(attr, fg, bg); | 1601 return get_cterm_attr_idx(attr, fg, bg); |
1658 } | 1700 } |
1659 #else | 1701 #else |
1660 ScreenLines[off] = c; | 1702 ScreenLines[off] = c; |
1661 #endif | 1703 #endif |
1662 } | 1704 } |
1663 ScreenAttrs[off] = cell2attr(&cell); | 1705 ScreenAttrs[off] = cell2attr(cell.attrs, cell.fg, cell.bg); |
1664 | 1706 |
1665 ++pos.col; | 1707 ++pos.col; |
1666 ++off; | 1708 ++off; |
1667 if (cell.width == 2) | 1709 if (cell.width == 2) |
1668 { | 1710 { |
1732 * Get the screen attribute for a position in the buffer. | 1774 * Get the screen attribute for a position in the buffer. |
1733 */ | 1775 */ |
1734 int | 1776 int |
1735 term_get_attr(buf_T *buf, linenr_T lnum, int col) | 1777 term_get_attr(buf_T *buf, linenr_T lnum, int col) |
1736 { | 1778 { |
1737 term_T *term = buf->b_term; | 1779 term_T *term = buf->b_term; |
1738 sb_line_T *line; | 1780 sb_line_T *line; |
1781 cellattr_T *cellattr; | |
1739 | 1782 |
1740 if (lnum > term->tl_scrollback.ga_len) | 1783 if (lnum > term->tl_scrollback.ga_len) |
1741 return 0; | 1784 return 0; |
1742 line = (sb_line_T *)term->tl_scrollback.ga_data + lnum - 1; | 1785 line = (sb_line_T *)term->tl_scrollback.ga_data + lnum - 1; |
1743 if (col >= line->sb_cols) | 1786 if (col >= line->sb_cols) |
1744 return 0; | 1787 return 0; |
1745 return cell2attr(line->sb_cells + col); | 1788 cellattr = line->sb_cells + col; |
1789 return cell2attr(cellattr->attrs, cellattr->fg, cellattr->bg); | |
1746 } | 1790 } |
1747 | 1791 |
1748 /* | 1792 /* |
1749 * Create a new vterm and initialize it. | 1793 * Create a new vterm and initialize it. |
1750 */ | 1794 */ |
2084 buf_T *buf = term_get_buf(argvars); | 2128 buf_T *buf = term_get_buf(argvars); |
2085 VTermScreen *screen = NULL; | 2129 VTermScreen *screen = NULL; |
2086 VTermPos pos; | 2130 VTermPos pos; |
2087 list_T *l; | 2131 list_T *l; |
2088 term_T *term; | 2132 term_T *term; |
2133 char_u *p; | |
2134 sb_line_T *line; | |
2089 | 2135 |
2090 if (rettv_list_alloc(rettv) == FAIL) | 2136 if (rettv_list_alloc(rettv) == FAIL) |
2091 return; | 2137 return; |
2092 if (buf == NULL) | 2138 if (buf == NULL) |
2093 return; | 2139 return; |
2094 term = buf->b_term; | 2140 term = buf->b_term; |
2141 | |
2142 l = rettv->vval.v_list; | |
2143 pos.row = get_row_number(&argvars[1], term); | |
2144 | |
2095 if (term->tl_vterm != NULL) | 2145 if (term->tl_vterm != NULL) |
2096 screen = vterm_obtain_screen(term->tl_vterm); | 2146 screen = vterm_obtain_screen(term->tl_vterm); |
2097 | 2147 else |
2098 l = rettv->vval.v_list; | 2148 { |
2099 pos.row = get_row_number(&argvars[1], term); | 2149 linenr_T lnum = pos.row + term->tl_scrollback_scrolled; |
2150 | |
2151 if (lnum < 0 || lnum >= term->tl_scrollback.ga_len) | |
2152 return; | |
2153 p = ml_get_buf(buf, lnum + 1, FALSE); | |
2154 line = (sb_line_T *)term->tl_scrollback.ga_data + lnum; | |
2155 } | |
2156 | |
2100 for (pos.col = 0; pos.col < term->tl_cols; ) | 2157 for (pos.col = 0; pos.col < term->tl_cols; ) |
2101 { | 2158 { |
2102 dict_T *dcell; | 2159 dict_T *dcell; |
2103 VTermScreenCell cell; | 2160 int width; |
2161 VTermScreenCellAttrs attrs; | |
2162 VTermColor fg, bg; | |
2104 char_u rgb[8]; | 2163 char_u rgb[8]; |
2105 char_u mbs[MB_MAXBYTES * VTERM_MAX_CHARS_PER_CELL + 1]; | 2164 char_u mbs[MB_MAXBYTES * VTERM_MAX_CHARS_PER_CELL + 1]; |
2106 int off = 0; | 2165 int off = 0; |
2107 int i; | 2166 int i; |
2108 | 2167 |
2109 if (screen == NULL) | 2168 if (screen == NULL) |
2110 { | 2169 { |
2111 linenr_T lnum = pos.row + term->tl_scrollback_scrolled; | 2170 cellattr_T *cellattr; |
2112 sb_line_T *line; | 2171 int len; |
2113 | 2172 |
2114 /* vterm has finished, get the cell from scrollback */ | 2173 /* vterm has finished, get the cell from scrollback */ |
2115 if (lnum < 0 || lnum >= term->tl_scrollback.ga_len) | |
2116 break; | |
2117 line = (sb_line_T *)term->tl_scrollback.ga_data + lnum; | |
2118 if (pos.col >= line->sb_cols) | 2174 if (pos.col >= line->sb_cols) |
2119 break; | 2175 break; |
2120 cell = line->sb_cells[pos.col]; | 2176 cellattr = line->sb_cells + pos.col; |
2121 } | 2177 width = cellattr->width; |
2122 else if (vterm_screen_get_cell(screen, pos, &cell) == 0) | 2178 attrs = cellattr->attrs; |
2123 break; | 2179 fg = cellattr->fg; |
2180 bg = cellattr->bg; | |
2181 len = MB_PTR2LEN(p); | |
2182 mch_memmove(mbs, p, len); | |
2183 mbs[len] = NUL; | |
2184 p += len; | |
2185 } | |
2186 else | |
2187 { | |
2188 VTermScreenCell cell; | |
2189 if (vterm_screen_get_cell(screen, pos, &cell) == 0) | |
2190 break; | |
2191 for (i = 0; i < VTERM_MAX_CHARS_PER_CELL; ++i) | |
2192 { | |
2193 if (cell.chars[i] == 0) | |
2194 break; | |
2195 off += (*utf_char2bytes)((int)cell.chars[i], mbs + off); | |
2196 } | |
2197 mbs[off] = NUL; | |
2198 width = cell.width; | |
2199 attrs = cell.attrs; | |
2200 fg = cell.fg; | |
2201 bg = cell.bg; | |
2202 } | |
2124 dcell = dict_alloc(); | 2203 dcell = dict_alloc(); |
2125 list_append_dict(l, dcell); | 2204 list_append_dict(l, dcell); |
2126 | 2205 |
2127 for (i = 0; i < VTERM_MAX_CHARS_PER_CELL; ++i) | |
2128 { | |
2129 if (cell.chars[i] == 0) | |
2130 break; | |
2131 off += (*utf_char2bytes)((int)cell.chars[i], mbs + off); | |
2132 } | |
2133 mbs[off] = NUL; | |
2134 dict_add_nr_str(dcell, "chars", 0, mbs); | 2206 dict_add_nr_str(dcell, "chars", 0, mbs); |
2135 | 2207 |
2136 vim_snprintf((char *)rgb, 8, "#%02x%02x%02x", | 2208 vim_snprintf((char *)rgb, 8, "#%02x%02x%02x", |
2137 cell.fg.red, cell.fg.green, cell.fg.blue); | 2209 fg.red, fg.green, fg.blue); |
2138 dict_add_nr_str(dcell, "fg", 0, rgb); | 2210 dict_add_nr_str(dcell, "fg", 0, rgb); |
2139 vim_snprintf((char *)rgb, 8, "#%02x%02x%02x", | 2211 vim_snprintf((char *)rgb, 8, "#%02x%02x%02x", |
2140 cell.bg.red, cell.bg.green, cell.bg.blue); | 2212 bg.red, bg.green, bg.blue); |
2141 dict_add_nr_str(dcell, "bg", 0, rgb); | 2213 dict_add_nr_str(dcell, "bg", 0, rgb); |
2142 | 2214 |
2143 dict_add_nr_str(dcell, "attr", cell2attr(&cell), NULL); | 2215 dict_add_nr_str(dcell, "attr", |
2144 dict_add_nr_str(dcell, "width", cell.width, NULL); | 2216 cell2attr(attrs, fg, bg), NULL); |
2217 dict_add_nr_str(dcell, "width", width, NULL); | |
2145 | 2218 |
2146 ++pos.col; | 2219 ++pos.col; |
2147 if (cell.width == 2) | 2220 if (width == 2) |
2148 ++pos.col; | 2221 ++pos.col; |
2149 } | 2222 } |
2150 } | 2223 } |
2151 | 2224 |
2152 /* | 2225 /* |