diff options
-rw-r--r-- | src/frame.c | 671 | ||||
-rw-r--r-- | src/frame.h | 11 | ||||
-rw-r--r-- | src/sc_editor.c | 6 | ||||
-rw-r--r-- | src/sc_interp.c | 25 | ||||
-rw-r--r-- | src/sc_parse.c | 13 | ||||
-rw-r--r-- | src/sc_parse.h | 2 |
6 files changed, 527 insertions, 201 deletions
diff --git a/src/frame.c b/src/frame.c index fc2fefc..20b3ded 100644 --- a/src/frame.c +++ b/src/frame.c @@ -35,13 +35,10 @@ #include "frame.h" #include "imagestore.h" - struct text_run { - SCBlock *scblock; - SCBlock *macro_real_block; - SCBlock *macro_contents; - int macro_editable; + SCBlock *scblock; /* If macro, this is \macro */ + SCBlock *rscblock; /* The block with the actual text */ size_t para_offs_bytes; /* Offset from start of paragraph */ size_t len_bytes; PangoFontDescription *fontdesc; @@ -65,7 +62,6 @@ struct _paragraph /* For anything other than PARA_TYPE_TEXT * (for text paragraphs, these things are in the runs) */ SCBlock *scblock; - SCBlock *macro_real_scblock; /* For PARA_TYPE_IMAGE */ char *filename; @@ -321,7 +317,7 @@ void wrap_paragraph(Paragraph *para, PangoContext *pc, double w, const char *run_text; guint16 r, g, b; - run_text = sc_block_contents(para->runs[i].scblock); + run_text = sc_block_contents(para->runs[i].rscblock); attr = pango_attr_font_desc_new(para->runs[i].fontdesc); attr->start_index = pos; @@ -377,10 +373,9 @@ void set_newline_at_end(Paragraph *para, SCBlock *bl) } -void add_run(Paragraph *para, SCBlock *scblock, - SCBlock *macro_real, SCBlock *contents_top, +void add_run(Paragraph *para, SCBlock *scblock, SCBlock *rscblock, size_t len_bytes, PangoFontDescription *fdesc, - double col[4], int macro_editable) + double col[4]) { struct text_run *runs_new; @@ -398,9 +393,7 @@ void add_run(Paragraph *para, SCBlock *scblock, para->runs = runs_new; para->runs[para->n_runs].scblock = scblock; - para->runs[para->n_runs].macro_real_block = macro_real; - para->runs[para->n_runs].macro_contents = contents_top; - para->runs[para->n_runs].macro_editable = macro_editable; + para->runs[para->n_runs].rscblock = rscblock; para->runs[para->n_runs].para_offs_bytes = para->offset_last; para->offset_last += len_bytes; para->runs[para->n_runs].len_bytes = len_bytes; @@ -463,7 +456,7 @@ Paragraph *insert_paragraph(struct frame *fr, int pos) } -void add_callback_para(struct frame *fr, SCBlock *bl, SCBlock *mr, +void add_callback_para(struct frame *fr, SCBlock *bl, double w, double h, SCCallbackDrawFunc draw_func, SCCallbackClickFunc click_func, void *bvp, @@ -479,7 +472,6 @@ void add_callback_para(struct frame *fr, SCBlock *bl, SCBlock *mr, pnew->type = PARA_TYPE_CALLBACK; pnew->scblock = bl; - pnew->macro_real_scblock = mr; pnew->cb_w = w; pnew->cb_h = h; pnew->draw_func = draw_func; @@ -948,13 +940,13 @@ size_t pos_trail_to_offset(Paragraph *para, size_t offs, int trail) return 0; } - if ( (sc_block_name(run->scblock) != NULL) - && (strcmp(sc_block_name(run->scblock), "newpara") == 0) ) + if ( (sc_block_name(run->rscblock) != NULL) + && (strcmp(sc_block_name(run->rscblock), "newpara") == 0) ) { return 0; } - if ( sc_block_contents(run->scblock) == NULL ) { + if ( sc_block_contents(run->rscblock) == NULL ) { fprintf(stderr, "pos_trail_to_offset: No contents " "(%p name=%s, options=%s)\n", run->scblock, sc_block_name(run->scblock), @@ -963,7 +955,7 @@ size_t pos_trail_to_offset(Paragraph *para, size_t offs, int trail) } /* Get the text for the run */ - run_text = sc_block_contents(run->scblock); + run_text = sc_block_contents(run->rscblock); /* Turn the paragraph offset into a run offset */ run_offs = offs - run->para_offs_bytes; @@ -998,13 +990,6 @@ void insert_text_in_paragraph(Paragraph *para, size_t offs, const char *t) } run = ¶->runs[nrun]; - if ( run->macro_real_block != NULL ) { - if ( !run->macro_editable ) { - printf("Not inserting text into a macro block.\n"); - return; - } - } - if ( (sc_block_name(run->scblock) != NULL) && (strcmp(sc_block_name(run->scblock), "newpara") == 0) ) { @@ -1028,7 +1013,7 @@ void insert_text_in_paragraph(Paragraph *para, size_t offs, const char *t) /* Translate paragraph offset for insertion into SCBlock offset */ run_offs = offs - run->para_offs_bytes; - sc_insert_text(run->scblock, run_offs, t); + sc_insert_text(run->rscblock, run_offs, t); /* Update length of this run */ ins_len = strlen(t); @@ -1041,118 +1026,524 @@ void insert_text_in_paragraph(Paragraph *para, size_t offs, const char *t) } -static void delete_text_paragraph(Paragraph *para, int p, struct frame *fr) +static SCBlock *pos_to_rscblock(struct frame *fr, struct edit_pos p) +{ + int run; + size_t paraoffs; + Paragraph *para; + + para = fr->paras[p.para]; + + if ( para->type != PARA_TYPE_TEXT ) { + return NULL; + } + + paraoffs = pos_trail_to_offset(para, p.pos, p.trail); + + run = which_run(para, paraoffs); + assert(run < para->n_runs); + + return para->runs[run].rscblock; +} + + + +static SCBlock *pos_to_scblock(struct frame *fr, struct edit_pos p, + enum para_type *type) +{ + int run; + size_t paraoffs; + Paragraph *para; + + para = fr->paras[p.para]; + if ( type != NULL ) { + *type = para->type; + } + + if ( para->type != PARA_TYPE_TEXT ) { + return para->scblock; + } + + paraoffs = pos_trail_to_offset(para, p.pos, p.trail); + + run = which_run(para, paraoffs); + assert(run < para->n_runs); + + return para->runs[run].scblock; +} + + +static size_t pos_to_offset(struct frame *fr, struct edit_pos p) +{ + int run; + size_t paraoffs; + Paragraph *para; + + para = fr->paras[p.para]; + if ( para->type != PARA_TYPE_TEXT ) { + return 0; + } + + paraoffs = pos_trail_to_offset(para, p.pos, p.trail); + + run = which_run(para, paraoffs); + assert(run < para->n_runs); + + return paraoffs - para->runs[run].para_offs_bytes; +} + + +static int pos_to_run_number(struct frame *fr, struct edit_pos p) +{ + int run; + size_t paraoffs; + Paragraph *para; + + para = fr->paras[p.para]; + if ( para->type != PARA_TYPE_TEXT ) { + return 0; + } + + paraoffs = pos_trail_to_offset(para, p.pos, p.trail); + + run = which_run(para, paraoffs); + assert(run < para->n_runs); + + return run; +} + + +/* Reduce para_offs_bytes for all runs in "para" after "start" by "del" */ +static void update_subsq_para_offsets(Paragraph *para, int start, size_t del) { int i; - /* Delete the corresponding SC */ - for ( i=0; i<para->n_runs; i++ ) { + for ( i=start+1; i<para->n_runs; i++ ) { + para->runs[i].para_offs_bytes -= del; + } +} - int j; - struct text_run *run; - run = ¶->runs[i]; +static size_t delete_run(Paragraph *para, int nrun) +{ + size_t del; - if ( run->macro_real_block != NULL ) { - printf("Not deleting text from macro block\n"); - continue; - } + printf("deleting run %i of %i from para %p\n", nrun, para->n_runs, para); + del = para->runs[nrun].len_bytes; + memmove(¶->runs[nrun], ¶->runs[nrun+1], + (para->n_runs-1)*sizeof(struct text_run)); + para->n_runs--; - if ( (sc_block_name(run->scblock) != NULL) - && (strcmp(sc_block_name(run->scblock), "newpara") == 0) ) - { - sc_block_delete(&fr->scblocks, run->scblock); - return; - } + return del; +} - /* Delete from the corresponding SC block */ - scblock_delete_text(run->scblock, 0, run->len_bytes); - /* Fix up the offsets of the subsequent text runs */ - size_t del_len = run->len_bytes; - run->len_bytes -= del_len; - for ( j=i+1; j<para->n_runs; j++ ) { - para->runs[j].para_offs_bytes -= del_len; +static Paragraph *scan_runs_for_scblock(struct frame *fr, int pn1, int pn2, + SCBlock *bl, int *run) +{ + int i; + for ( i=pn1; i<=pn2; i++ ) { + int j; + for ( j=0; j<fr->paras[i]->n_runs; j++ ) { + if ( fr->paras[i]->runs[j].rscblock == bl ) { + *run = j; + return fr->paras[i]; + } } + } + return NULL; +} + + +static Paragraph *find_run_for_scblock_next(struct frame *fr, int pn1, int pn2, + SCBlock *bl, int *run) +{ + if ( sc_block_child(bl) != NULL ) { + Paragraph *para; + para = find_run_for_scblock_next(fr, pn1, pn2, + sc_block_child(bl), run); + if ( para != NULL ) return para; + } + + do { + Paragraph *para; + para = scan_runs_for_scblock(fr, pn1, pn2, bl, run); + if ( para != NULL ) return para; + bl = sc_block_next(bl); + } while ( bl != NULL ); + + return NULL; +} + + +/* Find the run which contains the text from "bl", + * taking into account that it might be a child block, for example: + * {some text} + * \italic <---- bl points here + * {more text} <---- but this block is referenced by the run + * {final text} + */ +static Paragraph *find_run_for_scblock(struct frame *fr, int pn1, int pn2, + SCBlock *bl, int *run) +{ + Paragraph *para; + + show_sc_block(bl, "searching "); + para = scan_runs_for_scblock(fr, pn1, pn2, bl, run); + if ( para != NULL ) return para; + if ( sc_block_child(bl) != NULL ) { + para = find_run_for_scblock_next(fr, pn1, pn2, sc_block_child(bl), run); + if ( para != NULL ) return para; } + + return NULL; } -static void delete_paragraph(struct frame *fr, int p) +static int paragraph_number(struct frame *fr, Paragraph *p, int *err) { int i; - Paragraph *para = fr->paras[p]; + for ( i=0; i<fr->n_paras; i++ ) { + if ( fr->paras[i] == p ) return i; + } + fprintf(stderr, "Couldn't find paragraph %p\n", p); + *err = 1; + return 0; +} + + +static size_t delete_run_for_scblock(struct frame *fr, + Paragraph *p1, Paragraph *p2, SCBlock *bl) +{ + int pn1, pn2; + int err = 0; + size_t del; + Paragraph *para; + int run; + + pn1 = paragraph_number(fr, p1, &err); + pn2 = paragraph_number(fr, p2, &err); + if ( err ) return 0; + + para = find_run_for_scblock(fr, pn1, pn2, bl, &run); + if ( para == NULL ) { + fprintf(stderr, "Couldn't find block %p between paragraphs %p and %p\n", + bl, p1, p2); + return 0; + } + + del = delete_run(para, run); + update_subsq_para_offsets(para, run, del); + + return del; +} + + +static signed int merge_paragraph_runs(Paragraph *p1, Paragraph *p2) +{ + struct text_run *runs_new; + int i, spos; + + /* All the runs from p2 get added to p1 */ + runs_new = realloc(p1->runs, + (p1->n_runs+p2->n_runs)*sizeof(struct text_run)); + if ( runs_new == NULL ) { + fprintf(stderr, "Failed to allocate merged runs.\n"); + return -1; + } + p1->runs = runs_new; + + assert(p1->runs[p1->n_runs-1].scblock == get_newline_at_end(p1)); + p1->n_runs--; /* Chop off the run corresponding to \newpara */ + spos = p1->n_runs; + + /* The end of the united paragraph should now be the end of the + * second one */ + set_newline_at_end(p1, get_newline_at_end(p2)); + + for ( i=0; i<p2->n_runs; i++ ) { + + size_t offs; + + p1->runs[p1->n_runs] = p2->runs[i]; + + offs = p1->runs[p1->n_runs-1].para_offs_bytes; + offs += p1->runs[p1->n_runs-1].len_bytes; + p1->runs[p1->n_runs].para_offs_bytes = offs; + + p1->n_runs++; - if ( para->type != PARA_TYPE_TEXT ) { - if ( para->macro_real_scblock != NULL ) { - sc_block_delete(&fr->scblocks, para->macro_real_scblock); - } else { - sc_block_delete(&fr->scblocks, para->scblock); - } - } else { - delete_text_paragraph(para, p, fr); } + free(p2->runs); + free(p2); - /* Delete the paragraph from the frame */ - free_paragraph(fr->paras[p]); - for ( i=p; i<fr->n_paras-1; i++ ) { + return spos; +} + + +void merge_paragraphs(struct frame *fr, int para) +{ + Paragraph *p1, *p2; + int i; + SCBlock *n; + + if ( para >= fr->n_paras-1 ) { + printf("Paragraph number too high to merge.\n"); + return; + } + + p1 = fr->paras[para]; + p2 = fr->paras[para+1]; + + if ( (p1->type != PARA_TYPE_TEXT) || (p2->type != PARA_TYPE_TEXT) ) { + printf("Trying to merge non-text paragraphs.\n"); + return; + } + + /* Delete the \newpara block to unite the paragraphs */ + n = get_newline_at_end(p1); + assert(n != NULL); + + if ( sc_block_delete(&fr->scblocks, n) ) { + fprintf(stderr, "Failed to delete paragraph end sentinel.\n"); + return; + } + + merge_paragraph_runs(p1, p2); + + for ( i=para+1; i<fr->n_paras-1; i++ ) { fr->paras[i] = fr->paras[i+1]; } fr->n_paras--; } + +static void merge_paragraphs_by_newpara(struct frame *fr, SCBlock *np) +{ + int i; + Paragraph *p1; + Paragraph *p2; + + for ( i=0; i<fr->n_paras-1; i++ ) { + if ( fr->paras[i]->newline_at_end == np ) { + + int j; + signed int spos; + + p1 = fr->paras[i]; + p2 = fr->paras[i+1]; + + printf("-------------------------------\n"); + show_para(p1); + printf("---x--------x------------------\n"); + show_para(p2); + spos = merge_paragraph_runs(p1, p2); + if ( spos < 0 ) { + fprintf(stderr, "Failed to merge paragraphs\n"); + return; + } + printf("-------------------------------\n"); + show_para(p1); + + for ( j=i+1; j<fr->n_paras-1; j++ ) { + fr->paras[j] = fr->paras[j+1]; + } + fr->n_paras--; + + return; + + } + } + + fprintf(stderr, "Couldn't find paragraphs to merge by newpara\n"); +} + + +static int find_block_inside(SCBlock *needle, SCBlock *bl) +{ + if ( needle == bl ) return 1; + + if ( sc_block_child(bl) != NULL ) { + if ( find_block_inside(needle, sc_block_child(bl)) ) return 1; + } + + if ( sc_block_next(bl) != NULL ) { + if ( find_block_inside(needle, sc_block_next(bl)) ) return 1; + } + + return 0; +} + + +/* Return true if "top" either IS "child", or contains "child" somewhere + * underneath, even if via a macro expansion */ +static int block_is_under(SCBlock *needle, SCBlock *top) +{ + if ( needle == top ) return 1; + + if ( sc_block_child(top) != NULL ) { + if ( find_block_inside(needle, sc_block_child(top)) ) return 1; + } + + /* Do not look at top->next here */ + + return 0; +} + + void delete_text_from_frame(struct frame *fr, struct edit_pos p1, struct edit_pos p2, double wrapw) { int i; - size_t del = 0; + SCBlock *p1scblock, *p2scblock; + SCBlock *p1rscblock, *p2rscblock; + enum para_type type1, type2; + SCBlock *scblock; sort_positions(&p1, &p2); printf("para %i offs %ld\n", p1.para, p1.pos); printf("para %i offs %li\n", p2.para, p2.pos); - for ( i=p1.para; i<=p2.para; i++ ) { + /* Find SC positions for start and end */ + p1scblock = pos_to_scblock(fr, p1, &type1); + p2scblock = pos_to_scblock(fr, p2, &type2); + p1rscblock = pos_to_rscblock(fr, p1); + p2rscblock = pos_to_rscblock(fr, p2); - size_t start; - ssize_t finis; + printf("SCBlocks %p to %p\n", p1scblock, p2scblock); + //show_sc_blocks(p1scblock); - printf("para %i\n", i); + if ( (p1scblock == p2scblock) && (type1 == PARA_TYPE_TEXT) ) { - Paragraph *para = fr->paras[i]; + size_t del; + int p1run; + size_t p1offs, p2offs; + printf("Simple case, one SCBlock\n"); - if ( i == p1.para ) { - start = pos_trail_to_offset(para, p1.pos, p1.trail); - } else { - start = 0; - } + assert(type1 == type2); + + /* Remove the text and update the run length */ + p1offs = pos_to_offset(fr, p1); + p2offs = pos_to_offset(fr, p2); + del = scblock_delete_text(p1scblock, p1offs, p2offs); + + p1run = pos_to_run_number(fr, p1); + fr->paras[p1.para]->runs[p1run].len_bytes -= del; + + /* Update the paragraph offsets of subsequent runs */ + update_subsq_para_offsets(fr->paras[p1.para], p1run, del); + + wrap_paragraph(fr->paras[p1.para], NULL, wrapw, 0, 0); + + return; + } - if ( i == p2.para ) { - finis = pos_trail_to_offset(para, p2.pos, p2.trail); + /* Starting point for iteration over blocks in middle of range. + * Record this now, because p1scblock might be about to get deleted */ + scblock = sc_block_next(p1scblock); + + /* First SCBlock in range: delete whole thing or second half */ + printf("First block %p\n", p1scblock); + if ( type1 == PARA_TYPE_TEXT ) { + + size_t p1offs = pos_to_offset(fr, p1); + int p1run = pos_to_run_number(fr, p1); + printf(" offs %li\n", (long int)p1offs); + if ( p1offs != 0 ) { + size_t del; + printf("Partial delete\n"); + printf("contents '%s'\n", sc_block_contents(p1rscblock)); + printf("from offs %li\n", (long int)p1offs); + del = scblock_delete_text(p1rscblock, p1offs, -1); + fr->paras[p1.para]->runs[p1run].len_bytes -= del; + update_subsq_para_offsets(fr->paras[p1.para], p1run, del); } else { - finis = -1; + printf("Deleting the whole text SCBlock\n"); + sc_block_delete(&fr->scblocks, p1scblock); + delete_run(fr->paras[p1.para], p1run); } - if ( (start == 0) && (finis == -1) ) { - printf("deleting para %i\n", i); - delete_paragraph(fr, i); - p2.para--; - i--; + } else { + printf("Deleting the whole non-text SCBlock\n"); + sc_block_delete(&fr->scblocks, p1scblock); + } + + /* Delete all the complete SCBlocks in the middle of the range */ + if ( !block_is_under(p2scblock, scblock) ) { + do { + + SCBlock *next; + + /* For each SC block in middle of range: */ + printf("Deleting %p\n", scblock); + if ( scblock == NULL ) { + fprintf(stderr, "nothing?\n"); + break; + } + printf("name is '%s'\n", sc_block_name(scblock)); + if ( (sc_block_name(scblock) != NULL) + && (strcmp(sc_block_name(scblock), "newpara") == 0) ) + { + /* Deleting newpara block, merge the paragraphs */ + merge_paragraphs_by_newpara(fr, scblock); + + } + + next = sc_block_next(scblock); + delete_run_for_scblock(fr, fr->paras[p1.para], + fr->paras[p2.para], scblock); + sc_block_delete(&fr->scblocks, scblock); + + scblock = next; + + } while ( !block_is_under(p2scblock, scblock) ); + } + + /* Last SCBlock in range: delete whole thing or first half */ + printf("Last block %p (%s)\n", p2scblock, sc_block_name(p2scblock)); + if ( type2 == PARA_TYPE_TEXT ) { + size_t len; + size_t p2offs = pos_to_offset(fr, p2); + int p2run = pos_to_run_number(fr, p2); + printf(" offs %li\n", (long int)p2offs); + if ( sc_block_contents(p2rscblock) != NULL ) { + len = strlen(sc_block_contents(p2rscblock)); } else { - printf("deleting from %ld to %ld\n", start, finis); - del += delete_text_in_paragraph(fr, i, start, finis); - wrap_paragraph(para, NULL, wrapw, 0, 0); + len = 0; } - + printf(" len %li\n", (long int)len); + if ( (len > 0) && (p2offs == len) ) { + printf("Deleting the whole text SCBlock\n"); + printf("deleting block %p\n", p2scblock); + show_sc_block(p2scblock, ""); + sc_block_delete(&fr->scblocks, p2scblock); + delete_run(fr->paras[p2.para], p2run); + } else if ( p2offs > 0 ) { + size_t del; + printf("Partial delete\n"); + printf("contents '%s'\n", sc_block_contents(p2rscblock)); + printf("up to offs %li\n", (long int)p2offs); + del = scblock_delete_text(p2rscblock, 0, p2offs); + fr->paras[p2.para]->runs[p2run].len_bytes -= del; + update_subsq_para_offsets(fr->paras[p2.para], p2run, del); + } /* else do nothing */ + } else { + printf("Deleting the whole non-text SCBlock\n"); + sc_block_delete(&fr->scblocks, p2scblock); } - /* If we deleted across a paragraph, merge paragraphs */ - if ( p1.para != p2.para ) { - merge_paragraphs(fr, p1.para); - wrap_paragraph(fr->paras[p1.para], NULL, wrapw, 0, 0); + /* If any paragraphs have been deleted, this will wrap too many + * paragraphs, but it doesn't matter as long as we don't wrap + * past the end of the frame's contents. */ + for ( i=p1.para; i<=p2.para; i++ ) { + if ( i >= fr->n_paras ) break; + printf("Wrapping para %i (%p)\n", i, fr->paras[i]); + wrap_paragraph(fr->paras[i], NULL, wrapw, 0, 0); } + printf("All done.\n"); } @@ -1200,13 +1591,6 @@ size_t delete_text_in_paragraph(struct frame *fr, int npara, size_t offs1, ssize assert(de >= 0); /* Otherwise nrun2 was too big */ if ( ds == de ) continue; - if ( run->macro_real_block != NULL ) { - if ( !run->macro_editable ) { - printf("Not deleting inside macro block!\n"); - continue; - } - } - /* Delete from the corresponding SC block */ scblock_offs1 = ds; scblock_offs2 = de; @@ -1231,7 +1615,7 @@ size_t delete_text_in_paragraph(struct frame *fr, int npara, size_t offs1, ssize static char *run_text(struct text_run *run) { - return strndup(sc_block_contents(run->scblock), run->len_bytes); + return strndup(sc_block_contents(run->rscblock), run->len_bytes); } @@ -1263,82 +1647,13 @@ void show_para(Paragraph *p) } -void merge_paragraphs(struct frame *fr, int para) -{ - Paragraph *p1, *p2; - struct text_run *runs_new; - int i; - SCBlock *n; - - if ( para >= fr->n_paras-1 ) { - printf("Paragraph number too high to merge.\n"); - return; - } - - p1 = fr->paras[para]; - p2 = fr->paras[para+1]; - - if ( (p1->type != PARA_TYPE_TEXT) || (p2->type != PARA_TYPE_TEXT) ) { - printf("Trying to merge non-text paragraphs.\n"); - return; - } - - /* Delete the \newpara block to unite the paragraphs */ - n = get_newline_at_end(p1); - assert(n != NULL); - - if ( sc_block_delete(&fr->scblocks, n) ) { - if ( p1->runs[p1->n_runs-1].macro_contents != NULL ) { - if ( sc_block_delete(&p1->runs[p1->n_runs-1].macro_contents, n) ) { - fprintf(stderr, "Failed to delete paragraph end sentinel.\n"); - return; - } - } - } - - /* All the runs from p2 get added to p1 */ - runs_new = realloc(p1->runs, - (p1->n_runs+p2->n_runs)*sizeof(struct text_run)); - if ( runs_new == NULL ) { - fprintf(stderr, "Failed to allocate merged runs.\n"); - return; - } - p1->runs = runs_new; - - /* The end of the united paragraph should now be the end of the - * second one */ - set_newline_at_end(p1, get_newline_at_end(p2)); - - for ( i=0; i<p2->n_runs; i++ ) { - - size_t offs; - - p1->runs[p1->n_runs] = p2->runs[i]; - - offs = p1->runs[p1->n_runs-1].para_offs_bytes; - offs += p1->runs[p1->n_runs-1].len_bytes; - p1->runs[p1->n_runs].para_offs_bytes = offs; - - p1->n_runs++; - - } - free(p2->runs); - free(p2); - - for ( i=para+1; i<fr->n_paras-1; i++ ) { - fr->paras[i] = fr->paras[i+1]; - } - fr->n_paras--; -} - - static void check_para(Paragraph *para) { int i; for ( i=0; i<para->n_runs; i++ ) { const char *run_text; - if ( sc_block_contents(para->runs[i].scblock) == NULL ) continue; - run_text = sc_block_contents(para->runs[i].scblock); + if ( sc_block_contents(para->runs[i].rscblock) == NULL ) continue; + run_text = sc_block_contents(para->runs[i].rscblock); if ( strlen(run_text) < para->runs[i].len_bytes ) { printf("found a wrong run\n"); printf("run %i, para offs %li text '%s'\n", i, @@ -1397,7 +1712,7 @@ static SCBlock *split_text_paragraph(struct frame *fr, int pn, size_t pos, printf("splitting at end of para\n"); pnew->runs[0].para_offs_bytes = 0; pnew->runs[0].scblock = rr->scblock; - pnew->runs[0].macro_real_block = rr->macro_real_block; + pnew->runs[0].rscblock = rr->rscblock; pnew->runs[0].para_offs_bytes = 0; pnew->runs[0].len_bytes = 0; pnew->runs[0].fontdesc = pango_font_description_copy(rr->fontdesc); @@ -1424,7 +1739,7 @@ static SCBlock *split_text_paragraph(struct frame *fr, int pn, size_t pos, /* First run of the new paragraph contains the leftover text */ pnew->runs[0].scblock = rr->scblock; - pnew->runs[0].macro_real_block = rr->macro_real_block; + pnew->runs[0].rscblock = rr->rscblock; pnew->runs[0].para_offs_bytes = 0; pnew->runs[0].len_bytes = rr->len_bytes - run_offs; printf("%i - %i\n", (int)rr->len_bytes, (int)run_offs); @@ -1456,14 +1771,14 @@ static SCBlock *split_text_paragraph(struct frame *fr, int pn, size_t pos, para->n_runs = run+1; /* If the first and second paragraphs have the same SCBlock, split it */ - if ( (rr->scblock != NULL) && (rr->scblock == pnew->runs[0].scblock) ) { + if ( (rr->rscblock != NULL) && (rr->rscblock == pnew->runs[0].rscblock) ) { printf("splitting SCBlock at %i\n", (int)run_offs); - printf("old block: '%s'\n", sc_block_contents(rr->scblock)); - pnew->runs[0].scblock = sc_block_split(rr->scblock, run_offs); - printf("new block 1: '%s'\n", sc_block_contents(rr->scblock)); - printf("new block 2: '%s'\n", sc_block_contents(pnew->runs[0].scblock)); - printf("run %p block %p\n", &pnew->runs[0], pnew->runs[0].scblock); + printf("old block: '%s'\n", sc_block_contents(rr->rscblock)); + pnew->runs[0].rscblock = sc_block_split(rr->rscblock, run_offs); + printf("new block 1: '%s'\n", sc_block_contents(rr->rscblock)); + printf("new block 2: '%s'\n", sc_block_contents(pnew->runs[0].rscblock)); + printf("run %p block %p\n", &pnew->runs[0], pnew->runs[0].rscblock); printf("run %i, para offs %li\n", 0, (long int)pnew->runs[0].para_offs_bytes); @@ -1509,7 +1824,7 @@ SCBlock *block_at_cursor(struct frame *fr, int pn, size_t pos) if ( para->type != PARA_TYPE_CALLBACK ) return NULL; - return para->macro_real_scblock; + return para->scblock; } diff --git a/src/frame.h b/src/frame.h index 6145666..d22cd35 100644 --- a/src/frame.h +++ b/src/frame.h @@ -62,7 +62,8 @@ typedef struct _paragraph Paragraph; struct edit_pos { int para; /* Paragraph number */ - size_t pos; /* Byte position within paragraph */ + size_t pos; /* Byte position within paragraph + * Yes, really. See pango_layout_xy_to_index */ int trail; }; @@ -135,15 +136,13 @@ extern void set_newline_at_end(Paragraph *para, SCBlock *bl); extern void check_run(struct frame *fr, int pn); extern void show_edit_pos(struct edit_pos a); -extern void add_run(Paragraph *para, SCBlock *scblock, - SCBlock *macro_real, SCBlock *contents_top, +extern void add_run(Paragraph *para, SCBlock *scblock, SCBlock *rscblock, size_t len_bytes, - PangoFontDescription *fdesc, double col[4], - int macro_editable); + PangoFontDescription *fdesc, double col[4]); extern Paragraph *insert_paragraph(struct frame *fr, int pos); -extern void add_callback_para(struct frame *fr, SCBlock *scblock, SCBlock *mr, +extern void add_callback_para(struct frame *fr, SCBlock *scblock, double w, double h, SCCallbackDrawFunc draw_func, SCCallbackClickFunc click_func, void *bvp, diff --git a/src/sc_editor.c b/src/sc_editor.c index c872acc..6b8ba69 100644 --- a/src/sc_editor.c +++ b/src/sc_editor.c @@ -853,8 +853,8 @@ static void insert_text(char *t, SCEditor *e) fprintf(stderr, "Failed to insert paragraph\n"); return; } - add_run(pnew, ad, NULL, NULL, strlen(t), - e->cursor_frame->fontdesc, e->cursor_frame->col, 0); + add_run(pnew, ad, ad, strlen(t), + e->cursor_frame->fontdesc, e->cursor_frame->col); wrap_frame(e->cursor_frame, e->pc); @@ -1076,7 +1076,7 @@ static void check_paragraph(struct frame *fr, PangoContext *pc, } scblocks = sc_block_append(scblocks, NULL, NULL, strdup(""), NULL); - add_run(para, scblocks, NULL, NULL, 0, fr->fontdesc, fr->col, 0); + add_run(para, scblocks, scblocks, 0, fr->fontdesc, fr->col); wrap_paragraph(para, pc, fr->w - fr->pad_l - fr->pad_r, 0, 0); } diff --git a/src/sc_interp.c b/src/sc_interp.c index 24dd4ee..51849d5 100644 --- a/src/sc_interp.c +++ b/src/sc_interp.c @@ -239,7 +239,7 @@ static void do_callback(SCInterpreter *scin, SCBlock *bl, const char *name) if ( strcmp(cbl->names[i], name) != 0 ) continue; r = cbl->box_funcs[i](scin, bl, &w, &h, &bvp, cbl->vps[i]); if ( !r ) return; - add_callback_para(sc_interp_get_frame(scin), bl, mr, w, h, + add_callback_para(sc_interp_get_frame(scin), bl, w, h, cbl->draw_funcs[i], cbl->click_funcs[i], bvp, cbl->vps[i]); @@ -950,7 +950,7 @@ static int add_text(struct frame *fr, PangoContext *pc, SCBlock *bl, PangoFontDescription *fontdesc; double *col; struct sc_state *st = &scin->state[scin->j]; - SCBlock *mrb; + SCBlock *rbl; /* Empty block? */ if ( text == NULL ) return 1; @@ -958,12 +958,16 @@ static int add_text(struct frame *fr, PangoContext *pc, SCBlock *bl, fontdesc = sc_interp_get_fontdesc(scin); col = sc_interp_get_fgcol(scin); - mrb = sc_interp_get_macro_real_block(scin); len_bytes = strlen(text); Paragraph *para = last_open_para(fr); - add_run(para, bl, mrb, st->macro_contents, len_bytes, - fontdesc, col, st->macro_editable); + + rbl = bl; + if ( st->macro_real_block != NULL ) { + bl = st->macro_real_block; + } + + add_run(para, bl, rbl, len_bytes, fontdesc, col); set_para_spacing(para, st->paraspace); return 0; @@ -975,6 +979,7 @@ static int check_outputs(SCBlock *bl, SCInterpreter *scin) const char *name = sc_block_name(bl); const char *options = sc_block_options(bl); SCBlock *child = sc_block_child(bl); + struct sc_state *st = &scin->state[scin->j]; if ( name == NULL ) { add_text(sc_interp_get_frame(scin), @@ -986,7 +991,11 @@ static int check_outputs(SCBlock *bl, SCInterpreter *scin) if ( parse_image_options(options, sc_interp_get_frame(scin), &w, &h, &filename) == 0 ) { - add_image_para(sc_interp_get_frame(scin), bl, + SCBlock *ebl = bl; + if ( st->macro_real_block != NULL ) { + ebl = st->macro_real_block; + } + add_image_para(sc_interp_get_frame(scin), ebl, filename, scin->is, w, h, 1); free(filename); } else { @@ -1022,10 +1031,8 @@ static int check_outputs(SCBlock *bl, SCInterpreter *scin) } else if ( strcmp(name, "newpara")==0 ) { struct frame *fr = sc_interp_get_frame(scin); Paragraph *para = last_open_para(fr); - struct sc_state *st = &scin->state[scin->j]; /* Add a dummy run which we can type into */ - add_run(para, bl, st->macro_real_block, st->macro_contents, 0, - sc_interp_get_fontdesc(scin), fr->col, st->macro_editable); + add_run(para, bl, bl, 0, sc_interp_get_fontdesc(scin), fr->col); set_newline_at_end(para, bl); close_last_paragraph(fr); diff --git a/src/sc_parse.c b/src/sc_parse.c index f2814b6..2607031 100644 --- a/src/sc_parse.c +++ b/src/sc_parse.c @@ -58,6 +58,7 @@ SCBlock *sc_block_new() SCBlock *sc_block_next(const SCBlock *bl) { + assert(bl != NULL); return bl->next; } @@ -734,23 +735,27 @@ void sc_insert_block(SCBlock *b1, int o1, SCBlock *ins) } -void scblock_delete_text(SCBlock *b, size_t o1, size_t o2) +/* Delete text from SCBlock contents. o2=-1 means "to the end". + * Returns the number of bytes deleted. */ +size_t scblock_delete_text(SCBlock *b, ssize_t o1, ssize_t o2) { - size_t len; if ( b->contents == NULL ) { fprintf(stderr, "Deleting text from block \\%s\n", b->name); - return; + return 0; } len = strlen(b->contents); + if ( o2 < 0 ) o2 = len; if ( (o1 >= o2) || (o1 > len) || (o2 > len) ) { fprintf(stderr, "Invalid delete: %i %i %i\n", (int)o1, (int)o2, (int)len); - return; + return 0; } memmove(b->contents+o1, b->contents+o2, len-o2+1); + + return o2-o1; } diff --git a/src/sc_parse.h b/src/sc_parse.h index be7d0ee..ff10638 100644 --- a/src/sc_parse.h +++ b/src/sc_parse.h @@ -82,6 +82,6 @@ extern void show_sc_block(const SCBlock *bl, const char *prefix); extern char *serialise_sc_block(const SCBlock *bl); extern void save_sc_block(FILE *fh, const SCBlock *bl); -extern void scblock_delete_text(SCBlock *b, size_t o1, size_t o2); +extern size_t scblock_delete_text(SCBlock *b, ssize_t o1, ssize_t o2); #endif /* SC_PARSE_H */ |