xref: /openbsd-src/usr.bin/tmux/style.c (revision 0b7734b3d77bb9b21afec6f4621cae6c805dbd45)
1 /* $OpenBSD: style.c,v 1.10 2016/07/15 00:42:56 nicm Exp $ */
2 
3 /*
4  * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5  * Copyright (c) 2014 Tiago Cunha <tcunha@users.sourceforge.net>
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER
16  * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
17  * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #include <sys/types.h>
21 
22 #include <string.h>
23 
24 #include "tmux.h"
25 
26 /* Parse an embedded style of the form "fg=colour,bg=colour,bright,...". */
27 int
28 style_parse(const struct grid_cell *defgc, struct grid_cell *gc,
29     const char *in)
30 {
31 	struct grid_cell	savedgc;
32 	const char		delimiters[] = " ,";
33 	char			tmp[32];
34 	int			val;
35 	size_t			end;
36 	int			fg, bg;
37 	u_char			attr, flags;
38 
39 	if (*in == '\0')
40 		return (0);
41 	if (strchr(delimiters, in[strlen(in) - 1]) != NULL)
42 		return (-1);
43 	memcpy(&savedgc, gc, sizeof savedgc);
44 
45 	fg = gc->fg;
46 	bg = gc->bg;
47 	attr = gc->attr;
48 	flags = gc->flags;
49 	do {
50 		end = strcspn(in, delimiters);
51 		if (end > (sizeof tmp) - 1)
52 			goto error;
53 		memcpy(tmp, in, end);
54 		tmp[end] = '\0';
55 
56 		if (strcasecmp(tmp, "default") == 0) {
57 			fg = defgc->fg;
58 			bg = defgc->bg;
59 			attr = defgc->attr;
60 			flags = defgc->flags;
61 		} else if (end > 3 && strncasecmp(tmp + 1, "g=", 2) == 0) {
62 			if ((val = colour_fromstring(tmp + 3)) == -1)
63 				goto error;
64 			if (*in == 'f' || *in == 'F') {
65 				if (val != 8)
66 					fg = val;
67 				else
68 					fg = defgc->fg;
69 			} else if (*in == 'b' || *in == 'B') {
70 				if (val != 8)
71 					bg = val;
72 				else
73 					bg = defgc->bg;
74 			} else
75 				goto error;
76 		} else if (strcasecmp(tmp, "none") == 0)
77 			attr = 0;
78 		else if (end > 2 && strncasecmp(tmp, "no", 2) == 0) {
79 			if ((val = attributes_fromstring(tmp + 2)) == -1)
80 				goto error;
81 			attr &= ~val;
82 		} else {
83 			if ((val = attributes_fromstring(tmp)) == -1)
84 				goto error;
85 			attr |= val;
86 		}
87 
88 		in += end + strspn(in + end, delimiters);
89 	} while (*in != '\0');
90 	gc->fg = fg;
91 	gc->bg = bg;
92 	gc->attr = attr;
93 	gc->flags = flags;
94 
95 	return (0);
96 
97 error:
98 	memcpy(gc, &savedgc, sizeof *gc);
99 	return (-1);
100 }
101 
102 /* Convert style to a string. */
103 const char *
104 style_tostring(struct grid_cell *gc)
105 {
106 	int		 off = 0, comma = 0;
107 	static char	 s[256];
108 
109 	*s = '\0';
110 
111 	if (gc->fg != 8) {
112 		off += xsnprintf(s, sizeof s, "fg=%s", colour_tostring(gc->fg));
113 		comma = 1;
114 	}
115 
116 	if (gc->bg != 8) {
117 		off += xsnprintf(s + off, sizeof s - off, "%sbg=%s",
118 		    comma ? "," : "", colour_tostring(gc->bg));
119 		comma = 1;
120 	}
121 
122 	if (gc->attr != 0 && gc->attr != GRID_ATTR_CHARSET) {
123 		xsnprintf(s + off, sizeof s - off, "%s%s",
124 		    comma ? "," : "", attributes_tostring(gc->attr));
125 	}
126 
127 	if (*s == '\0')
128 		return ("default");
129 	return (s);
130 }
131 
132 /* Synchronize new -style option with the old one. */
133 void
134 style_update_new(struct options *oo, const char *name, const char *newname)
135 {
136 	int			 value;
137 	struct grid_cell	*gc;
138 	struct options_entry	*o;
139 
140 	/* It's a colour or attribute, but with no -style equivalent. */
141 	if (newname == NULL)
142 		return;
143 
144 	o = options_find1(oo, newname);
145 	if (o == NULL)
146 		o = options_set_style(oo, newname, "default", 0);
147 	gc = &o->style;
148 
149 	o = options_find1(oo, name);
150 	if (o == NULL)
151 		o = options_set_number(oo, name, 8);
152 	value = o->num;
153 
154 	if (strstr(name, "-bg") != NULL)
155 		gc->bg = value;
156 	else if (strstr(name, "-fg") != NULL)
157 		gc->fg = value;
158 	else if (strstr(name, "-attr") != NULL)
159 		gc->attr = value;
160 }
161 
162 /* Synchronize all the old options with the new -style one. */
163 void
164 style_update_old(struct options *oo, const char *name, struct grid_cell *gc)
165 {
166 	char	newname[128];
167 	int	size;
168 
169 	size = strrchr(name, '-') - name;
170 
171 	xsnprintf(newname, sizeof newname, "%.*s-bg", size, name);
172 	options_set_number(oo, newname, gc->bg);
173 
174 	xsnprintf(newname, sizeof newname, "%.*s-fg", size, name);
175 	options_set_number(oo, newname, gc->fg);
176 
177 	xsnprintf(newname, sizeof newname, "%.*s-attr", size, name);
178 	options_set_number(oo, newname, gc->attr);
179 }
180 
181 /* Apply a style. */
182 void
183 style_apply(struct grid_cell *gc, struct options *oo, const char *name)
184 {
185 	struct grid_cell	*gcp;
186 
187 	memcpy(gc, &grid_default_cell, sizeof *gc);
188 	gcp = options_get_style(oo, name);
189 	gc->fg = gcp->fg;
190 	gc->bg = gcp->bg;
191 	gc->attr |= gcp->attr;
192 }
193 
194 /* Apply a style, updating if default. */
195 void
196 style_apply_update(struct grid_cell *gc, struct options *oo, const char *name)
197 {
198 	struct grid_cell	*gcp;
199 
200 	gcp = options_get_style(oo, name);
201 	if (gcp->fg != 8)
202 		gc->fg = gcp->fg;
203 	if (gcp->bg != 8)
204 		gc->bg = gcp->bg;
205 	if (gcp->attr != 0)
206 		gc->attr |= gcp->attr;
207 }
208 
209 /* Check if two styles are the same. */
210 int
211 style_equal(const struct grid_cell *gc1, const struct grid_cell *gc2)
212 {
213 	return (gc1->fg == gc2->fg &&
214 	    gc1->bg == gc2->bg &&
215 	    (gc1->flags & ~GRID_FLAG_PADDING) ==
216 	    (gc2->flags & ~GRID_FLAG_PADDING) &&
217 	    (gc1->attr & ~GRID_ATTR_CHARSET) ==
218 	    (gc2->attr & ~GRID_ATTR_CHARSET));
219 }
220