X-Git-Url: https://git.stderr.nl/gitweb?a=blobdiff_plain;f=libchimara%2Fstyle.c;h=3f86bad2573b2f54565e6ef605b266c1183f03f9;hb=2ce0ccd78003fce557bb76883c87ca2cb101608d;hp=3826ebfc4d1fcf482de4fc8c8ee7cb81f97166f6;hpb=464d51cc55900461a61982dce7665dd9423e1c28;p=rodin%2Fchimara.git diff --git a/libchimara/style.c b/libchimara/style.c index 3826ebf..3f86bad 100644 --- a/libchimara/style.c +++ b/libchimara/style.c @@ -1,6 +1,9 @@ #include "style.h" +#include +#include extern GPrivate *glk_data_key; +static gboolean chimara_style_initialized = FALSE; /** * glk_set_style: @@ -63,19 +66,265 @@ style_init_textbuffer(GtkTextBuffer *buffer) { g_return_if_fail(buffer != NULL); + if( G_UNLIKELY(!chimara_style_initialized) ) { + style_init(); + } + + ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + g_hash_table_foreach(glk_data->default_styles, style_add_tag_to_textbuffer, gtk_text_buffer_get_tag_table(buffer)); +} + +static void +style_add_tag_to_textbuffer(gpointer key, gpointer tag, gpointer tag_table) +{ + gtk_text_tag_table_add(tag_table, tag); +} + +void +style_init() +{ ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + GtkTextTag *tag; + + /* Create the CSS file scanner */ + GScanner *scanner = g_scanner_new(NULL); + int f = open(glk_data->css_file, O_RDONLY); + g_return_if_fail(f != -1); + g_scanner_input_file(scanner, f); + scanner->input_name = glk_data->css_file; + scanner->config->cset_identifier_first = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ#"; + scanner->config->cset_identifier_nth = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_0123456789"; + scanner->config->symbol_2_token = TRUE; + scanner->config->cpair_comment_single = NULL; + + /* Initialise the default styles */ + g_hash_table_insert(glk_data->default_styles, "normal", gtk_text_tag_new("normal")); + + tag = gtk_text_tag_new("emphasized"); + g_object_set(tag, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL); + g_hash_table_insert(glk_data->default_styles, "emphasized", tag); + + tag = gtk_text_tag_new("preformatted"); + g_object_set(tag, "font-desc", glk_data->monospace_font_desc, NULL); + g_hash_table_insert(glk_data->default_styles, "preformatted", tag); + + tag = gtk_text_tag_new("header"); + g_object_set(tag, "size-points", 18.0, "weight", PANGO_WEIGHT_BOLD, NULL); + g_hash_table_insert(glk_data->default_styles, "header", tag); + + tag = gtk_text_tag_new("subheader"); + g_object_set(tag, "size-points", 14.0, "weight", PANGO_WEIGHT_BOLD, NULL); + g_hash_table_insert(glk_data->default_styles, "subheader", tag); + + tag = gtk_text_tag_new("alert"); + g_object_set(tag, "foreground", "#aa0000", "weight", PANGO_WEIGHT_BOLD, NULL); + g_hash_table_insert(glk_data->default_styles, "alert", tag); + + tag = gtk_text_tag_new("note"); + g_object_set(tag, "foreground", "#aaaa00", "weight", PANGO_WEIGHT_BOLD, NULL); + g_hash_table_insert(glk_data->default_styles, "note", tag); + + tag = gtk_text_tag_new("block-quote"); + g_object_set(tag, "justification", GTK_JUSTIFY_CENTER, "style", PANGO_STYLE_ITALIC, NULL); + g_hash_table_insert(glk_data->default_styles, "block-quote", tag); + + g_hash_table_insert(glk_data->default_styles, "input", gtk_text_tag_new("input")); + g_hash_table_insert(glk_data->default_styles, "user1", gtk_text_tag_new("user1")); + g_hash_table_insert(glk_data->default_styles, "user2", gtk_text_tag_new("user2")); + + /* Run the scanner over the CSS file */ + while( g_scanner_peek_next_token(scanner) != G_TOKEN_EOF) { + if( !style_accept_style_identifier(scanner) ) + break; + } + + g_scanner_destroy(scanner); +} + +static gboolean +style_accept(GScanner *scanner, GTokenType token) +{ + if( g_scanner_get_next_token(scanner) != token ) { + g_scanner_unexp_token(scanner, token, NULL, NULL, NULL, "CSS Error", 1); + return FALSE; + } else { + return TRUE; + } +} + +static gboolean +style_accept_style_identifier(GScanner *scanner) +{ + ChimaraGlkPrivate *glk_data = g_private_get(glk_data_key); + + GtkTextTag *current_tag; + GTokenType token = g_scanner_get_next_token(scanner); + GTokenValue value = g_scanner_cur_value(scanner); + + if(token != G_TOKEN_IDENTIFIER) { + g_scanner_error(scanner, "CSS Error: style identifier expected"); + return FALSE; + } + + printf("Identifier: %s\n", value.v_identifier); + current_tag = g_hash_table_lookup(glk_data->default_styles, value.v_identifier); + + if(current_tag == NULL) { + g_scanner_error(scanner, "CSS Error: invalid style identifier"); + return FALSE; + } + + if( !style_accept(scanner, '{') ) + return FALSE; + + while( g_scanner_peek_next_token(scanner) != '}') { + if( !style_accept_style_hint(scanner, current_tag) ) + return FALSE; + } + + if( !style_accept(scanner, '}') ) + return FALSE; + + return TRUE; +} + +static gboolean +style_accept_style_hint(GScanner *scanner, GtkTextTag *current_tag) +{ + GTokenType token = g_scanner_get_next_token(scanner); + GTokenValue value = g_scanner_cur_value(scanner); + gchar *hint; + + if(token != G_TOKEN_IDENTIFIER) { + g_scanner_error(scanner, "CSS Error: style hint expected"); + return FALSE; + } + + hint = g_strdup(value.v_identifier); + printf("Hint: %s\n", hint); + + if( !style_accept(scanner, ':') ) + return FALSE; + + token = g_scanner_get_next_token(scanner); + value = g_scanner_cur_value(scanner); + + if( !strcmp(hint, "font-family") ) { + if(token != G_TOKEN_STRING) { + g_scanner_error(scanner, "CSS Error: string expected"); + return FALSE; + } + g_object_set(current_tag, "family", value.v_string, "family-set", TRUE, NULL); + } + else if( !strcmp(hint, "font-weight") ) { + if(token != G_TOKEN_IDENTIFIER) { + g_scanner_error(scanner, "CSS Error: bold/normal expected"); + return FALSE; + } + + if( !strcmp(value.v_identifier, "bold") ) + g_object_set(current_tag, "weight", PANGO_WEIGHT_BOLD, "weight-set", TRUE, NULL); + else if( !strcmp(value.v_identifier, "normal") ) + g_object_set(current_tag, "weight", PANGO_WEIGHT_NORMAL, "weight-set", TRUE, NULL); + else { + g_scanner_error(scanner, "CSS Error: bold/normal expected"); + return FALSE; + } + } + else if( !strcmp(hint, "font-style") ) { + if(token != G_TOKEN_IDENTIFIER) { + g_scanner_error(scanner, "CSS Error: italic/normal expected"); + return FALSE; + } + + if( !strcmp(value.v_identifier, "italic") ) + g_object_set(current_tag, "style", PANGO_STYLE_ITALIC, "style-set", TRUE, NULL); + else if( !strcmp(value.v_identifier, "normal") ) + g_object_set(current_tag, "style", PANGO_STYLE_NORMAL, "style-set", TRUE, NULL); + else { + g_scanner_error(scanner, "CSS Error: italic/normal expected"); + return FALSE; + } + } + else if( !strcmp(hint, "font-size") ) { + if(token == G_TOKEN_INT) + g_object_set(current_tag, "size-points", (float)value.v_int, "size-set", TRUE, NULL); + else if(token == G_TOKEN_FLOAT) + g_object_set(current_tag, "size-points", value.v_float, "size-set", TRUE, NULL); + else { + g_scanner_error(scanner, "CSS Error: integer or float expected"); + return FALSE; + } + } + else if( !strcmp(hint, "color") ) { + if(token != G_TOKEN_IDENTIFIER) { + g_scanner_error(scanner, "CSS Error: hex color expected"); + return FALSE; + } + g_object_set(current_tag, "foreground", value.v_identifier, "foreground-set", TRUE, NULL); + } + else if( !strcmp(hint, "background-color") ) { + if(token != G_TOKEN_IDENTIFIER) { + g_scanner_error(scanner, "CSS Error: hex color expected"); + return FALSE; + } + g_object_set(current_tag, "background", value.v_identifier, "background-set", TRUE, NULL); + } + else if( !strcmp(hint, "text-align") ) { + if(token != G_TOKEN_IDENTIFIER) { + g_scanner_error(scanner, "CSS Error: left/right/center expected"); + return FALSE; + } + + if( !strcmp(value.v_identifier, "left") ) + g_object_set(current_tag, "justification", GTK_JUSTIFY_LEFT, "justification-set", TRUE, NULL); + else if( !strcmp(value.v_identifier, "right") ) + g_object_set(current_tag, "justification", GTK_JUSTIFY_RIGHT, "justification-set", TRUE, NULL); + else if( !strcmp(value.v_identifier, "center") ) + g_object_set(current_tag, "justification", GTK_JUSTIFY_CENTER, "justification-set", TRUE, NULL); + else { + g_scanner_error(scanner, "CSS Error: left/right/center expected"); + return FALSE; + } + } + else if( !strcmp(hint, "margin-left") ) { + if(token != G_TOKEN_INT) { + g_scanner_error(scanner, "CSS Error: integer expected"); + return FALSE; + } + g_object_set(current_tag, "left-margin", value.v_int, "left-margin-set", TRUE, NULL); + } + else if( !strcmp(hint, "margin-right") ) { + if(token != G_TOKEN_INT) { + g_scanner_error(scanner, "CSS Error: integer expected"); + return FALSE; + } + g_object_set(current_tag, "right-margin", value.v_int, "right-margin-set", TRUE, NULL); + } + else if( !strcmp(hint, "margin-top") ) { + if(token != G_TOKEN_INT) { + g_scanner_error(scanner, "CSS Error: integer expected"); + return FALSE; + } + g_object_set(current_tag, "pixels-above-lines", value.v_int, "pixels-above-lines-set", TRUE, NULL); + } + else if( !strcmp(hint, "margin-bottom") ) { + if(token != G_TOKEN_INT) { + g_scanner_error(scanner, "CSS Error: integer expected"); + return FALSE; + } + g_object_set(current_tag, "pixels-below-lines", value.v_int, "pixels-below-lines-set", TRUE, NULL); + } + + else { + g_scanner_error(scanner, "CSS Error: invalid style hint %s", hint); + return FALSE; + } + + if( !style_accept(scanner, ';') ) + return FALSE; - gtk_text_buffer_create_tag(buffer, "normal", NULL); - gtk_text_buffer_create_tag(buffer, "emphasized", "style", PANGO_STYLE_ITALIC, NULL); - gtk_text_buffer_create_tag(buffer, "preformatted", "font-desc", glk_data->monospace_font_desc, NULL); - gtk_text_buffer_create_tag(buffer, "header", "size-points", 18.0, "weight", PANGO_WEIGHT_BOLD, NULL); - gtk_text_buffer_create_tag(buffer, "subheader", "size-points", 14.0, "weight", PANGO_WEIGHT_BOLD, NULL); - gtk_text_buffer_create_tag(buffer, "alert", "foreground", "#aa0000", "weight", PANGO_WEIGHT_BOLD, NULL); - gtk_text_buffer_create_tag(buffer, "note", "foreground", "#aaaa00", "weight", PANGO_WEIGHT_BOLD, NULL); - gtk_text_buffer_create_tag(buffer, "block-quote", "justification", GTK_JUSTIFY_CENTER, "style", PANGO_STYLE_ITALIC, NULL); - gtk_text_buffer_create_tag(buffer, "input", NULL); - gtk_text_buffer_create_tag(buffer, "user1", NULL); - gtk_text_buffer_create_tag(buffer, "user2", NULL); + return TRUE; } static void