Added support for Pango markup.

This commit is contained in:
Kenneth Lyons 2015-10-05 01:10:01 -07:00
parent 876c1cef8d
commit dcd0518e25
6 changed files with 105 additions and 7 deletions

View File

@ -295,6 +295,7 @@ int main(int argc, char *argv[]) {
CFG_STR("color_separator", "#333333", CFGF_NONE),
CFG_INT("interval", 1, CFGF_NONE),
CFG_COLOR_OPTS("#00FF00", "#FFFF00", "#FF0000"),
CFG_STR("markup", "none", CFGF_NONE),
CFG_END()};
cfg_opt_t run_watch_opts[] = {
@ -365,6 +366,7 @@ int main(int argc, char *argv[]) {
cfg_opt_t tztime_opts[] = {
CFG_STR("format", "%Y-%m-%d %H:%M:%S %Z", CFGF_NONE),
CFG_STR("timezone", "", CFGF_NONE),
CFG_STR("format_time", NULL, CFGF_NONE),
CFG_CUSTOM_ALIGN_OPT,
CFG_CUSTOM_MIN_WIDTH_OPT,
CFG_END()};
@ -532,6 +534,14 @@ int main(int argc, char *argv[]) {
if (!valid_color(cfg_getstr(cfg_general, "color_good")) || !valid_color(cfg_getstr(cfg_general, "color_degraded")) || !valid_color(cfg_getstr(cfg_general, "color_bad")) || !valid_color(cfg_getstr(cfg_general, "color_separator")))
die("Bad color format");
char *markup_str = cfg_getstr(cfg_general, "markup");
if (strcasecmp(markup_str, "pango") == 0)
markup_format = M_PANGO;
else if (strcasecmp(markup_str, "none") == 0)
markup_format = M_NONE;
else
die("Unknown markup format: \"%s\"\n", markup_str);
#if YAJL_MAJOR >= 2
yajl_gen json_gen = yajl_gen_alloc(NULL);
#else
@ -648,13 +658,13 @@ int main(int argc, char *argv[]) {
CASE_SEC("time") {
SEC_OPEN_MAP("time");
print_time(json_gen, buffer, NULL, cfg_getstr(sec, "format"), NULL, tv.tv_sec);
print_time(json_gen, buffer, NULL, cfg_getstr(sec, "format"), NULL, NULL, tv.tv_sec);
SEC_CLOSE_MAP;
}
CASE_SEC_TITLE("tztime") {
SEC_OPEN_MAP("tztime");
print_time(json_gen, buffer, title, cfg_getstr(sec, "format"), cfg_getstr(sec, "timezone"), tv.tv_sec);
print_time(json_gen, buffer, title, cfg_getstr(sec, "format"), cfg_getstr(sec, "timezone"), cfg_getstr(sec, "format_time"), tv.tv_sec);
SEC_CLOSE_MAP;
}

View File

@ -8,6 +8,9 @@ enum { O_DZEN2,
O_TERM,
O_NONE } output_format;
enum { M_PANGO,
M_NONE } markup_format;
char *pct_mark;
#include <stdbool.h>
@ -78,6 +81,9 @@ char *pct_mark;
* not forgotten in the module */ \
*outwalk = '\0'; \
if (output_format == O_I3BAR) { \
char *_markup = cfg_getstr(cfg_general, "markup"); \
yajl_gen_string(json_gen, (const unsigned char *) "markup", strlen("markup")); \
yajl_gen_string(json_gen, (const unsigned char *)_markup, strlen(_markup)); \
yajl_gen_string(json_gen, (const unsigned char *) "full_text", strlen("full_text")); \
yajl_gen_string(json_gen, (const unsigned char *)text, strlen(text)); \
} else { \
@ -176,6 +182,7 @@ void print_separator(const char *separator);
char *color(const char *colorstr);
char *endcolor() __attribute__((pure));
void reset_cursor(void);
void maybe_escape_markup(char *text, char **buffer);
/* src/auto_detect_format.c */
char *auto_detect_format();
@ -193,7 +200,7 @@ const char *first_eth_interface(const net_type_t type);
void print_ipv6_info(yajl_gen json_gen, char *buffer, const char *format_up, const char *format_down);
void print_disk_info(yajl_gen json_gen, char *buffer, const char *path, const char *format, const char *format_not_mounted, const char *prefix_type, const char *threshold_type, const double low_threshold);
void print_battery_info(yajl_gen json_gen, char *buffer, int number, const char *path, const char *format, const char *format_down, const char *status_chr, const char *status_bat, const char *status_full, int low_threshold, char *threshold_type, bool last_full_capacity, bool integer_battery_capacity, bool hide_seconds);
void print_time(yajl_gen json_gen, char *buffer, const char *title, const char *format, const char *tz, time_t t);
void print_time(yajl_gen json_gen, char *buffer, const char *title, const char *format, const char *tz, const char *format_time, time_t t);
void print_ddate(yajl_gen json_gen, char *buffer, const char *format, time_t t);
const char *get_ip_addr(const char *interface);
void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface, const char *format_up, const char *format_down);

View File

@ -184,6 +184,13 @@ format as the separator is drawn by i3bar directly otherwise. For the other
output formats, the provided non-empty string will be automatically enclosed
with the necessary coloring bits if color support is enabled.
i3bar supports Pango markup, allowing your format strings to specify font
color, size, etc. by setting the +markup+ directive to "pango". Note that the
ampersand ("&"), less-than ("<"), greater-than (">"), single-quote ("'"), and
double-quote (""") characters need to be replaced with "`&amp;`", "`&lt;`",
"`&gt;`", "`&apos;`", and "`&quot;`" respectively. This is done automatically
for generated content (e.g. wireless ESSID, time).
*Example configuration*:
-------------------------------------------------------------
general {
@ -417,6 +424,18 @@ in the +tztime+ module.
*Example timezone*: +Europe/Berlin+
If you would like to use markup in this section, there is a separate
+format_time+ option that is automatically escaped. Its output then replaces
%time in the format string.
*Example configuration (markup)*:
-------------------------------------------------------------
tztime time {
format = "<span foreground='#ffffff'>time:</span> %time"
format_time = "%H:%M %Z"
}
-------------------------------------------------------------
=== DDate
Outputs the current discordian date in user-specified format. See +ddate(1)+ for

View File

@ -78,3 +78,46 @@ void print_separator(const char *separator) {
void reset_cursor(void) {
printf("\033[?25h");
}
/*
* Escapes ampersand, less-than, greater-than, single-quote, and double-quote
* characters with the corresponding Pango markup strings if markup is enabled.
* See the glib implementation:
* https://git.gnome.org/browse/glib/tree/glib/gmarkup.c?id=03db1f455b4265654e237d2ad55464b4113cba8a#n2142
*
*/
void maybe_escape_markup(char *text, char **buffer) {
if (markup_format == M_NONE) {
*buffer += sprintf(*buffer, "%s", text);
return;
}
for (; *text != '\0'; text++) {
switch (*text) {
case '&':
*buffer += sprintf(*buffer, "%s", "&amp;");
break;
case '<':
*buffer += sprintf(*buffer, "%s", "&lt;");
break;
case '>':
*buffer += sprintf(*buffer, "%s", "&gt;");
break;
case '\'':
*buffer += sprintf(*buffer, "%s", "&apos;");
break;
case '"':
*buffer += sprintf(*buffer, "%s", "&quot;");
break;
default:
if ((0x1 <= *text && *text <= 0x8) ||
(0xb <= *text && *text <= 0xc) ||
(0xe <= *text && *text <= 0x1f) ||
(0x7f <= *text && *text <= 0x84) ||
(0x86 <= *text && *text <= 0x9f))
*buffer += sprintf(*buffer, "&#x%x;", *text);
else
*(*buffer)++ = *text;
break;
}
}
}

View File

@ -33,17 +33,36 @@ void set_timezone(const char *tz) {
}
}
void print_time(yajl_gen json_gen, char *buffer, const char *title, const char *format, const char *tz, time_t t) {
void print_time(yajl_gen json_gen, char *buffer, const char *title, const char *format, const char *tz, const char *format_time, time_t t) {
const char *walk;
char *outwalk = buffer;
struct tm tm;
char timebuf[1024];
if (title != NULL)
INSTANCE(title);
/* Convert time and format output. */
set_timezone(tz);
localtime_r(&t, &tm);
outwalk += strftime(outwalk, 4095, format, &tm);
if (format_time == NULL) {
strftime(timebuf, sizeof(timebuf), format, &tm);
maybe_escape_markup(timebuf, &outwalk);
} else {
for (walk = format; *walk != '\0'; walk++) {
if (*walk != '%') {
*(outwalk++) = *walk;
continue;
}
if (BEGINS_WITH(walk + 1, "time")) {
strftime(timebuf, sizeof(timebuf), format_time, &tm);
maybe_escape_markup(timebuf, &outwalk);
walk += strlen("time");
}
}
}
*outwalk = '\0';
OUTPUT_FULL_TEXT(buffer);
}

View File

@ -519,7 +519,7 @@ void print_wireless_info(yajl_gen json_gen, char *buffer, const char *interface,
if (BEGINS_WITH(walk + 1, "essid")) {
if (info.flags & WIRELESS_INFO_FLAG_HAS_ESSID)
outwalk += sprintf(outwalk, "%s", info.essid);
maybe_escape_markup(info.essid, &outwalk);
else
*(outwalk++) = '?';
walk += strlen("essid");