mirror of
https://github.com/irssi/irssi.git
synced 2026-08-10 12:23:37 +02:00
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
This commit is contained in:
parent
35fd48a0b4
commit
000ba23aa7
4 changed files with 663 additions and 48 deletions
|
|
@ -436,7 +436,7 @@ char *output_format_get_text(const char *module, WINDOW_REC *window,
|
|||
va_start(va, formatnum);
|
||||
ret = output_format_text_args(&dest, &formats[formatnum],
|
||||
module_theme == NULL ? NULL :
|
||||
module_theme->formats[formatnum], va);
|
||||
module_theme->expanded_formats[formatnum], va);
|
||||
va_end(va);
|
||||
|
||||
return ret;
|
||||
|
|
@ -456,7 +456,7 @@ static char *output_format_text(TEXT_DEST_REC *dest, int formatnum, ...)
|
|||
va_start(va, formatnum);
|
||||
ret = output_format_text_args(dest, &fecommon_core_formats[formatnum],
|
||||
module_theme == NULL ? NULL :
|
||||
module_theme->formats[formatnum], va);
|
||||
module_theme->expanded_formats[formatnum], va);
|
||||
va_end(va);
|
||||
|
||||
return ret;
|
||||
|
|
@ -481,7 +481,7 @@ void printformat_module_args(const char *module, void *server,
|
|||
|
||||
str = output_format_text_args(&dest, &formats[formatnum],
|
||||
module_theme == NULL ? NULL :
|
||||
module_theme->formats[formatnum], va);
|
||||
module_theme->expanded_formats[formatnum], va);
|
||||
if (*str != '\0') print_string(&dest, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
|
@ -511,7 +511,7 @@ void printformat_module_window_args(const char *module, WINDOW_REC *window, int
|
|||
formats = g_hash_table_lookup(default_formats, module);
|
||||
str = output_format_text_args(&dest, &formats[formatnum],
|
||||
module_theme == NULL ? NULL :
|
||||
module_theme->formats[formatnum], va);
|
||||
module_theme->expanded_formats[formatnum], va);
|
||||
if (*str != '\0') print_string(&dest, str);
|
||||
g_free(str);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -8,6 +8,8 @@ typedef struct {
|
|||
|
||||
int count;
|
||||
char **formats; /* in same order as in module's default formats */
|
||||
char **expanded_formats; /* this contains the formats after
|
||||
expanding {templates} */
|
||||
} MODULE_THEME_REC;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -17,6 +19,10 @@ typedef struct {
|
|||
int default_color;
|
||||
GHashTable *modules;
|
||||
|
||||
GSList *replace_keys;
|
||||
GSList *replace_values;
|
||||
GHashTable *abstracts;
|
||||
|
||||
void *gui_data;
|
||||
} THEME_REC;
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue