From 939a485d411c644020cfacfeda17994e4573172f Mon Sep 17 00:00:00 2001 From: ivan <522518+ivanmilov@users.noreply.github.com> Date: Sun, 3 Nov 2019 20:29:07 +0100 Subject: [PATCH 1/2] added style support MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit With this PR you can make statusbar output looks like e.g. powerline. Example there: https://i.redd.it/13a2zz2ifjw31.png New field in config: full_text_pattern Value of this pattern will be parsed and all values surrounded by '%' will be used as parameter keys. Values started with '&' - are references on another parameter keys. Demo config example: ``` command=~/.config/i3/i3blocksScripts/$BLOCK_NAME separator_block_width=0 markup=pango color1=#ffffffa0 color2=#000000a0 background=#000000a0 separator_glyph= full_text_pattern=%separator_glyph%%full_text% gbg=&fg gfg=&bg [foo] command=echo foo bg=&color1 fg=&color2 interval=once [bar] command=echo bar bg=&color2 fg=&color1 interval=once ``` i3 config: ``` bar { position top i3bar_command i3bar -t 0.1 colors{ background #000000a0 } status_command i3blocks -c demo.conf } ``` --- i3bar.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 94 insertions(+) diff --git a/i3bar.c b/i3bar.c index 30fb989b..3af5fd77 100644 --- a/i3bar.c +++ b/i3bar.c @@ -23,6 +23,7 @@ #include "log.h" #include "map.h" #include "term.h" +#include /* See https://i3wm.org/docs/i3bar-protocol.html for details */ @@ -148,6 +149,78 @@ static int i3bar_print_pair(const char *key, const char *value, void *data) return 0; } +static const char* i3bar_get_value_by_ref(const char *value, struct block *block) +{ + if(value == NULL || block == NULL) + return NULL; + + if(value[0] == '#') // color + { + return value; + } + if(value[0] == '&') // reference + { + const char *ref = map_get(block->env, value + 1); + if(ref != NULL) + { + // reccursive reference lookup + return i3bar_get_value_by_ref(ref, block); + } + else + { + block_debug(block, "Cannot found reference %s.", value); + return value; + } + } + + return value; +} + +static int i3bar_parse_pattern(struct block *block, const char *pattern, char *res) +{ + char pattern_copy[BUFSIZ] = {0}; + + // TODO: parametrize wia block->conf + char delim[] = "%"; + + // copy, because strtok modifies input string + // TODO: use strdup + strcpy(pattern_copy, pattern); + + char *ptr = strtok(pattern_copy, delim); + bool token = false; + while(ptr != NULL) + { + if(token) + { + const char *value = map_get(block->env, ptr); + if(value != NULL) + { + const char *final_value = i3bar_get_value_by_ref(value, block); + if(final_value) + strcat(res, final_value); + else + { + block_error(block, "Something wrong with %s", value); // should not hit there + return 2; + } + } + else + { + block_debug(block, "Key %s is not defined.", ptr); + return 1; + } + } + else + strcat(res, ptr); + + token = !token; + ptr = strtok(NULL, delim); + } + + return 0; +} + static int i3bar_print_block(struct block *block, void *data) { const char *full_text = map_get(block->env, "full_text"); @@ -161,6 +234,21 @@ static int i3bar_print_block(struct block *block, void *data) return 0; } + char *full_text_copy = NULL; + + const char *full_text_pattern = map_get(block->config, "full_text_pattern"); + if(full_text_pattern) + { + char buf[BUFSIZ] = {0}; + + if(i3bar_parse_pattern(block, full_text_pattern, buf) == 0) + { + full_text_copy = strdup(full_text); + if(full_text_copy != NULL) + map_set(block->env, "full_text", buf); + } + } + if ((*mcount)++) fprintf(stdout, ","); @@ -168,6 +256,12 @@ static int i3bar_print_block(struct block *block, void *data) err = map_for_each(block->env, i3bar_print_pair, &pcount); fprintf(stdout, "}"); + if(full_text_copy) + { + map_set(block->env, "full_text", full_text_copy); + free(full_text_copy); + } + return err; } From 96e69299b13c54c507409e7eb085a699f5debd41 Mon Sep 17 00:00:00 2001 From: Ivan Milov <522518+ivanmilov@users.noreply.github.com> Date: Tue, 9 Feb 2021 17:07:21 +0100 Subject: [PATCH 2/2] escape ampersand --- i3bar.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/i3bar.c b/i3bar.c index 3af5fd77..ba57b344 100644 --- a/i3bar.c +++ b/i3bar.c @@ -105,6 +105,26 @@ static void i3bar_print_term(const struct bar *bar) fflush(stdout); } +void amp_escape(const char *value, char *buf, size_t size) +{ + int i, k = 0; + for(i = 0; value[i] != '\0'; ) + { + buf[k] = value[i]; + + if(value[i] == '&') + { + buf[++k] = 'a'; + buf[++k] = 'm'; + buf[++k] = 'p'; + buf[++k] = ';'; + } + + ++i; ++k; + } + buf[k] = 0; +} + static int i3bar_print_pair(const char *key, const char *value, void *data) { unsigned int index = i3bar_indexof(key); @@ -144,6 +164,14 @@ static int i3bar_print_pair(const char *key, const char *value, void *data) if ((*pcount)++) fprintf(stdout, ","); + // escape [& -> &] + if(strncmp(key, "full_text", strlen(key)) == 0 && strchr(value, '&') != NULL) + { + static char buf1[BUFSIZ]={0}; + amp_escape(value, buf1, sizeof(buf1)); + value = buf1; + } + fprintf(stdout, "\"%s\":%s", key, value); return 0; @@ -187,13 +215,13 @@ static int i3bar_parse_pattern(struct block *block, const char *pattern, char *r // TODO: use strdup strcpy(pattern_copy, pattern); - char *ptr = strtok(pattern_copy, delim); + char *key = strtok(pattern_copy, delim); bool token = false; - while(ptr != NULL) + while(key != NULL) { if(token) { - const char *value = map_get(block->env, ptr); + const char *value = map_get(block->env, key); if(value != NULL) { const char *final_value = i3bar_get_value_by_ref(value, block); @@ -207,15 +235,15 @@ static int i3bar_parse_pattern(struct block *block, const char *pattern, char *r } else { - block_debug(block, "Key %s is not defined.", ptr); + block_debug(block, "Key %s is not defined.", key); return 1; } } else - strcat(res, ptr); + strcat(res, key); token = !token; - ptr = strtok(NULL, delim); + key = strtok(NULL, delim); } return 0;