4 * Copyright (c) 2007 Nicholas Marriott <nicholas.marriott@gmail.com>
5 * Copyright (c) 2014 Tiago Cunha <tcunha@users.sourceforge.net>
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.
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.
20 #include <sys/types.h>
28 /* Mask for bits not included in style. */
29 #define STYLE_ATTR_MASK (~0)
32 static struct style style_default
= {
33 { { { ' ' }, 0, 1, 1 }, 0, 0, 8, 8, 0, 0 },
40 STYLE_RANGE_NONE
, 0, "",
45 /* Set range string. */
47 style_set_range_string(struct style
*sy
, const char *s
)
49 strlcpy(sy
->range_string
, s
, sizeof sy
->range_string
);
53 * Parse an embedded style of the form "fg=colour,bg=colour,bright,...". Note
54 * that this adds onto the given style, so it must have been initialized
58 style_parse(struct style
*sy
, const struct grid_cell
*base
, const char *in
)
61 const char delimiters
[] = " ,\n", *errstr
;
62 char tmp
[256], *found
;
69 style_copy(&saved
, sy
);
71 log_debug("%s: %s", __func__
, in
);
73 while (*in
!= '\0' && strchr(delimiters
, *in
) != NULL
)
78 end
= strcspn(in
, delimiters
);
79 if (end
> (sizeof tmp
) - 1)
84 log_debug("%s: %s", __func__
, tmp
);
85 if (strcasecmp(tmp
, "default") == 0) {
89 sy
->gc
.attr
= base
->attr
;
90 sy
->gc
.flags
= base
->flags
;
91 } else if (strcasecmp(tmp
, "ignore") == 0)
93 else if (strcasecmp(tmp
, "noignore") == 0)
95 else if (strcasecmp(tmp
, "push-default") == 0)
96 sy
->default_type
= STYLE_DEFAULT_PUSH
;
97 else if (strcasecmp(tmp
, "pop-default") == 0)
98 sy
->default_type
= STYLE_DEFAULT_POP
;
99 else if (strcasecmp(tmp
, "nolist") == 0)
100 sy
->list
= STYLE_LIST_OFF
;
101 else if (strncasecmp(tmp
, "list=", 5) == 0) {
102 if (strcasecmp(tmp
+ 5, "on") == 0)
103 sy
->list
= STYLE_LIST_ON
;
104 else if (strcasecmp(tmp
+ 5, "focus") == 0)
105 sy
->list
= STYLE_LIST_FOCUS
;
106 else if (strcasecmp(tmp
+ 5, "left-marker") == 0)
107 sy
->list
= STYLE_LIST_LEFT_MARKER
;
108 else if (strcasecmp(tmp
+ 5, "right-marker") == 0)
109 sy
->list
= STYLE_LIST_RIGHT_MARKER
;
112 } else if (strcasecmp(tmp
, "norange") == 0) {
113 sy
->range_type
= style_default
.range_type
;
114 sy
->range_argument
= style_default
.range_type
;
115 strlcpy(sy
->range_string
, style_default
.range_string
,
116 sizeof sy
->range_string
);
117 } else if (end
> 6 && strncasecmp(tmp
, "range=", 6) == 0) {
118 found
= strchr(tmp
+ 6, '|');
124 if (strcasecmp(tmp
+ 6, "left") == 0) {
127 sy
->range_type
= STYLE_RANGE_LEFT
;
128 sy
->range_argument
= 0;
129 style_set_range_string(sy
, "");
130 } else if (strcasecmp(tmp
+ 6, "right") == 0) {
133 sy
->range_type
= STYLE_RANGE_RIGHT
;
134 sy
->range_argument
= 0;
135 style_set_range_string(sy
, "");
136 } else if (strcasecmp(tmp
+ 6, "pane") == 0) {
139 if (*found
!= '%' || found
[1] == '\0')
141 n
= strtonum(found
+ 1, 0, UINT_MAX
, &errstr
);
144 sy
->range_type
= STYLE_RANGE_PANE
;
145 sy
->range_argument
= n
;
146 style_set_range_string(sy
, "");
147 } else if (strcasecmp(tmp
+ 6, "window") == 0) {
150 n
= strtonum(found
, 0, UINT_MAX
, &errstr
);
153 sy
->range_type
= STYLE_RANGE_WINDOW
;
154 sy
->range_argument
= n
;
155 style_set_range_string(sy
, "");
156 } else if (strcasecmp(tmp
+ 6, "session") == 0) {
159 if (*found
!= '$' || found
[1] == '\0')
161 n
= strtonum(found
+ 1, 0, UINT_MAX
, &errstr
);
164 sy
->range_type
= STYLE_RANGE_SESSION
;
165 sy
->range_argument
= n
;
166 style_set_range_string(sy
, "");
167 } else if (strcasecmp(tmp
+ 6, "user") == 0) {
170 sy
->range_type
= STYLE_RANGE_USER
;
171 sy
->range_argument
= 0;
172 style_set_range_string(sy
, found
);
174 } else if (strcasecmp(tmp
, "noalign") == 0)
175 sy
->align
= style_default
.align
;
176 else if (end
> 6 && strncasecmp(tmp
, "align=", 6) == 0) {
177 if (strcasecmp(tmp
+ 6, "left") == 0)
178 sy
->align
= STYLE_ALIGN_LEFT
;
179 else if (strcasecmp(tmp
+ 6, "centre") == 0)
180 sy
->align
= STYLE_ALIGN_CENTRE
;
181 else if (strcasecmp(tmp
+ 6, "right") == 0)
182 sy
->align
= STYLE_ALIGN_RIGHT
;
183 else if (strcasecmp(tmp
+ 6, "absolute-centre") == 0)
184 sy
->align
= STYLE_ALIGN_ABSOLUTE_CENTRE
;
187 } else if (end
> 5 && strncasecmp(tmp
, "fill=", 5) == 0) {
188 if ((value
= colour_fromstring(tmp
+ 5)) == -1)
191 } else if (end
> 3 && strncasecmp(tmp
+ 1, "g=", 2) == 0) {
192 if ((value
= colour_fromstring(tmp
+ 3)) == -1)
194 if (*in
== 'f' || *in
== 'F') {
198 sy
->gc
.fg
= base
->fg
;
199 } else if (*in
== 'b' || *in
== 'B') {
203 sy
->gc
.bg
= base
->bg
;
206 } else if (end
> 3 && strncasecmp(tmp
, "us=", 3) == 0) {
207 if ((value
= colour_fromstring(tmp
+ 3)) == -1)
212 sy
->gc
.us
= base
->us
;
213 } else if (strcasecmp(tmp
, "none") == 0)
215 else if (end
> 2 && strncasecmp(tmp
, "no", 2) == 0) {
216 if ((value
= attributes_fromstring(tmp
+ 2)) == -1)
218 sy
->gc
.attr
&= ~value
;
220 if ((value
= attributes_fromstring(tmp
)) == -1)
222 sy
->gc
.attr
|= value
;
225 in
+= end
+ strspn(in
+ end
, delimiters
);
226 } while (*in
!= '\0');
231 style_copy(sy
, &saved
);
235 /* Convert style to a string. */
237 style_tostring(struct style
*sy
)
239 struct grid_cell
*gc
= &sy
->gc
;
241 const char *comma
= "", *tmp
= "";
247 if (sy
->list
!= STYLE_LIST_OFF
) {
248 if (sy
->list
== STYLE_LIST_ON
)
250 else if (sy
->list
== STYLE_LIST_FOCUS
)
252 else if (sy
->list
== STYLE_LIST_LEFT_MARKER
)
254 else if (sy
->list
== STYLE_LIST_RIGHT_MARKER
)
255 tmp
= "right-marker";
256 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%slist=%s", comma
,
260 if (sy
->range_type
!= STYLE_RANGE_NONE
) {
261 if (sy
->range_type
== STYLE_RANGE_LEFT
)
263 else if (sy
->range_type
== STYLE_RANGE_RIGHT
)
265 else if (sy
->range_type
== STYLE_RANGE_PANE
) {
266 snprintf(b
, sizeof b
, "pane|%%%u", sy
->range_argument
);
268 } else if (sy
->range_type
== STYLE_RANGE_WINDOW
) {
269 snprintf(b
, sizeof b
, "window|%u", sy
->range_argument
);
271 } else if (sy
->range_type
== STYLE_RANGE_SESSION
) {
272 snprintf(b
, sizeof b
, "session|$%u",
275 } else if (sy
->range_type
== STYLE_RANGE_USER
) {
276 snprintf(b
, sizeof b
, "user|%s", sy
->range_string
);
279 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%srange=%s", comma
,
283 if (sy
->align
!= STYLE_ALIGN_DEFAULT
) {
284 if (sy
->align
== STYLE_ALIGN_LEFT
)
286 else if (sy
->align
== STYLE_ALIGN_CENTRE
)
288 else if (sy
->align
== STYLE_ALIGN_RIGHT
)
290 else if (sy
->align
== STYLE_ALIGN_ABSOLUTE_CENTRE
)
291 tmp
= "absolute-centre";
292 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%salign=%s", comma
,
296 if (sy
->default_type
!= STYLE_DEFAULT_BASE
) {
297 if (sy
->default_type
== STYLE_DEFAULT_PUSH
)
298 tmp
= "push-default";
299 else if (sy
->default_type
== STYLE_DEFAULT_POP
)
301 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%s%s", comma
, tmp
);
305 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%sfill=%s", comma
,
306 colour_tostring(sy
->fill
));
310 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%sfg=%s", comma
,
311 colour_tostring(gc
->fg
));
315 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%sbg=%s", comma
,
316 colour_tostring(gc
->bg
));
320 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%sus=%s", comma
,
321 colour_tostring(gc
->us
));
325 xsnprintf(s
+ off
, sizeof s
- off
, "%s%s", comma
,
326 attributes_tostring(gc
->attr
));
335 /* Apply a style on top of the given style. */
337 style_add(struct grid_cell
*gc
, struct options
*oo
, const char *name
,
338 struct format_tree
*ft
)
341 struct format_tree
*ft0
= NULL
;
344 ft
= ft0
= format_create(NULL
, NULL
, 0, FORMAT_NOJOBS
);
346 sy
= options_string_to_style(oo
, name
, ft
);
355 gc
->attr
|= sy
->gc
.attr
;
361 /* Apply a style on top of the default style. */
363 style_apply(struct grid_cell
*gc
, struct options
*oo
, const char *name
,
364 struct format_tree
*ft
)
366 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
367 style_add(gc
, oo
, name
, ft
);
370 /* Initialize style from cell. */
372 style_set(struct style
*sy
, const struct grid_cell
*gc
)
374 memcpy(sy
, &style_default
, sizeof *sy
);
375 memcpy(&sy
->gc
, gc
, sizeof sy
->gc
);
380 style_copy(struct style
*dst
, struct style
*src
)
382 memcpy(dst
, src
, sizeof *dst
);