aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/frame.c671
-rw-r--r--src/frame.h11
-rw-r--r--src/sc_editor.c6
-rw-r--r--src/sc_interp.c25
-rw-r--r--src/sc_parse.c13
-rw-r--r--src/sc_parse.h2
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 = &para->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 = &para->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(&para->runs[nrun], &para->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 */