summaryrefslogtreecommitdiff
path: root/src/fe-common/core/themes.c
diff options
context:
space:
mode:
authorTimo Sirainen <cras@irssi.org>2000-10-27 23:06:26 +0000
committercras <cras@dbcabf3a-b0e7-0310-adc4-f8d773084564>2000-10-27 23:06:26 +0000
commit000ba23aa7a7779ee795b249140db886f338ef84 (patch)
tree7e7dfdc78616a5a51119515d773e08d1301c61c9 /src/fe-common/core/themes.c
parent35fd48a0b48879dd29b17bc263903907ea1ba345 (diff)
downloadirssi-000ba23aa7a7779ee795b249140db886f338ef84.zip
Support for templates in theme files.
module-formats.c files needs to be updated, meanwhile here's default.theme you can use. git-svn-id: http://svn.irssi.org/repos/irssi/trunk@791 dbcabf3a-b0e7-0310-adc4-f8d773084564
Diffstat (limited to 'src/fe-common/core/themes.c')
-rw-r--r--src/fe-common/core/themes.c300
1 files changed, 256 insertions, 44 deletions
diff --git a/src/fe-common/core/themes.c b/src/fe-common/core/themes.c
index f72d107e..1f1e371d 100644
--- a/src/fe-common/core/themes.c
+++ b/src/fe-common/core/themes.c
@@ -24,6 +24,7 @@
#include "commands.h"
#include "levels.h"
#include "misc.h"
+#include "special-vars.h"
#include "lib-config/iconfig.h"
#include "settings.h"
@@ -45,21 +46,32 @@ THEME_REC *theme_create(const char *path, const char *name)
rec = g_new0(THEME_REC, 1);
rec->path = g_strdup(path);
rec->name = g_strdup(name);
- rec->modules = g_hash_table_new((GHashFunc) g_istr_hash, (GCompareFunc) g_istr_equal);
+ rec->abstracts = g_hash_table_new((GHashFunc) g_str_hash,
+ (GCompareFunc) g_str_equal);
+ rec->modules = g_hash_table_new((GHashFunc) g_istr_hash,
+ (GCompareFunc) g_istr_equal);
themes = g_slist_append(themes, rec);
signal_emit("theme created", 1, rec);
return rec;
}
+static void theme_abstract_destroy(char *key, char *value)
+{
+ g_free(key);
+ g_free(value);
+}
+
static void theme_module_destroy(const char *key, MODULE_THEME_REC *rec)
{
int n;
- for (n = 0; n < rec->count; n++)
- if (rec->formats[n] != NULL)
- g_free(rec->formats[n]);
+ for (n = 0; n < rec->count; n++) {
+ g_free_not_null(rec->formats[n]);
+ g_free_not_null(rec->expanded_formats[n]);
+ }
g_free(rec->formats);
+ g_free(rec->expanded_formats);
g_free(rec->name);
g_free(rec);
@@ -70,14 +82,185 @@ void theme_destroy(THEME_REC *rec)
themes = g_slist_remove(themes, rec);
signal_emit("theme destroyed", 1, rec);
+
+ g_hash_table_foreach(rec->abstracts, (GHFunc) theme_abstract_destroy, NULL);
+ g_hash_table_destroy(rec->abstracts);
g_hash_table_foreach(rec->modules, (GHFunc) theme_module_destroy, NULL);
g_hash_table_destroy(rec->modules);
+ g_slist_foreach(rec->replace_keys, (GFunc) g_free, NULL);
+ g_slist_free(rec->replace_keys);
+ g_slist_foreach(rec->replace_values, (GFunc) g_free, NULL);
+ g_slist_free(rec->replace_values);
+
g_free(rec->path);
g_free(rec->name);
g_free(rec);
}
+static char *theme_format_expand_data(THEME_REC *theme,
+ const char **format, int root);
+
+static int theme_replace_find(THEME_REC *theme, char chr)
+{
+ GSList *tmp;
+ int index = 0;
+
+ for (tmp = theme->replace_keys; tmp != NULL; tmp = tmp->next) {
+ if (strchr(tmp->data, chr) != NULL)
+ return index;
+ index++;
+ }
+
+ return -1;
+}
+
+static char *theme_replace_expand(THEME_REC *theme, int index, char chr)
+{
+ GSList *rec;
+ char data[2];
+
+ rec = g_slist_nth(theme->replace_values, index);
+ g_return_val_if_fail(rec != NULL, NULL);
+
+ data[0] = chr; data[1] = '\0';
+ return parse_special_string(rec->data, NULL, NULL, data, NULL);
+}
+
+/* append next "item", either a character or $variable */
+static void theme_format_append_next(THEME_REC *theme, GString *str,
+ const char **format)
+{
+ int index;
+ char *value;
+
+ if (**format == '$') {
+ /* $variable .. we'll always need to skip this, since it
+ may contain characters that are in replace chars. */
+ const char *orig;
+ char *args[1] = { NULL };
+ int free_ret;
+
+ orig = *format;
+ (*format)++;
+ value = parse_special((char **) format, NULL, NULL,
+ args, &free_ret, NULL );
+ if (free_ret) g_free(value);
+ (*format)++;
+
+ /* append the variable name */
+ value = g_strndup(orig, (int) (*format-orig));
+ g_string_append(str, value);
+ g_free(value);
+ return;
+ }
+
+ index = theme_replace_find(theme, **format);
+ if (index == -1)
+ g_string_append_c(str, **format);
+ else {
+ value = theme_replace_expand(theme, index, **format);
+ g_string_append(str, value);
+ g_free(value);
+ }
+
+ (*format)++;
+}
+
+/* expand a single {abstract ...data... } */
+static char *theme_format_expand_abstract(THEME_REC *theme,
+ const char **formatp)
+{
+ const char *p, *format;
+ char *abstract, *data, *ret;
+ int len;
+
+ format = *formatp;
+
+ /* get abstract name first */
+ p = format;
+ while (*p != '\0' && *p != ' ' &&
+ *p != '{' && *p != '}') p++;
+ if (*p == '\0' || p == format)
+ return NULL; /* error */
+
+ len = (int) (p-format);
+ abstract = g_strndup(format, len);
+
+ /* skip the following space */
+ if (*p == ' ') len++;
+ *formatp = format + len;
+
+ /* get the abstract data */
+ data = g_hash_table_lookup(theme->abstracts, abstract);
+ g_free(abstract);
+ if (data == NULL) {
+ /* unknown abstract */
+ return NULL;
+ }
+ abstract = g_strdup(data);
+
+ /* abstract may itself contain abstracts or replaces :) */
+ p = data = abstract;
+ abstract = theme_format_expand_data(theme, &p, FALSE);
+ g_free(data);
+
+ /* now we'll need to get the data part. it may contain
+ more abstracts, they are automatically expanded. */
+ data = theme_format_expand_data(theme, formatp, FALSE);
+
+ ret = parse_special_string(abstract, NULL, NULL, data, NULL);
+ g_free(abstract);
+ g_free(data);
+ return ret;
+}
+
+/* expand the data part in {abstract data}. If root is TRUE, we're actually
+ expanding the original format string so we ignore all extra } chars. */
+static char *theme_format_expand_data(THEME_REC *theme,
+ const char **format, int root)
+{
+ GString *str;
+ char *ret, *abstract;
+
+ str = g_string_new(NULL);
+
+ while (**format != '\0') {
+ if (!root && **format == '}') {
+ (*format)++;
+ break;
+ }
+
+ if (**format != '{') {
+ theme_format_append_next(theme, str, format);
+ continue;
+ }
+
+ (*format)++;
+ if (**format == '\0' || **format == '}')
+ break; /* error */
+
+ /* get a single {...} */
+ abstract = theme_format_expand_abstract(theme, format);
+ if (abstract != NULL) {
+ g_string_append(str, abstract);
+ g_free(abstract);
+ }
+ }
+
+ ret = str->str;
+ g_string_free(str, FALSE);
+ return ret;
+}
+
+static char *theme_format_expand(THEME_REC *theme, const char *format)
+{
+ g_return_val_if_fail(theme != NULL, NULL);
+ g_return_val_if_fail(format != NULL, NULL);
+
+ return theme_format_expand_data(theme, &format, TRUE);
+}
+
static MODULE_THEME_REC *theme_module_create(THEME_REC *theme, const char *module)
{
MODULE_THEME_REC *rec;
@@ -94,18 +277,78 @@ static MODULE_THEME_REC *theme_module_create(THEME_REC *theme, const char *modul
for (rec->count = 0; formats[rec->count].def != NULL; rec->count++) ;
rec->formats = g_new0(char *, rec->count);
+ rec->expanded_formats = g_new0(char *, rec->count);
g_hash_table_insert(theme->modules, rec->name, rec);
return rec;
}
-static void theme_read_formats(CONFIG_REC *config, THEME_REC *theme, const char *module)
+static void theme_read_replaces(CONFIG_REC *config, THEME_REC *theme)
+{
+ GSList *tmp;
+ CONFIG_NODE *node;
+
+ node = config_node_traverse(config, "replaces", FALSE);
+ if (node == NULL || node->type != NODE_TYPE_BLOCK) return;
+
+ for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
+ node = tmp->data;
+
+ if (node->key != NULL && node->value != NULL) {
+ theme->replace_keys =
+ g_slist_append(theme->replace_keys,
+ g_strdup(node->key));
+ theme->replace_values =
+ g_slist_append(theme->replace_values,
+ g_strdup(node->value));
+ }
+ }
+}
+
+static void theme_read_abstracts(CONFIG_REC *config, THEME_REC *theme)
+{
+ GSList *tmp;
+ CONFIG_NODE *node;
+
+ node = config_node_traverse(config, "abstracts", FALSE);
+ if (node == NULL || node->type != NODE_TYPE_BLOCK) return;
+
+ for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
+ node = tmp->data;
+
+ if (node->key != NULL && node->value != NULL &&
+ g_hash_table_lookup(theme->abstracts, node->key) == NULL) {
+ g_hash_table_insert(theme->abstracts,
+ g_strdup(node->key),
+ g_strdup(node->value));
+ }
+ }
+}
+
+static void theme_set_format(THEME_REC *theme, MODULE_THEME_REC *rec,
+ FORMAT_REC *formats,
+ const char *key, const char *value)
+{
+ int n;
+
+ for (n = 0; formats[n].def != NULL; n++) {
+ if (formats[n].tag != NULL &&
+ g_strcasecmp(formats[n].tag, key) == 0) {
+ rec->formats[n] = g_strdup(value);
+ rec->expanded_formats[n] =
+ theme_format_expand(theme, value);
+ break;
+ }
+ }
+}
+
+static void theme_read_formats(CONFIG_REC *config, THEME_REC *theme,
+ const char *module)
{
MODULE_THEME_REC *rec;
FORMAT_REC *formats;
CONFIG_NODE *node;
GSList *tmp;
- int n;
formats = g_hash_table_lookup(default_formats, module);
if (formats == NULL) return;
@@ -120,15 +363,9 @@ static void theme_read_formats(CONFIG_REC *config, THEME_REC *theme, const char
for (tmp = node->value; tmp != NULL; tmp = tmp->next) {
node = tmp->data;
- if (node->key == NULL || node->value == NULL)
- continue;
-
- for (n = 0; formats[n].def != NULL; n++) {
- if (formats[n].tag != NULL &&
- g_strcasecmp(formats[n].tag, node->key) == 0) {
- rec->formats[n] = g_strdup(node->value);
- break;
- }
+ if (node->key != NULL && node->value != NULL) {
+ theme_set_format(theme, rec, formats,
+ node->key, node->value);
}
}
}
@@ -241,35 +478,6 @@ THEME_REC *theme_load(const char *name)
return theme;
}
-#if 0
-/* Add all *.theme files from directory to themes */
-static void find_themes(gchar *path)
-{
- DIR *dirp;
- struct dirent *dp;
- char *fname, *name;
- int len;
-
- dirp = opendir(path);
- if (dirp == NULL) return;
-
- while ((dp = readdir(dirp)) != NULL) {
- len = strlen(dp->d_name);
- if (len <= 6 || strcmp(dp->d_name+len-6, ".theme") != 0)
- continue;
-
- name = g_strndup(dp->d_name, strlen(dp->d_name)-6);
- if (!theme_find(name)) {
- fname = g_strdup_printf("%s/%s", path, dp->d_name);
- themes = g_slist_append(themes, theme_create(fname, name));
- g_free(fname);
- }
- g_free(name);
- }
- closedir(dirp);
-}
-#endif
-
typedef struct {
THEME_REC *theme;
CONFIG_REC *config;
@@ -295,6 +503,8 @@ static void theme_read(THEME_REC *theme, const char *path)
config_parse(config);
theme->default_color = config_get_int(config, NULL, "default_color", 15);
+ theme_read_replaces(config, theme);
+ theme_read_abstracts(config, theme);
rec.theme = theme;
rec.config = config;
@@ -377,8 +587,10 @@ static void theme_show(THEME_SEARCH_REC *rec, const char *key, const char *value
if (reset || value != NULL) {
theme = theme_module_create(current_theme, rec->name);
g_free_not_null(theme->formats[n]);
+ g_free_not_null(theme->expanded_formats[n]);
theme->formats[n] = reset ? NULL : g_strdup(value);
+ theme->expanded_formats[n] = reset ? NULL : theme_format_expand(current_theme, value);
text = reset ? formats[n].def : value;
}
printformat(NULL, NULL, MSGLEVEL_CLIENTCRAP, IRCTXT_FORMAT_ITEM, formats[n].tag, text);