1 /* vifm
2 * Copyright (C) 2020 xaizek.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
17 */
18
19 #include "colored_line.h"
20
21 #include <stddef.h> /* size_t */
22 #include <stdlib.h> /* free() */
23 #include <string.h> /* memmove() strdup() */
24
25 #include "../cfg/config.h"
26 #include "../utils/str.h"
27 #include "../utils/utf8.h"
28 #include "color_manager.h"
29 #include "color_scheme.h"
30 #include "ui.h"
31
32 cline_t
cline_make(void)33 cline_make(void)
34 {
35 cline_t result = { .line = strdup(""), .attrs = strdup("") };
36 return result;
37 }
38
39 int
cline_sync(cline_t * cline,int extra_width)40 cline_sync(cline_t *cline, int extra_width)
41 {
42 const size_t nchars = utf8_strsw(cline->line) + extra_width;
43 if(cline->attrs_len < nchars)
44 {
45 int width = nchars - cline->attrs_len;
46 char *const new_attrs = format_str("%s%*s", cline->attrs, width, "");
47 free(cline->attrs);
48 cline->attrs = new_attrs;
49 cline->attrs_len = nchars;
50 }
51 return (cline->attrs_len > nchars);
52 }
53
54 void
cline_set_attr(cline_t * cline,char attr)55 cline_set_attr(cline_t *cline, char attr)
56 {
57 (void)cline_sync(cline, 1);
58 cline->attrs[cline->attrs_len - 1] = attr;
59 }
60
61 void
cline_clear(cline_t * cline)62 cline_clear(cline_t *cline)
63 {
64 cline->line[0] = '\0';
65 cline->line_len = 0;
66 cline->attrs[0] = '\0';
67 cline->attrs_len = 0;
68 }
69
70 void
cline_finish(cline_t * cline)71 cline_finish(cline_t *cline)
72 {
73 if(cline_sync(cline, 0))
74 {
75 cline->attrs[--cline->attrs_len] = '\0';
76 }
77 }
78
79 void
cline_splice_attrs(cline_t * cline,cline_t * admixture)80 cline_splice_attrs(cline_t *cline, cline_t *admixture)
81 {
82 char *attrs = admixture->attrs;
83 if(cline_sync(cline, 0) && admixture->attrs_len > 0U)
84 {
85 if(*attrs != ' ')
86 {
87 cline->attrs[cline->attrs_len - 1U] = *attrs;
88 }
89 ++attrs;
90 }
91 strappend(&cline->attrs, &cline->attrs_len, attrs);
92 free(admixture->attrs);
93 }
94
95 void
cline_print(const cline_t * cline,WINDOW * win,const col_attr_t * def_col)96 cline_print(const cline_t *cline, WINDOW *win, const col_attr_t *def_col)
97 {
98 cchar_t def_attr;
99 setcchar(&def_attr, L" ", def_col->attr,
100 colmgr_get_pair(def_col->fg, def_col->bg), NULL);
101
102 const char *line = cline->line;
103 const char *attrs = cline->attrs;
104
105 cchar_t attr = def_attr;
106 while(*line != '\0')
107 {
108 if(*attrs == '0')
109 {
110 attr = def_attr;
111 }
112 else if(*attrs != ' ')
113 {
114 const int color = (USER1_COLOR + (*attrs - '1'));
115 col_attr_t col = *def_col;
116 cs_mix_colors(&col, &cfg.cs.color[color]);
117 setcchar(&attr, L" ", col.attr, colmgr_get_pair(col.fg, col.bg), NULL);
118 }
119
120 const size_t len = utf8_chrw(line);
121 char char_buf[len + 1];
122 copy_str(char_buf, sizeof(char_buf), line);
123 wprinta(win, char_buf, &attr, 0);
124
125 line += len;
126 attrs += utf8_chrsw(char_buf);
127 }
128 }
129
130 void
cline_left_ellipsis(cline_t * cline,size_t max_width,const char ell[])131 cline_left_ellipsis(cline_t *cline, size_t max_width, const char ell[])
132 {
133 if(max_width == 0U)
134 {
135 /* No room to print anything. */
136 cline_clear(cline);
137 return;
138 }
139
140 size_t width = utf8_strsw(cline->line);
141 if(width <= max_width)
142 {
143 /* No need to change the string. */
144 return;
145 }
146
147 size_t ell_width = utf8_strsw(ell);
148 if(max_width <= ell_width)
149 {
150 /* Insert as many characters of ellipsis as we can. */
151 const int prefix = (int)utf8_nstrsnlen(ell, max_width);
152 cline->line = format_str("%.*s", prefix, ell);
153 cline->line_len = prefix;
154 cline->attrs[0] = '\0';
155 cline->attrs_len = 0;
156 cline_finish(cline);
157 return;
158 }
159
160 char *line = cline->line;
161 char *attrs = cline->attrs;
162
163 while(width > max_width - ell_width)
164 {
165 int cw = utf8_chrsw(line);
166 width -= cw;
167 line += utf8_chrw(line);
168 attrs += cw;
169 }
170
171 cline->line_len = cline->line_len - (line - cline->line);
172 memmove(cline->line, line, cline->line_len + 1);
173 cline->attrs_len = cline->attrs_len - (attrs - cline->attrs);
174 memmove(cline->attrs, attrs, cline->attrs_len + 1);
175
176 strprepend(&cline->line, &cline->line_len, ell);
177 char spaces[ell_width + 1];
178 memset(spaces, ' ', sizeof(spaces) - 1);
179 spaces[ell_width] = '\0';
180 strprepend(&cline->attrs, &cline->attrs_len, spaces);
181 }
182
183 void
cline_dispose(cline_t * cline)184 cline_dispose(cline_t *cline)
185 {
186 update_string(&cline->line, NULL);
187 cline->line_len = 0;
188 update_string(&cline->attrs, NULL);
189 cline->attrs_len = 0;
190 }
191
192 /* vim: set tabstop=2 softtabstop=2 shiftwidth=2 noexpandtab cinoptions-=(0 : */
193 /* vim: set cinoptions+=t0 : */
194