]> git.sur5r.net Git - i3/i3status/commitdiff
Added support for Pango markup. 72/head
authorKenneth Lyons <ixjlyons@gmail.com>
Mon, 5 Oct 2015 08:10:01 +0000 (01:10 -0700)
committerKenneth Lyons <ixjlyons@gmail.com>
Fri, 4 Dec 2015 18:27:18 +0000 (10:27 -0800)
i3status.c
include/i3status.h
man/i3status.man
src/output.c
src/print_time.c
src/print_wireless_info.c

index 462721b9055005234ae6096845b7d2e4bf2e6e2a..37814256a78586e71a06d891c0246d1c99adfcc3 100644 (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;
             }
 
index 037e1545eda3e7df6af7595317fbf6493116bc66..5f65c5edf7606b1e6bba847b6fc500d6090ce3f4 100644 (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);
index d550b812ce2fa0418116c6c8ae4c0edfdd3ed0c2..0b5b36765b0e7088492a368adc7e7450790b853c 100644 (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
index f7a88887a3ca9f6b07a798923ad9dd1f9065605b..1c8c415ada6b4bf714e9e92caf8f52d36f0cc65b 100644 (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;
+        }
+    }
+}
index c70a09c7a830f68f2eb5371e650d12128ca9328c..9fa6642c600644e66bd2781153d4cf837a9f14df 100644 (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);
 }
index aff04383ed43ac0a7294eb2a04e0d74de99348aa..4f92507b01572ea7cbdef2d15f8aa820ba5eac6c 100644 (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");