From c6abe4626c40d4925d6233cf0ca1c30cd49a22cd Mon Sep 17 00:00:00 2001 From: Thomas White Date: Sat, 14 Sep 2019 23:45:38 +0200 Subject: Handle *bold* in parser, rather than as a separate stage --- libstorycode/gtk/gtknarrativeview.c | 67 ++++---- libstorycode/narrative.c | 134 ++++++++++++---- libstorycode/narrative.h | 22 ++- libstorycode/narrative_priv.h | 13 +- libstorycode/narrative_render_cairo.c | 285 ++++++++++------------------------ libstorycode/narrative_render_cairo.h | 2 + libstorycode/scparse_priv.h | 7 +- libstorycode/storycode.c | 22 ++- libstorycode/storycode.l | 39 +++-- libstorycode/storycode.y | 113 +++++++++----- src/colloquium.c | 2 +- 11 files changed, 371 insertions(+), 335 deletions(-) diff --git a/libstorycode/gtk/gtknarrativeview.c b/libstorycode/gtk/gtknarrativeview.c index 0fe2c59..bb549d4 100644 --- a/libstorycode/gtk/gtknarrativeview.c +++ b/libstorycode/gtk/gtknarrativeview.c @@ -343,7 +343,7 @@ static void paste_text_received(GtkClipboard *cb, GtkSelectionData *seldata, // } // // para = e->cursor_frame->paras[e->cpos.para]; -// offs = pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail); +// offs = narrative_pos_trail_to_offset(para, e->cpos.pos, e->cpos.trail); // // get_sc_pos(e->cursor_frame, e->cpos.para, offs, &cur_bl, &cur_sc_pos); // sc_insert_block(cur_bl, cur_sc_pos, bl); @@ -496,22 +496,6 @@ static void draw_para_highlight(cairo_t *cr, Narrative *n, int cursor_para, } -static size_t pos_trail_to_offset(struct narrative_item *item, int offs, int trail) -{ - glong char_offs; - char *ptr; - - if ( item->type == NARRATIVE_ITEM_SLIDE ) { - return offs; - } - - char_offs = g_utf8_pointer_to_offset(item->layout_text, item->layout_text+offs); - char_offs += trail; - ptr = g_utf8_offset_to_pointer(item->layout_text, char_offs); - return ptr - item->layout_text; -} - - static void get_cursor_pos(Narrative *n, struct edit_pos cpos, double *x, double *y, double *h) { @@ -532,7 +516,7 @@ static void get_cursor_pos(Narrative *n, struct edit_pos cpos, return; } - offs = pos_trail_to_offset(item, cpos.pos, cpos.trail); + offs = narrative_pos_trail_to_offset(n, cpos.para, cpos.pos, cpos.trail); pango_layout_get_cursor_pos(item->layout, offs, &rect, NULL); *x = pango_units_to_double(rect.x) + item->space_l; *y = pango_units_to_double(rect.y) + para_top(n, cpos.para) + item->space_t; @@ -656,9 +640,14 @@ static void check_cursor_visible(GtkNarrativeView *e) static size_t end_offset_of_para(Narrative *n, int pnum) { + int i; + size_t len; assert(pnum >= 0); if ( !narrative_item_is_text(n, pnum) ) return 0; - return strlen(n->items[pnum].text); + for ( i=0; iitems[pnum].n_runs; i++ ) { + len += strlen(n->items[pnum].runs[i].text); + } + return len; } @@ -773,8 +762,6 @@ static void do_backspace(GtkNarrativeView *e, signed int dir) { struct edit_pos p1, p2; size_t o1, o2; - struct narrative_item *item1; - struct narrative_item *item2; if ( !positions_equal(e->sel_start, e->sel_end) ) { @@ -791,12 +778,8 @@ static void do_backspace(GtkNarrativeView *e, signed int dir) } sort_positions(&p1, &p2); - item1 = &e->n->items[p1.para]; - item2 = &e->n->items[p2.para]; - o1 = pos_trail_to_offset(item1, p1.pos, p1.trail); - o2 = pos_trail_to_offset(item2, p2.pos, p2.trail); - o1 = layout_index_to_text(item1, o1); - o2 = layout_index_to_text(item2, o2); + o1 = narrative_pos_trail_to_offset(e->n, p1.para, p1.pos, p1.trail); + o2 = narrative_pos_trail_to_offset(e->n, p2.para, p2.pos, p2.trail); narrative_delete_block(e->n, p1.para, o1, p2.para, o2); e->cpos = p1; unset_selection(e); @@ -815,14 +798,25 @@ static void do_backspace(GtkNarrativeView *e, signed int dir) static void insert_text_in_paragraph(struct narrative_item *item, size_t offs, char *t) { - char *n = malloc(strlen(t) + strlen(item->text) + 1); + char *n; + int run; + size_t pos; + + pos = 0; + for ( run=0; runn_runs; run++ ) { + pos += strlen(item->runs[run].text); + if ( pos > offs ) break; + } + offs -= pos; + + n = malloc(strlen(t) + strlen(item->runs[run].text) + 1); if ( n == NULL ) return; - strncpy(n, item->text, offs); + strncpy(n, item->runs[run].text, offs); n[offs] = '\0'; strcat(n, t); - strcat(n, item->text+offs); - free(item->text); - item->text = n; + strcat(n, item->runs[run].text+offs); + free(item->runs[run].text); + item->runs[run].text = n; } @@ -838,8 +832,7 @@ static void insert_text(char *t, GtkNarrativeView *e) if ( narrative_item_is_text(e->n, e->cpos.para) ) { - size_t off = pos_trail_to_offset(item, e->cpos.pos, e->cpos.trail); - off = layout_index_to_text(item, off); + size_t off = narrative_pos_trail_to_offset(e->n, e->cpos.para, e->cpos.pos, e->cpos.trail); if ( strcmp(t, "\n") == 0 ) { narrative_split_item(e->n, e->cpos.para, off); @@ -1208,9 +1201,9 @@ void gtk_narrative_view_add_slide_at_cursor(GtkNarrativeView *e) if ( s == NULL ) return; if ( narrative_item_is_text(e->n, e->cpos.para) ) { - size_t off = pos_trail_to_offset(&e->n->items[e->cpos.para], - e->cpos.pos, e->cpos.trail); - if ( (off > 0) && (off < strlen(e->n->items[e->cpos.para].text)) ) { + size_t off = narrative_pos_trail_to_offset(e->n, e->cpos.para, + e->cpos.pos, e->cpos.trail); + if ( (off > 0) && (off < end_offset_of_para(e->n, e->cpos.para)) ) { narrative_split_item(e->n, e->cpos.para, off); narrative_insert_slide(e->n, s, e->cpos.para+1); } else if ( off == 0 ) { diff --git a/libstorycode/narrative.c b/libstorycode/narrative.c index 7db31d9..6ed427d 100644 --- a/libstorycode/narrative.c +++ b/libstorycode/narrative.c @@ -70,13 +70,15 @@ Narrative *narrative_new() static void narrative_item_destroy(struct narrative_item *item) { - free(item->text); + int i; + for ( i=0; in_runs; i++ ) { + free(item->runs[i].text); + } + free(item->runs); #ifdef HAVE_PANGO if ( item->layout != NULL ) { g_object_unref(item->layout); } - free(item->chars_removed); - free(item->layout_text); #endif #ifdef HAVE_CAIRO if ( item->slide_thumbnail != NULL ) { @@ -98,6 +100,24 @@ void narrative_free(Narrative *n) } +void narrative_add_empty_item(Narrative *n) +{ + char **texts; + enum narrative_run_type *types; + char *text; + + texts = malloc(sizeof(char *)); + types = malloc(sizeof(enum narrative_run_type)); + text = strdup(""); + + if ( (texts != NULL) && (types != NULL) && (text != NULL) ) { + texts[0] = text; + types[0] = NARRATIVE_RUN_NORMAL; + narrative_add_text(n, texts, types, 1); + } +} + + Narrative *narrative_load(GFile *file) { GBytes *bytes; @@ -115,7 +135,7 @@ Narrative *narrative_load(GFile *file) if ( n->n_items == 0 ) { /* Presentation is empty. Add a dummy to start things off */ - narrative_add_text(n, strdup("")); + narrative_add_empty_item(n); } imagestore_set_parent(n->imagestore, g_file_get_parent(file)); @@ -204,11 +224,9 @@ static void init_item(struct narrative_item *item) { #ifdef HAVE_PANGO item->layout = NULL; - item->layout_text = NULL; - item->chars_removed = NULL; - item->n_chars_removed = 0; #endif - item->text = NULL; + item->runs = NULL; + item->n_runs = 0; item->slide = NULL; item->slide_thumbnail = NULL; } @@ -238,45 +256,52 @@ static struct narrative_item *insert_item(Narrative *n, int pos) } -void narrative_add_prestitle(Narrative *n, char *text) +extern void add_text_item(Narrative *n, char **texts, enum narrative_run_type *types, + int n_runs, enum narrative_item_type type) { struct narrative_item *item; + int i; item = add_item(n); if ( item == NULL ) return; - item->type = NARRATIVE_ITEM_PRESTITLE; - item->text = text; + item->type = type; item->align = ALIGN_INHERIT; item->layout = NULL; -} + /* Add all the runs */ + item->runs = malloc(n_runs * sizeof(struct narrative_text_run)); + if ( item->runs == NULL ) { + item->n_runs = 0; + return; + } -void narrative_add_bp(Narrative *n, char *text) -{ - struct narrative_item *item; + for ( i=0; iruns[i].type = types[i]; + item->runs[i].text = texts[i]; + } + item->n_runs = n_runs; +} - item = add_item(n); - if ( item == NULL ) return; - item->type = NARRATIVE_ITEM_BP; - item->text = text; - item->align = ALIGN_INHERIT; - item->layout = NULL; +void narrative_add_text(Narrative *n, char **texts, + enum narrative_run_type *types, int n_runs) +{ + add_text_item(n, texts, types, n_runs, NARRATIVE_ITEM_TEXT); } -void narrative_add_text(Narrative *n, char *text) +void narrative_add_prestitle(Narrative *n, char **texts, + enum narrative_run_type *types, int n_runs) { - struct narrative_item *item; + add_text_item(n, texts, types, n_runs, NARRATIVE_ITEM_PRESTITLE); +} - item = add_item(n); - if ( item == NULL ) return; - item->type = NARRATIVE_ITEM_TEXT; - item->text = text; - item->align = ALIGN_INHERIT; - item->layout = NULL; +void narrative_add_bp(Narrative *n, char **texts, + enum narrative_run_type *types, int n_runs) +{ + add_text_item(n, texts, types, n_runs, NARRATIVE_ITEM_BP); } @@ -327,6 +352,7 @@ static void delete_item(Narrative *n, int del) /* Delete from item i1 offset o1 to item i2 offset o2, inclusive */ void narrative_delete_block(Narrative *n, int i1, size_t o1, int i2, size_t o2) { +#if 0 int i; int n_del = 0; int merge = 1; @@ -388,11 +414,13 @@ void narrative_delete_block(Narrative *n, int i1, size_t o1, int i2, size_t o2) n->items[i1].text = new_text; delete_item(n, i2); } +#endif } void narrative_split_item(Narrative *n, int i1, size_t o1) { +#if 0 struct narrative_item *item1; struct narrative_item *item2; @@ -407,6 +435,7 @@ void narrative_split_item(Narrative *n, int i1, size_t o1) } item2->type = NARRATIVE_ITEM_TEXT; +#endif } @@ -482,3 +511,50 @@ Slide *narrative_get_slide_by_number(Narrative *n, int pos) } return NULL; } + + +static void debug_runs(struct narrative_item *item) +{ + int j; + for ( j=0; jn_runs; j++ ) { + printf("Run %i: '%s'\n", j, item->runs[j].text); + } +} + +void narrative_debug(Narrative *n) +{ + int i; + + for ( i=0; in_items; i++ ) { + + struct narrative_item *item = &n->items[i]; + printf("Item %i ", i); + switch ( item->type ) { + + case NARRATIVE_ITEM_TEXT : + printf("(text):\n"); + debug_runs(item); + break; + + case NARRATIVE_ITEM_BP : + printf("(bp):\n"); + debug_runs(item); + break; + + case NARRATIVE_ITEM_PRESTITLE : + printf("(prestitle):\n"); + debug_runs(item); + break; + + case NARRATIVE_ITEM_EOP : + printf("(EOP marker)\n"); + break; + + case NARRATIVE_ITEM_SLIDE : + printf("(slide)\n"); + break; + + } + + } +} diff --git a/libstorycode/narrative.h b/libstorycode/narrative.h index 3e21ca1..a51136b 100644 --- a/libstorycode/narrative.h +++ b/libstorycode/narrative.h @@ -31,11 +31,20 @@ typedef struct _narrative Narrative; +enum narrative_run_type +{ + NARRATIVE_RUN_NORMAL, + NARRATIVE_RUN_BOLD, + NARRATIVE_RUN_ITALIC, + NARRATIVE_RUN_UNDERLINE, +}; + #include "slide.h" #include "imagestore.h" extern Narrative *narrative_new(void); extern void narrative_free(Narrative *n); +extern void narrative_add_empty_item(Narrative *n); extern void narrative_add_stylesheet(Narrative *n, Stylesheet *ss); extern Stylesheet *narrative_get_stylesheet(Narrative *n); @@ -51,9 +60,15 @@ extern int narrative_get_unsaved(Narrative *n); extern int narrative_item_is_text(Narrative *n, int item); -extern void narrative_add_prestitle(Narrative *n, char *text); -extern void narrative_add_bp(Narrative *n, char *text); -extern void narrative_add_text(Narrative *n, char *text); +extern void narrative_add_text(Narrative *n, char **texts, + enum narrative_run_type *types, int n_runs); + +extern void narrative_add_bp(Narrative *n, char **texts, + enum narrative_run_type *types, int n_runs); + +extern void narrative_add_prestitle(Narrative *n, char **texts, + enum narrative_run_type *types, int n_runs); + extern void narrative_add_slide(Narrative *n, Slide *slide); extern void narrative_add_eop(Narrative *n); extern void narrative_insert_slide(Narrative *n, Slide *slide, int pos); @@ -68,5 +83,6 @@ extern Slide *narrative_get_slide_by_number(Narrative *n, int pos); extern int narrative_get_slide_number_for_para(Narrative *n, int para); extern int narrative_get_slide_number_for_slide(Narrative *n, Slide *s); +extern void narrative_debug(Narrative *n); #endif /* NARRATIVE_H */ diff --git a/libstorycode/narrative_priv.h b/libstorycode/narrative_priv.h index 86aa612..c783df2 100644 --- a/libstorycode/narrative_priv.h +++ b/libstorycode/narrative_priv.h @@ -42,6 +42,13 @@ enum narrative_item_type }; +struct narrative_text_run +{ + enum narrative_run_type type; + char *text; +}; + + struct narrative_item { enum narrative_item_type type; @@ -60,13 +67,11 @@ struct narrative_item * obj_w + space_l + space_r might be less than width of rendering surface */ /* For TEXT, BP, PRESTITLE */ - char *text; + int n_runs; + struct narrative_text_run *runs; enum alignment align; #ifdef HAVE_PANGO PangoLayout *layout; - char *layout_text; - int *chars_removed; - int n_chars_removed; #else void *layout; #endif diff --git a/libstorycode/narrative_render_cairo.c b/libstorycode/narrative_render_cairo.c index aaa05ee..8b009b5 100644 --- a/libstorycode/narrative_render_cairo.c +++ b/libstorycode/narrative_render_cairo.c @@ -69,197 +69,6 @@ static PangoAlignment to_pangoalignment(enum alignment align) } -static int find_pair(const gchar *p, gunichar c, gchar **start, gchar **end) -{ - gchar *s; - gchar *e; - gchar *next; - - /* FIXME: Check it's not escaped */ - s = g_utf8_strchr(p, -1, c); - if ( s == NULL ) return 0; - - next = g_utf8_find_next_char(s, NULL); - if ( next == NULL ) return 0; - - e = g_utf8_strchr(next, -1, c); - if ( e == NULL ) return 0; - - *start = s; - *end = e; - return 1; -} - - -struct attr_to_add -{ - int start; - int end; - char type; /* b=bold, i=italic, u=underline */ -}; - - -static int add_range(struct narrative_item *item, int *max_chars_removed, - int start, int end, int *n_add, int *max_add, - struct attr_to_add **add, char type) -{ - if ( item->n_chars_removed == *max_chars_removed ) { - (*max_chars_removed) += 256; - item->chars_removed = realloc(item->chars_removed, *max_chars_removed*sizeof(int)); - if ( item->chars_removed == NULL ) return 1; - } - - item->chars_removed[item->n_chars_removed++] = start; - item->chars_removed[item->n_chars_removed++] = end; - - if ( *n_add == *max_add ) { - *max_add += 64; - *add = realloc(*add, *max_add*sizeof(struct attr_to_add)); - if ( *add == NULL ) return 1; - } - - /* Indices NOT including the markers */ - (*add)[*n_add].start = start+1; - (*add)[*n_add].end = end-1; - (*add)[*n_add].type = type; - (*n_add)++; - - return 0; -} - - -/* How many bytes were removed up to idx? */ -int layout_index_to_text(struct narrative_item *item, int idx) -{ - int i; - - for ( i=0; in_chars_removed; i++ ) { - if ( item->chars_removed[i] > idx ) break; - } - - return idx + i; -} - - -/* How many bytes were removed up to idx? */ -int text_index_to_layout(struct narrative_item *item, int idx) -{ - int i; - - for ( i=0; in_chars_removed; i++ ) { - assert(item->chars_removed[i] != idx); - if ( item->chars_removed[i] > idx ) break; - } - - return idx - i; -} - - -static int cmpi(const void *a, const void *b) -{ - return *(int *)a - *(int *)b; -} - - -static void process_tags(struct narrative_item *item, PangoAttrList *attrs) -{ - gchar *efstart; - gchar *efend; - gchar *text; - PangoAttribute *attr; - struct attr_to_add *add; - int n_add; - int max_add; - int max_chars_removed; - int i, j, k; - size_t len; - - item->n_chars_removed = 0; - free(item->chars_removed); - item->chars_removed = NULL; - max_chars_removed = 0; - - add = NULL; - n_add = 0; - max_add = 0; - - /* Scan the text, identify characters to remove and character ranges - * (in the original text) which need attributes applied */ - text = item->text; - while ( find_pair(text, '*', &efstart, &efend) ) { - if ( add_range(item, &max_chars_removed, - efstart - item->text, efend - item->text, - &n_add, &max_add, &add, 'b') ) return; - text = g_utf8_find_next_char(efend, NULL); - } - text = item->text; - while ( find_pair(text, '/', &efstart, &efend) ) { - if ( add_range(item, &max_chars_removed, - efstart - item->text, efend - item->text, - &n_add, &max_add, &add, 'i') ) return; - text = g_utf8_find_next_char(efend, NULL); - } - text = item->text; - while ( find_pair(text, '_', &efstart, &efend) ) { - if ( add_range(item, &max_chars_removed, - efstart - item->text, efend - item->text, - &n_add, &max_add, &add, 'u') ) return; - text = g_utf8_find_next_char(efend, NULL); - } - - /* Sort the list of removed characters */ - qsort(item->chars_removed, item->n_chars_removed, sizeof(int), cmpi); - - /* Go through the list of attributes, and correct the character ranges - * so that they refer to the text with characters removed, and add them - * to the PangoAttrList */ - for ( i=0; istart_index = text_index_to_layout(item, add[i].start); - - attr->end_index = text_index_to_layout(item, add[i].end)+1; - - pango_attr_list_insert(attrs, attr); - - } - - /* Create the version of the text with characters removed */ - if ( item->n_chars_removed == 0 ) { - item->layout_text = strdup(item->text); - } else { - len = strlen(item->text); - item->layout_text = malloc(len); - if ( item->layout_text == NULL ) return; - j = 0; - for ( i=0; ichars_removed[k] == i ) { - k++; - } else { - item->layout_text[j++] = item->text[i]; - } - } - } - - free(add); -} - - static void wrap_text(struct narrative_item *item, PangoContext *pc, Stylesheet *ss, const char *stn, double w, size_t sel_start, size_t sel_end) @@ -314,13 +123,67 @@ static void wrap_text(struct narrative_item *item, PangoContext *pc, pango_layout_set_alignment(item->layout, palignment); pango_layout_set_font_description(item->layout, fontdesc); - /* Handle *bold*, _underline_, /italic/ etc. */ - process_tags(item, attrs); + size_t total_len = 0; + int i; + char *text; + + /* Work out length of all text in item (paragraph) */ + for ( i=0; in_runs; i++ ) { + total_len += strlen(item->runs[i].text); + } + + /* Allocate the complete text */ + text = malloc(total_len+1); + if ( text == NULL ) { + fprintf(stderr, "Couldn't allocate combined text (%lli)\n", + (long long int)total_len); + return; + } + + /* Put all of the text together */ + text[0] = '\0'; + size_t pos = 0; + for ( i=0; in_runs; i++ ) { + + PangoAttribute *attr = NULL; + size_t run_len = strlen(item->runs[i].text); + + switch ( item->runs[i].type ) { + + case NARRATIVE_RUN_NORMAL : + break; + + case NARRATIVE_RUN_BOLD: + attr = pango_attr_weight_new(PANGO_WEIGHT_BOLD); + break; + + case NARRATIVE_RUN_ITALIC: + attr = pango_attr_style_new(PANGO_STYLE_ITALIC); + break; + + case NARRATIVE_RUN_UNDERLINE: + attr = pango_attr_underline_new(PANGO_UNDERLINE_SINGLE); + break; + + + + } + + if ( attr != NULL ) { + attr->start_index = pos; + attr->end_index = pos + run_len; + pango_attr_list_insert(attrs, attr); + } + + /* FIXME: Should check that each bit of text finishes on a character boundary */ + pos += run_len; + strcat(text, item->runs[i].text); + + } pango_layout_set_attributes(item->layout, attrs); + pango_layout_set_text(item->layout, text, -1); pango_attr_list_unref(attrs); - pango_layout_set_text(item->layout, item->layout_text, -1); - pango_layout_get_extents(item->layout, NULL, &rect); item->obj_w = pango_units_to_double(rect.width); item->obj_h = pango_units_to_double(rect.height); @@ -387,18 +250,30 @@ static void wrap_slide(struct narrative_item *item, Stylesheet *ss, ImageStore * } -static size_t pos_trail_to_offset(Narrative *n, int i, int offs, int trail) +size_t narrative_pos_trail_to_offset(Narrative *n, int i, int offs, int trail) { - glong char_offs; - char *ptr; + int run; struct narrative_item *item = &n->items[i]; + size_t pos; if ( !narrative_item_is_text(n, i) ) return offs; - char_offs = g_utf8_pointer_to_offset(item->text, item->text+offs); - char_offs += trail; - ptr = g_utf8_offset_to_pointer(item->text, char_offs); - return ptr - item->text; + pos = 0; + for ( run=0; runn_runs; run++ ) { + pos += strlen(item->runs[run].text); + if ( pos > offs ) { + glong char_offs; + char *ptr; + char_offs = g_utf8_pointer_to_offset(item->runs[run].text, + item->runs[run].text+offs); + char_offs += trail; + ptr = g_utf8_offset_to_pointer(item->runs[run].text, char_offs); + return ptr - item->runs[run].text; + } + } + + fprintf(stderr, "narrative_pos_trail_to_offset: Outside last run\n"); + return 0; } @@ -465,8 +340,10 @@ int narrative_wrap_range(Narrative *n, Stylesheet *stylesheet, PangoLanguage *la if ( max >= n->n_items ) max = n->n_items-1; if ( !positions_equal(sel_start, sel_end) ) { - sel_s = pos_trail_to_offset(n, sel_start.para, sel_start.pos, sel_start.trail); - sel_e = pos_trail_to_offset(n, sel_end.para, sel_end.pos, sel_end.trail); + sel_s = narrative_pos_trail_to_offset(n, sel_start.para, + sel_start.pos, sel_start.trail); + sel_e = narrative_pos_trail_to_offset(n, sel_end.para, + sel_end.pos, sel_end.trail); } else { sel_s = 0; sel_e = 0; diff --git a/libstorycode/narrative_render_cairo.h b/libstorycode/narrative_render_cairo.h index c62d2e9..bfd2a05 100644 --- a/libstorycode/narrative_render_cairo.h +++ b/libstorycode/narrative_render_cairo.h @@ -46,6 +46,8 @@ extern double narrative_get_height(Narrative *n); extern double narrative_item_get_height(Narrative *n, int i); +extern size_t narrative_pos_trail_to_offset(Narrative *n, int i, int offs, int trail); + extern int narrative_render_item_cairo(Narrative*n, cairo_t *cr, int i); extern int narrative_render_cairo(Narrative *n, cairo_t *cr, diff --git a/libstorycode/scparse_priv.h b/libstorycode/scparse_priv.h index 3d97ead..98ddbda 100644 --- a/libstorycode/scparse_priv.h +++ b/libstorycode/scparse_priv.h @@ -42,9 +42,10 @@ struct scpctx Narrative *n; Slide *s; - int n_str; - int max_str; - char **str; + int n_runs; + int max_runs; + char **runs; + enum narrative_run_type *run_types; /* Current style or frame options. * These will be copied to a stylesheet entry or frame when the diff --git a/libstorycode/storycode.c b/libstorycode/storycode.c index ca0d2d0..e17d5dd 100644 --- a/libstorycode/storycode.c +++ b/libstorycode/storycode.c @@ -40,14 +40,19 @@ #include "scparse_priv.h" +extern int scdebug; + + Narrative *storycode_parse_presentation(const char *sc) { YY_BUFFER_STATE b; struct scpctx parse_ctx; b = sc_scan_string(sc); + //scdebug = 1; scparse(&parse_ctx); sc_delete_buffer(b); + //narrative_debug(parse_ctx.n); return parse_ctx.n; } @@ -189,26 +194,37 @@ static int write_slide(GOutputStream *fh, Slide *s) static int write_item(GOutputStream *fh, struct narrative_item *item) { + int i; + switch ( item->type ) { case NARRATIVE_ITEM_TEXT: /* FIXME: separate alignment */ if ( write_string(fh, ": ") ) return 1; - if ( write_string(fh, item->text) ) return 1; + for ( i=0; in_runs; i++ ) { + /* FIXME: Run markers (e.g. '*') */ + if ( write_string(fh, item->runs[i].text) ) return 1; + } if ( write_string(fh, "\n") ) return 1; break; case NARRATIVE_ITEM_PRESTITLE: /* FIXME: separate alignment */ if ( write_string(fh, "PRESTITLE: ") ) return 1; - if ( write_string(fh, item->text) ) return 1; + for ( i=0; in_runs; i++ ) { + /* FIXME: Run markers (e.g. '*') */ + if ( write_string(fh, item->runs[i].text) ) return 1; + } if ( write_string(fh, "\n") ) return 1; break; case NARRATIVE_ITEM_BP: /* FIXME: separate alignment */ if ( write_string(fh, "BP: ") ) return 1; - if ( write_string(fh, item->text) ) return 1; + for ( i=0; in_runs; i++ ) { + /* FIXME: Run markers (e.g. '*') */ + if ( write_string(fh, item->runs[i].text) ) return 1; + } if ( write_string(fh, "\n") ) return 1; break; diff --git a/libstorycode/storycode.l b/libstorycode/storycode.l index b1bd81a..b4dbb03 100644 --- a/libstorycode/storycode.l +++ b/libstorycode/storycode.l @@ -30,18 +30,23 @@ #include "storycode_parse.h" int lineno = 0; + int sqb_caller = 0; %} %option prefix="sc" %option noyywrap nounput noinput -%s string %s geom %s font +%s filename %s paraspace %s pad %s align %s col %s sqb +%x stringesc +%x runtext +%s image +%s image_filename %% @@ -54,7 +59,6 @@ ENDOFPRESENTATION { return SC_EOP; } BP { return SC_BP; } GEOMETRY { BEGIN(geom); return SC_GEOMETRY; } TEXT { return SC_TEXTFRAME; } -IMAGE { return SC_IMAGEFRAME; } FOOTER { return SC_FOOTER; } FONT[ ] { BEGIN(font); return SC_FONT; } PAD { BEGIN(pad); return SC_PAD; } @@ -69,19 +73,36 @@ BGCOL { BEGIN(col); return SC_BGCOL; } (?i:left) { return SC_LEFT; } (?i:center) { return SC_CENTER; } (?i:right) { return SC_RIGHT; } -.*\n { sclval.str = strdup(yytext); + +.*\n { sclval.str = strdup(yytext); sclval.str[yyleng-1] = '\0'; BEGIN(0); lineno++; - return SC_STRING; } -"[" { BEGIN(sqb); return SC_SQOPEN; } -"]" { BEGIN(0); return SC_SQCLOSE; } -:[ ] { BEGIN(string); } -:\n { sclval.str = strdup(""); lineno++; return SC_STRING; } + return SC_FONTNAME; } + +IMAGE { BEGIN(image); return SC_IMAGEFRAME; } +:[ ] { BEGIN(image_filename); return SC_TEXT_START; } +[^\n]* { sclval.str = strdup(yytext); + lineno++; + return SC_FILENAME; } + +:[ ] { BEGIN(runtext); return SC_TEXT_START; } +[\\] { BEGIN(stringesc); } +[.] { sclval.str = strdup(yytext); BEGIN(runtext); return SC_RUN_TEXT; } +[\*] { return '*'; } +[^\*\n]* { sclval.str = strdup(yytext); + sclval.str[yyleng] = '\0'; + lineno++; + return SC_RUN_TEXT; } +\n { BEGIN(0); lineno++; } + +\n { BEGIN(0); lineno++; } + +"[" { sqb_caller = YY_START; BEGIN(sqb); return SC_SQOPEN; } +"]" { BEGIN(sqb_caller); return SC_SQCLOSE; } [{] { return '{'; } [}] { return '}'; } [. ] {} -\n { BEGIN(0); lineno++; } [0-9\.]+ { sclval.val = atof(yytext); return SC_VALUE; } [uf] { sclval.character = yytext[0]; return SC_UNIT; } [+] { return '+'; } diff --git a/libstorycode/storycode.y b/libstorycode/storycode.y index b5ac68e..daf2504 100644 --- a/libstorycode/storycode.y +++ b/libstorycode/storycode.y @@ -27,10 +27,12 @@ %code requires { #include "narrative.h" + #include "narrative_priv.h" #include "slide.h" #include "stylesheet.h" #include "scparse_priv.h" + } %union { @@ -38,6 +40,10 @@ Narrative *n; Slide *s; char *str; + struct { + char *text; + enum narrative_run_type type; + } str_w_type; struct length len; struct length lenquad[4]; struct frame_geom geom; @@ -59,6 +65,8 @@ extern int lineno; %} +%define parse.trace + %token STYLES %token SLIDE %token EOP @@ -68,24 +76,27 @@ %token FOOTER %token TEXTFRAME %token IMAGEFRAME +%token FILENAME %token BP %token FONT GEOMETRY PAD ALIGN FGCOL BGCOL PARASPACE %token VERT HORIZ %token LEFT CENTER RIGHT -%token STRING +%token FONTNAME RUN_TEXT %token SQOPEN SQCLOSE %token UNIT VALUE HEXCOL +%token TEXT_START %type narrative %type slide %type stylesheet -%type narrative_prestitle %type slide_prestitle -%type STRING +%type FONTNAME %type imageframe %type slide_bulletpoint -%type narrative_bulletpoint %type frameopt +%type FILENAME +%type RUN_TEXT +%type text_run %type geometry %type lenquad %type colour @@ -106,10 +117,11 @@ * Will be added to the narrative when complete */ ctx->s = slide_new(); - ctx->max_str = 32; - ctx->str = malloc(ctx->max_str*sizeof(char *)); - if ( ctx->str == NULL ) ctx->max_str = 0; - str_reset(ctx); + ctx->max_runs = 32; + ctx->runs = malloc(ctx->max_runs*sizeof(char *)); + ctx->run_types = malloc(ctx->max_runs*sizeof(enum narrative_run_type)); + if ( (ctx->runs == NULL) || (ctx->run_types == NULL) ) ctx->max_runs = 0; + reset_runs(ctx); } %{ @@ -144,24 +156,34 @@ static int hex_to_double(const char *v, double *r) return 1; } -void str_reset(struct scpctx *ctx) + +void reset_runs(struct scpctx *ctx) { - ctx->n_str = 0; + ctx->n_runs = 0; ctx->mask = 0; ctx->alignment = ALIGN_INHERIT; } -void add_str(struct scpctx *ctx, char *str) + +void add_run(struct scpctx *ctx, char *str, enum narrative_run_type type) { - if ( ctx->n_str == ctx->max_str ) { - char **nstr = realloc(ctx->str, (ctx->max_str+32)*sizeof(char *)); - if ( nstr == NULL ) return; - ctx->max_str += 32; + if ( ctx->n_runs == ctx->max_runs ) { + char **nruns; + enum narrative_run_type *ntype; + nruns = realloc(ctx->runs, (ctx->max_runs+32)*sizeof(char *)); + ntype = realloc(ctx->run_types, (ctx->max_runs+32)*sizeof(enum narrative_run_type)); + if ( (nruns == NULL) || (ntype == NULL) ) return; + ctx->max_runs += 32; + ctx->runs = nruns; + ctx->run_types = ntype; } - ctx->str[ctx->n_str++] = str; + ctx->runs[ctx->n_runs] = str; + ctx->run_types[ctx->n_runs] = type; + ctx->n_runs++; } + void set_style(struct scpctx *ctx, const char *element) { if ( ctx->mask & STYMASK_GEOM ) stylesheet_set_geometry(narrative_get_stylesheet(ctx->n), @@ -198,26 +220,29 @@ presentation: /* ------ Narrative ------ */ narrative: - narrative_el { } + narrative_el { } | narrative narrative_el { } ; narrative_el: - narrative_prestitle { narrative_add_prestitle(ctx->n, $1); } -| narrative_bulletpoint { narrative_add_bp(ctx->n, $1); } -| slide { } -| STRING { narrative_add_text(ctx->n, $1); } -| EOP { narrative_add_eop(ctx->n); } + PRESTITLE TEXT_START text_line { narrative_add_prestitle(ctx->n, ctx->runs, ctx->run_types, ctx->n_runs); + reset_runs(ctx); } +| BP TEXT_START text_line { narrative_add_bp(ctx->n, ctx->runs, ctx->run_types, ctx->n_runs); + reset_runs(ctx); } +| TEXT_START text_line { narrative_add_text(ctx->n, ctx->runs, ctx->run_types, ctx->n_runs); + reset_runs(ctx); } +| slide { } +| EOP { narrative_add_eop(ctx->n); } ; -narrative_prestitle: - PRESTITLE STRING { $$ = $2; } -; - -narrative_bulletpoint: - BP STRING { $$ = $2; } +text_line: + %empty +| text_line text_run { add_run(ctx, $2.text, $2.type); } ; +text_run: + RUN_TEXT { $$.text = $1; $$.type = NARRATIVE_RUN_NORMAL; } +| '*' RUN_TEXT '*' { $$.text = $2; $$.type = NARRATIVE_RUN_BOLD; } /* -------- Slide -------- */ @@ -233,16 +258,16 @@ slide_parts: ; slide_part: - slide_prestitle { slide_add_prestitle(ctx->s, ctx->str, ctx->n_str); - str_reset(ctx); } + slide_prestitle { slide_add_prestitle(ctx->s, ctx->runs, ctx->n_runs); + reset_runs(ctx); } | imageframe { slide_add_image(ctx->s, $1, ctx->geom); - str_reset(ctx); } -| textframe { slide_add_text(ctx->s, ctx->str, ctx->n_str, + reset_runs(ctx); } +| textframe { slide_add_text(ctx->s, ctx->runs, ctx->n_runs, ctx->geom, ctx->alignment); - str_reset(ctx); } + reset_runs(ctx); } | FOOTER { slide_add_footer(ctx->s); } -| slidetitle { slide_add_slidetitle(ctx->s, ctx->str, ctx->n_str); - str_reset(ctx); } +| slidetitle { slide_add_slidetitle(ctx->s, ctx->runs, ctx->n_runs); + reset_runs(ctx); } ; slide_prestitle: @@ -256,7 +281,7 @@ slidetitle: ; imageframe: - IMAGEFRAME frame_options STRING { $$ = $STRING; } + IMAGEFRAME frame_options TEXT_START FILENAME { $$ = $FILENAME; } ; textframe: @@ -264,15 +289,19 @@ textframe: | TEXTFRAME frame_options '{' multi_line_string '}' { } ; +text_line_with_start: + TEXT_START text_line { } +; + multi_line_string: - STRING { add_str(ctx, $1); } -| multi_line_string STRING { add_str(ctx, $2); } -| slide_bulletpoint { add_str(ctx, $1); } -| multi_line_string slide_bulletpoint { add_str(ctx, $2); } + text_line_with_start { } +| multi_line_string text_line_with_start { } +| slide_bulletpoint { } +| multi_line_string slide_bulletpoint { } ; slide_bulletpoint: - BP STRING { $$ = $2; } + BP TEXT_START text_line { } ; /* There can be any number of options */ @@ -414,7 +443,7 @@ styledefs: ; styledef: - FONT STRING { ctx->font = $2; + FONT FONTNAME { ctx->font = $2; ctx->mask |= STYMASK_FONT; } | GEOMETRY geometry { ctx->geom = $2; ctx->mask |= STYMASK_GEOM; } diff --git a/src/colloquium.c b/src/colloquium.c index 95b5231..745ccef 100644 --- a/src/colloquium.c +++ b/src/colloquium.c @@ -62,7 +62,7 @@ static void colloquium_activate(GApplication *papp) Colloquium *app = COLLOQUIUM(papp); if ( !app->first_run ) { Narrative *n = narrative_new(); - narrative_add_text(n, strdup("")); + narrative_add_empty_item(n); narrative_window_new(n, NULL, papp); } } -- cgit v1.2.3