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, "",
42 STYLE_WIDTH_DEFAULT
, STYLE_PAD_DEFAULT
,
47 /* Set range string. */
49 style_set_range_string(struct style
*sy
, const char *s
)
51 strlcpy(sy
->range_string
, s
, sizeof sy
->range_string
);
55 * Parse an embedded style of the form "fg=colour,bg=colour,bright,...". Note
56 * that this adds onto the given style, so it must have been initialized
60 style_parse(struct style
*sy
, const struct grid_cell
*base
, const char *in
)
63 const char delimiters
[] = " ,\n", *errstr
;
64 char tmp
[256], *found
;
71 style_copy(&saved
, sy
);
73 log_debug("%s: %s", __func__
, in
);
75 while (*in
!= '\0' && strchr(delimiters
, *in
) != NULL
)
80 end
= strcspn(in
, delimiters
);
81 if (end
> (sizeof tmp
) - 1)
86 log_debug("%s: %s", __func__
, tmp
);
87 if (strcasecmp(tmp
, "default") == 0) {
91 sy
->gc
.attr
= base
->attr
;
92 sy
->gc
.flags
= base
->flags
;
93 } else if (strcasecmp(tmp
, "ignore") == 0)
95 else if (strcasecmp(tmp
, "noignore") == 0)
97 else if (strcasecmp(tmp
, "push-default") == 0)
98 sy
->default_type
= STYLE_DEFAULT_PUSH
;
99 else if (strcasecmp(tmp
, "pop-default") == 0)
100 sy
->default_type
= STYLE_DEFAULT_POP
;
101 else if (strcasecmp(tmp
, "nolist") == 0)
102 sy
->list
= STYLE_LIST_OFF
;
103 else if (strncasecmp(tmp
, "list=", 5) == 0) {
104 if (strcasecmp(tmp
+ 5, "on") == 0)
105 sy
->list
= STYLE_LIST_ON
;
106 else if (strcasecmp(tmp
+ 5, "focus") == 0)
107 sy
->list
= STYLE_LIST_FOCUS
;
108 else if (strcasecmp(tmp
+ 5, "left-marker") == 0)
109 sy
->list
= STYLE_LIST_LEFT_MARKER
;
110 else if (strcasecmp(tmp
+ 5, "right-marker") == 0)
111 sy
->list
= STYLE_LIST_RIGHT_MARKER
;
114 } else if (strcasecmp(tmp
, "norange") == 0) {
115 sy
->range_type
= style_default
.range_type
;
116 sy
->range_argument
= style_default
.range_type
;
117 strlcpy(sy
->range_string
, style_default
.range_string
,
118 sizeof sy
->range_string
);
119 } else if (end
> 6 && strncasecmp(tmp
, "range=", 6) == 0) {
120 found
= strchr(tmp
+ 6, '|');
126 if (strcasecmp(tmp
+ 6, "left") == 0) {
129 sy
->range_type
= STYLE_RANGE_LEFT
;
130 sy
->range_argument
= 0;
131 style_set_range_string(sy
, "");
132 } else if (strcasecmp(tmp
+ 6, "right") == 0) {
135 sy
->range_type
= STYLE_RANGE_RIGHT
;
136 sy
->range_argument
= 0;
137 style_set_range_string(sy
, "");
138 } else if (strcasecmp(tmp
+ 6, "pane") == 0) {
141 if (*found
!= '%' || found
[1] == '\0')
143 n
= strtonum(found
+ 1, 0, UINT_MAX
, &errstr
);
146 sy
->range_type
= STYLE_RANGE_PANE
;
147 sy
->range_argument
= n
;
148 style_set_range_string(sy
, "");
149 } else if (strcasecmp(tmp
+ 6, "window") == 0) {
152 n
= strtonum(found
, 0, UINT_MAX
, &errstr
);
155 sy
->range_type
= STYLE_RANGE_WINDOW
;
156 sy
->range_argument
= n
;
157 style_set_range_string(sy
, "");
158 } else if (strcasecmp(tmp
+ 6, "session") == 0) {
161 if (*found
!= '$' || found
[1] == '\0')
163 n
= strtonum(found
+ 1, 0, UINT_MAX
, &errstr
);
166 sy
->range_type
= STYLE_RANGE_SESSION
;
167 sy
->range_argument
= n
;
168 style_set_range_string(sy
, "");
169 } else if (strcasecmp(tmp
+ 6, "user") == 0) {
172 sy
->range_type
= STYLE_RANGE_USER
;
173 sy
->range_argument
= 0;
174 style_set_range_string(sy
, found
);
176 } else if (strcasecmp(tmp
, "noalign") == 0)
177 sy
->align
= style_default
.align
;
178 else if (end
> 6 && strncasecmp(tmp
, "align=", 6) == 0) {
179 if (strcasecmp(tmp
+ 6, "left") == 0)
180 sy
->align
= STYLE_ALIGN_LEFT
;
181 else if (strcasecmp(tmp
+ 6, "centre") == 0)
182 sy
->align
= STYLE_ALIGN_CENTRE
;
183 else if (strcasecmp(tmp
+ 6, "right") == 0)
184 sy
->align
= STYLE_ALIGN_RIGHT
;
185 else if (strcasecmp(tmp
+ 6, "absolute-centre") == 0)
186 sy
->align
= STYLE_ALIGN_ABSOLUTE_CENTRE
;
189 } else if (end
> 5 && strncasecmp(tmp
, "fill=", 5) == 0) {
190 if ((value
= colour_fromstring(tmp
+ 5)) == -1)
193 } else if (end
> 3 && strncasecmp(tmp
+ 1, "g=", 2) == 0) {
194 if ((value
= colour_fromstring(tmp
+ 3)) == -1)
196 if (*in
== 'f' || *in
== 'F') {
200 sy
->gc
.fg
= base
->fg
;
201 } else if (*in
== 'b' || *in
== 'B') {
205 sy
->gc
.bg
= base
->bg
;
208 } else if (end
> 3 && strncasecmp(tmp
, "us=", 3) == 0) {
209 if ((value
= colour_fromstring(tmp
+ 3)) == -1)
214 sy
->gc
.us
= base
->us
;
215 } else if (strcasecmp(tmp
, "none") == 0)
217 else if (end
> 2 && strncasecmp(tmp
, "no", 2) == 0) {
218 if ((value
= attributes_fromstring(tmp
+ 2)) == -1)
220 sy
->gc
.attr
&= ~value
;
221 } else if (end
> 6 && strncasecmp(tmp
, "width=", 6) == 0) {
222 n
= strtonum(tmp
+ 6, 0, UINT_MAX
, &errstr
);
226 } else if (end
> 4 && strncasecmp(tmp
, "pad=", 4) == 0) {
227 n
= strtonum(tmp
+ 4, 0, UINT_MAX
, &errstr
);
232 if ((value
= attributes_fromstring(tmp
)) == -1)
234 sy
->gc
.attr
|= value
;
237 in
+= end
+ strspn(in
+ end
, delimiters
);
238 } while (*in
!= '\0');
243 style_copy(sy
, &saved
);
247 /* Convert style to a string. */
249 style_tostring(struct style
*sy
)
251 struct grid_cell
*gc
= &sy
->gc
;
253 const char *comma
= "", *tmp
= "";
259 if (sy
->list
!= STYLE_LIST_OFF
) {
260 if (sy
->list
== STYLE_LIST_ON
)
262 else if (sy
->list
== STYLE_LIST_FOCUS
)
264 else if (sy
->list
== STYLE_LIST_LEFT_MARKER
)
266 else if (sy
->list
== STYLE_LIST_RIGHT_MARKER
)
267 tmp
= "right-marker";
268 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%slist=%s", comma
,
272 if (sy
->range_type
!= STYLE_RANGE_NONE
) {
273 if (sy
->range_type
== STYLE_RANGE_LEFT
)
275 else if (sy
->range_type
== STYLE_RANGE_RIGHT
)
277 else if (sy
->range_type
== STYLE_RANGE_PANE
) {
278 snprintf(b
, sizeof b
, "pane|%%%u", sy
->range_argument
);
280 } else if (sy
->range_type
== STYLE_RANGE_WINDOW
) {
281 snprintf(b
, sizeof b
, "window|%u", sy
->range_argument
);
283 } else if (sy
->range_type
== STYLE_RANGE_SESSION
) {
284 snprintf(b
, sizeof b
, "session|$%u",
287 } else if (sy
->range_type
== STYLE_RANGE_USER
) {
288 snprintf(b
, sizeof b
, "user|%s", sy
->range_string
);
291 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%srange=%s", comma
,
295 if (sy
->align
!= STYLE_ALIGN_DEFAULT
) {
296 if (sy
->align
== STYLE_ALIGN_LEFT
)
298 else if (sy
->align
== STYLE_ALIGN_CENTRE
)
300 else if (sy
->align
== STYLE_ALIGN_RIGHT
)
302 else if (sy
->align
== STYLE_ALIGN_ABSOLUTE_CENTRE
)
303 tmp
= "absolute-centre";
304 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%salign=%s", comma
,
308 if (sy
->default_type
!= STYLE_DEFAULT_BASE
) {
309 if (sy
->default_type
== STYLE_DEFAULT_PUSH
)
310 tmp
= "push-default";
311 else if (sy
->default_type
== STYLE_DEFAULT_POP
)
313 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%s%s", comma
, tmp
);
317 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%sfill=%s", comma
,
318 colour_tostring(sy
->fill
));
322 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%sfg=%s", comma
,
323 colour_tostring(gc
->fg
));
327 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%sbg=%s", comma
,
328 colour_tostring(gc
->bg
));
332 off
+= xsnprintf(s
+ off
, sizeof s
- off
, "%sus=%s", comma
,
333 colour_tostring(gc
->us
));
337 xsnprintf(s
+ off
, sizeof s
- off
, "%s%s", comma
,
338 attributes_tostring(gc
->attr
));
341 if (sy
->width
>= 0) {
342 xsnprintf(s
+ off
, sizeof s
- off
, "%swidth=%u", comma
,
347 xsnprintf(s
+ off
, sizeof s
- off
, "%spad=%u", comma
,
356 /* Apply a style on top of the given style. */
358 style_add(struct grid_cell
*gc
, struct options
*oo
, const char *name
,
359 struct format_tree
*ft
)
362 struct format_tree
*ft0
= NULL
;
365 ft
= ft0
= format_create(NULL
, NULL
, 0, FORMAT_NOJOBS
);
367 sy
= options_string_to_style(oo
, name
, ft
);
376 gc
->attr
|= sy
->gc
.attr
;
382 /* Apply a style on top of the default style. */
384 style_apply(struct grid_cell
*gc
, struct options
*oo
, const char *name
,
385 struct format_tree
*ft
)
387 memcpy(gc
, &grid_default_cell
, sizeof *gc
);
388 style_add(gc
, oo
, name
, ft
);
391 /* Initialize style from cell. */
393 style_set(struct style
*sy
, const struct grid_cell
*gc
)
395 memcpy(sy
, &style_default
, sizeof *sy
);
396 memcpy(&sy
->gc
, gc
, sizeof sy
->gc
);
401 style_copy(struct style
*dst
, struct style
*src
)
403 memcpy(dst
, src
, sizeof *dst
);
407 style_set_scrollbar_style_from_option(struct style
*sb_style
, struct options
*oo
)
411 sy
= options_string_to_style(oo
, "pane-scrollbars-style", NULL
);
413 style_set(sb_style
, &grid_default_cell
);
414 sb_style
->width
= PANE_SCROLLBARS_DEFAULT_WIDTH
;
415 sb_style
->pad
= PANE_SCROLLBARS_DEFAULT_PADDING
;
416 utf8_set(&sb_style
->gc
.data
, PANE_SCROLLBARS_CHARACTER
);
418 style_copy(sb_style
, sy
);
419 if (sb_style
->width
< 1)
420 sb_style
->width
= PANE_SCROLLBARS_DEFAULT_WIDTH
;
421 if (sb_style
->pad
< 0)
422 sb_style
->pad
= PANE_SCROLLBARS_DEFAULT_PADDING
;
423 utf8_set(&sb_style
->gc
.data
, PANE_SCROLLBARS_CHARACTER
);