shithub: fc

Download patch

ref: ef1c78b3ad619f48c4835f1684cf23393d704b3b
parent: 02f0fdccefc6d03202d5c631141b8b0dc951f775
author: glenda <glenda@krsna>
date: Sun Aug 17 17:14:04 EDT 2025

really-done-now

--- a/fc.c
+++ b/fc.c
@@ -396,36 +396,36 @@
 };
 
 BoxType boxtypes[] = {
-	[T_TEXT]    = {"text",    parse_text,    eval_text,    draw_box_generic},
+	[T_TEXT]	= {"text",	parse_text,	eval_text,	draw_box_generic},
 	[T_NUMBER]  = {"number",  parse_number,  eval_number,  draw_box_generic},
 	[T_FORMULA] = {"formula", parse_formula, eval_formula, draw_box_generic},
-	[T_LABEL]   = {"label",   parse_text,    eval_text,    draw_box_generic},
+	[T_LABEL]   = {"label",   parse_text,	eval_text,	draw_box_generic},
 	[T_PARAGRAPH] = {"paragraph", parse_paragraph, eval_paragraph, draw_box_paragraph},
 };
 
 Function functions[MAXFUNCS] = {
-	[FN_SUM]    = {"SUM",    1, 100, fn_sum},
-	[FN_AVG]    = {"AVG",    1, 100, fn_avg},
-	[FN_MIN]    = {"MIN",    1, 100, fn_min},
-	[FN_MAX]    = {"MAX",    1, 100, fn_max},
+	[FN_SUM]	= {"SUM",	1, 100, fn_sum},
+	[FN_AVG]	= {"AVG",	1, 100, fn_avg},
+	[FN_MIN]	= {"MIN",	1, 100, fn_min},
+	[FN_MAX]	= {"MAX",	1, 100, fn_max},
 	[FN_COUNT]  = {"COUNT",  1, 100, fn_count},
-	[FN_ABS]    = {"ABS",    1, 1,   fn_abs},
+	[FN_ABS]	= {"ABS",	1, 1,   fn_abs},
 	[FN_SQRT]   = {"SQRT",   1, 1,   fn_sqrt},
-	[FN_POW]    = {"POW",    2, 2,   fn_pow},
+	[FN_POW]	= {"POW",	2, 2,   fn_pow},
 	[FN_ROUND]  = {"ROUND",  1, 2,   fn_round},
 	[FN_FLOOR]  = {"FLOOR",  1, 1,   fn_floor},
 	[FN_CEIL]   = {"CEIL",   1, 1,   fn_ceil},
-	[FN_IF]     = {"IF",     3, 3,   fn_if},
-	[FN_AND]    = {"AND",    2, 100, fn_and},
-	[FN_OR]     = {"OR",     2, 100, fn_or},
-	[FN_NOT]    = {"NOT",    1, 1,   fn_not},
+	[FN_IF]	 = {"IF",	 3, 3,   fn_if},
+	[FN_AND]	= {"AND",	2, 100, fn_and},
+	[FN_OR]	 = {"OR",	 2, 100, fn_or},
+	[FN_NOT]	= {"NOT",	1, 1,   fn_not},
 	[FN_LOOKUP] = {"LOOKUP", 2, 3,   fn_lookup},
 };
 
 InputMode input_modes[] = {
-	[0] = {"normal",    handle_normal_mode,    handle_normal_mouse,    draw_normal_overlay,    "E:moji  e:cycle  S:ave  O:pen  l:abel  g:rid  r:eload-cfg "},
-	[1] = {"edit",      handle_cell_edit,      handle_edit_mouse,      draw_cell_edit_overlay, "Enter:save  Esc:cancel"},
-	[2] = {"label",     handle_label_edit,     handle_label_mouse,     draw_label_edit_overlay,"Enter:save  Esc:cancel"},
+	[0] = {"normal",	handle_normal_mode,	handle_normal_mouse,	draw_normal_overlay,	"E:moji  e:cycle  S:ave  O:pen  l:abel  g:rid  r:eload-cfg "},
+	[1] = {"edit",	  handle_cell_edit,	  handle_edit_mouse,	  draw_cell_edit_overlay, "Enter:save  Esc:cancel"},
+	[2] = {"label",	 handle_label_edit,	 handle_label_mouse,	 draw_label_edit_overlay,"Enter:save  Esc:cancel"},
 	[3] = {"filename",  handle_filename_input, handle_filename_mouse,  draw_filename_overlay,  "Tab:.spr  Enter:confirm  Esc:cancel"},
 };
 
@@ -539,8 +539,12 @@
 		Bprint(b, "box %d\n", i);
 		Bprint(b, "  pos %d %d\n", box->pos.x, box->pos.y);
 		Bprint(b, "  type %d\n", box->type);
+		
+		Bprint(b, "  formula_len %d\n", (int)strlen(box->formula));
 		Bprint(b, "  formula %s\n", box->formula);
+		
 		Bprint(b, "  value %g\n", box->value);
+		Bprint(b, "  label_len %d\n", (int)strlen(box->label));
 		Bprint(b, "  label %s\n", box->label);
 
 		if(box->nrefs > 0){
@@ -563,6 +567,8 @@
 	char *line;
 	char *fields[10];
 	int nf;
+	int formula_len = 0;
+	int label_len = 0;
 
 	b = Bopen(file, OREAD);
 	if(b == nil){
@@ -586,6 +592,44 @@
 		if(line[0] == '#' || line[0] == '\0')
 			continue;
 
+		// Check for formula with spaces (don't tokenize these lines)
+		if(strncmp(line, "  formula ", 10) == 0){
+			if(sheet.nboxes > 0){
+				Box *box = &sheet.boxes[sheet.nboxes-1];
+				char *content = line + 10;
+				
+				// If we have a length, use it; otherwise just copy what's there
+				if(formula_len > 0 && formula_len < MAXFORMULA){
+					strncpy(box->formula, content, formula_len);
+					box->formula[formula_len] = '\0';
+					formula_len = 0;
+				} else {
+					strncpy(box->formula, content, MAXFORMULA-1);
+					box->formula[MAXFORMULA-1] = '\0';
+				}
+			}
+			continue;
+		}
+		
+		// Check for label with spaces
+		if(strncmp(line, "  label ", 8) == 0){
+			if(sheet.nboxes > 0){
+				Box *box = &sheet.boxes[sheet.nboxes-1];
+				char *content = line + 8;
+				
+				if(label_len > 0 && label_len < 32){
+					strncpy(box->label, content, label_len);
+					box->label[label_len] = '\0';
+					label_len = 0;
+				} else {
+					strncpy(box->label, content, 31);
+					box->label[31] = '\0';
+				}
+			}
+			continue;
+		}
+
+		// For other lines, use tokenize as before
 		nf = tokenize(line, fields, nelem(fields));
 
 		if(nf >= 2 && strcmp(fields[0], "box") == 0){
@@ -604,16 +648,22 @@
 		} else if(nf >= 2 && strcmp(fields[0], "type") == 0){
 			int type = atoi(fields[1]);
 			if (type >= 0 && type < MAXBOXTYPES) {
-				sheet.boxes[sheet.nboxes-1].type = type;
-			} else {
-				sheet.boxes[sheet.nboxes-1].type = T_TEXT;
+				Box *box = &sheet.boxes[sheet.nboxes-1];
+				box->type = type;
+				
+				// Resize box if it's a paragraph
+				if(type == T_PARAGRAPH){
+					box->r = Rect(box->pos.x, box->pos.y, 
+						box->pos.x + config.paragraph_width, 
+						box->pos.y + config.paragraph_height);
+				}
 			}
-		} else if(nf >= 2 && strcmp(fields[0], "formula") == 0){
-			strcpy(sheet.boxes[sheet.nboxes-1].formula, fields[1]);
+		} else if(nf >= 2 && strcmp(fields[0], "formula_len") == 0){
+			formula_len = atoi(fields[1]);
+		} else if(nf >= 2 && strcmp(fields[0], "label_len") == 0){
+			label_len = atoi(fields[1]);
 		} else if(nf >= 2 && strcmp(fields[0], "value") == 0){
 			sheet.boxes[sheet.nboxes-1].value = atof(fields[1]);
-		} else if(nf >= 2 && strcmp(fields[0], "label") == 0){
-			strncpy(sheet.boxes[sheet.nboxes-1].label, fields[1], 31);
 		}
 	}
 
@@ -925,32 +975,6 @@
 }
 
 void
-cmd_reload_config(void)
-{
-	load_config(CONFIG_FILE);
-	validate_config();
-	apply_config();
-	sheet.needredraw = 1;
-	fprint(2, "Configuration reloaded from %s\n", CONFIG_FILE);
-}
-
-void
-handlekey(int key)
-{
-	InputMode *mode = &input_modes[sheet.current_mode];
-	if(mode->handler)
-		mode->handler(key);
-}
-
-void
-handlemouse(Mouse m)
-{
-	InputMode *mode = &input_modes[sheet.current_mode];
-	if(mode->mouse_handler)
-		mode->mouse_handler(m);
-}
-
-void
 initcolors(void)
 {
 	colors[0] = allocimage(display, Rect(0,0,1,1), screen->chan, 1, config.color_fg);
@@ -966,6 +990,19 @@
 	gridcolor = allocimage(display, Rect(0,0,1,1), screen->chan, 1, config.color_grid);
 }
 
+void
+init_emoji(void)
+{
+	sheet.emoji_pos = 0;
+	sheet.emoji_frame = 0;
+	sheet.emoji_dir = 1;
+	sheet.emoji_enabled = config.emoji_enabled;
+
+	int i;
+	for(i = 0; i < 4; i++)
+		sheet.emoji_frames[i] = rcc_style[i];
+}
+
 double
 round(double x)
 {
@@ -1743,6 +1780,17 @@
 }
 
 void
+parse_paragraph(Box *b)
+{
+	if(b->formula[0] == '"'){
+		strncpy(b->content, b->formula + 1, MAXCONTENT - 1);
+	} else {
+		strncpy(b->content, b->formula, MAXCONTENT - 1);
+	}
+	b->content[MAXCONTENT-1] = '\0';
+}
+
+void
 parse_text(Box *b)
 {
 	strncpy(b->content, b->formula, MAXCONTENT);
@@ -1769,6 +1817,12 @@
 }
 
 void
+eval_paragraph(Box *b)
+{
+	USED(b);
+}
+
+void
 draw_box_generic(Box *b, Image *dst)
 {
 	Image *bg = boxbg;
@@ -1917,50 +1971,6 @@
 }
 
 void
-redraw(void)
-{
-	DrawStep *step;
-	draw_emoji_banner();
-	Rectangle clip = screen->r;
-	clip.min.y += config.banner_height;
-	replclipr(screen, 0, clip);
-
-	for(step = draw_steps; step->draw; step++) {
-		if(step->condition == 0 ||
-		   (step->condition == 1 && sheet.gridsnap)) {
-			step->draw();
-		}
-	}
-	replclipr(screen, 0, screen->r);
-
-	InputMode *mode = &input_modes[sheet.current_mode];
-	if(mode->draw)
-		mode->draw();
-
-	flushimage(display, 1);
-}
-
-int
-edit_finish(char *buf, int *pos, int maxlen)
-{
-	USED(buf); USED(pos); USED(maxlen);
-	return 1;
-}
-
-void
-init_emoji(void)
-{
-	sheet.emoji_pos = 0;
-	sheet.emoji_frame = 0;
-	sheet.emoji_dir = 1;
-	sheet.emoji_enabled = config.emoji_enabled;
-
-	int i;
-	for(i = 0; i < 4; i++)
-		sheet.emoji_frames[i] = rcc_style[i];
-}
-
-void
 draw_emoji_banner(void)
 {
 	if(!sheet.emoji_enabled)
@@ -2001,12 +2011,165 @@
 }
 
 void
+draw_box_paragraph(Box *b, Image *dst)
+{
+	Image *bg = boxbg;
+	int idx = b - sheet.boxes;
+
+	/* Determine background color based on state (editing, selected) */
+	if(sheet.editing == idx)
+		bg = boxediting;
+	else if(sheet.editing_label == idx)
+		bg = colors[5];
+	else if(b->selected)
+		bg = boxselected;
+
+	/* Draw box background and border */
+	draw(dst, b->r, bg, nil, ZP);
+	border(dst, b->r, 1, colors[0], ZP);
+
+	/* Draw the cell's label or default name */
+	char cellname[32];
+	if(sheet.editing_label == idx){
+		snprint(cellname, sizeof(cellname), "%s", sheet.labelbuf);
+		string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[4], ZP, font, cellname);
+	} else if(b->label[0]) {
+		snprint(cellname, sizeof(cellname), "%s", b->label);
+		string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[4], ZP, font, cellname);
+	} else {
+		if(idx < 26) {
+			snprint(cellname, sizeof(cellname), "%c", 'A' + idx);
+		} else {
+			snprint(cellname, sizeof(cellname), "%c%c", 'A' + (idx/26)-1, 'A' + (idx%26));
+		}
+		string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[3], ZP, font, cellname);
+	}
+
+	/* Text wrapping logic */
+	Point p = addpt(b->r.min, Pt(config.box_text_margin, config.box_label_offset_y));
+	char *text_to_draw = (sheet.editing == idx) ? sheet.editbuf : b->content;
+	int max_width = Dx(b->r) - (2 * config.box_text_margin);
+	int line_height = font->height;
+
+	char *text = text_to_draw;
+	char *line_start = text;
+	char line_buffer[MAXCONTENT];
+
+	while (*line_start) {
+		char *word_ptr = line_start;
+		char *line_end = line_start;
+		
+		while (*word_ptr) {
+			char *word_start = word_ptr;
+			while(*word_ptr && !isspace(*word_ptr))
+				word_ptr++;
+			
+			int word_len = word_ptr - line_start;
+			if(word_len >= MAXCONTENT) break;
+
+			strncpy(line_buffer, line_start, word_len);
+			line_buffer[word_len] = '\0';
+
+			if(stringwidth(font, line_buffer) > max_width) {
+				if(line_end == line_start)
+					line_end = word_start;
+				break;
+			}
+			line_end = word_ptr;
+
+			while(*word_ptr && isspace(*word_ptr))
+				word_ptr++;
+		}
+		
+		int len = line_end - line_start;
+		stringn(dst, p, colors[0], ZP, font, line_start, len);
+		p.y += line_height;
+		
+		if (p.y > b->r.max.y - config.box_text_margin - line_height)
+			break;
+
+		line_start = line_end;
+		while(*line_start && isspace(*line_start))
+			line_start++;
+	}
+}
+
+void
+redraw(void)
+{
+	DrawStep *step;
+	draw_emoji_banner();
+	Rectangle clip = screen->r;
+	clip.min.y += config.banner_height;
+	replclipr(screen, 0, clip);
+
+	for(step = draw_steps; step->draw; step++) {
+		if(step->condition == 0 ||
+		   (step->condition == 1 && sheet.gridsnap)) {
+			step->draw();
+		}
+	}
+	replclipr(screen, 0, screen->r);
+
+	InputMode *mode = &input_modes[sheet.current_mode];
+	if(mode->draw)
+		mode->draw();
+
+	flushimage(display, 1);
+}
+
+int
+edit_cancel(char *buf, int *pos, int maxlen)
+{
+	USED(maxlen);
+	buf[0] = '\0';
+	*pos = 0;
+	return -1;
+}
+
+int
+edit_backspace(char *buf, int *pos, int maxlen)
+{
+	USED(maxlen);
+	if(*pos > 0) {
+		(*pos)--;
+		buf[*pos] = '\0';
+		sheet.needredraw = 1;
+	}
+	return 0;
+}
+
+int
+edit_add_char(char *buf, int *pos, int maxlen)
+{
+	USED(buf); USED(pos); USED(maxlen);
+	return 0;
+}
+
+int
+edit_finish(char *buf, int *pos, int maxlen)
+{
+	USED(buf); USED(pos); USED(maxlen);
+	return 1;
+}
+
+void
+cmd_reload_config(void)
+{
+	load_config(CONFIG_FILE);
+	validate_config();
+	apply_config();
+	sheet.needredraw = 1;
+	fprint(2, "Configuration reloaded from %s\n", CONFIG_FILE);
+}
+
+void
 cmd_cycle_emoji(void)
 {
 	static int emoji_set = 0;
 	int i;
 
-	emoji_set = (emoji_set + 1) % 7;
+	emoji_set = (emoji_set + 1) % 7; /* +1 each case */
 
 	switch(emoji_set) {
 	case 0:
@@ -2042,42 +2205,6 @@
 }
 
 void
-cmd_toggle_emoji(void)
-{
-	sheet.emoji_enabled = !sheet.emoji_enabled;
-	config.emoji_enabled = sheet.emoji_enabled;
-	sheet.needredraw = 1;
-}
-
-int
-edit_cancel(char *buf, int *pos, int maxlen)
-{
-	USED(maxlen);
-	buf[0] = '\0';
-	*pos = 0;
-	return -1;
-}
-
-int
-edit_backspace(char *buf, int *pos, int maxlen)
-{
-	USED(maxlen);
-	if(*pos > 0) {
-		(*pos)--;
-		buf[*pos] = '\0';
-		sheet.needredraw = 1;
-	}
-	return 0;
-}
-
-int
-edit_add_char(char *buf, int *pos, int maxlen)
-{
-	USED(buf); USED(pos); USED(maxlen);
-	return 0;
-}
-
-void
 cmd_quit(void)
 {
 	int i;
@@ -2165,6 +2292,30 @@
 }
 
 void
+cmd_toggle_emoji(void)
+{
+	sheet.emoji_enabled = !sheet.emoji_enabled;
+	config.emoji_enabled = sheet.emoji_enabled;
+	sheet.needredraw = 1;
+}
+
+void
+handlekey(int key)
+{
+	InputMode *mode = &input_modes[sheet.current_mode];
+	if(mode->handler)
+		mode->handler(key);
+}
+
+void
+handlemouse(Mouse m)
+{
+	InputMode *mode = &input_modes[sheet.current_mode];
+	if(mode->mouse_handler)
+		mode->mouse_handler(m);
+}
+
+void
 handle_normal_mode(int key)
 {
 	Command *cmd;
@@ -2482,107 +2633,6 @@
 
 	fd = create(config.ctl_file, OWRITE, 0644);
 	if(fd >= 0) close(fd);
-}
-
-void
-parse_paragraph(Box *b)
-{
-	if(b->formula[0] == '"'){
-		strncpy(b->content, b->formula + 1, MAXCONTENT - 1);
-	} else {
-		strncpy(b->content, b->formula, MAXCONTENT - 1);
-	}
-	b->content[MAXCONTENT-1] = '\0';
-}
-
-void
-eval_paragraph(Box *b)
-{
-	USED(b);
-}
-
-void
-draw_box_paragraph(Box *b, Image *dst)
-{
-	Image *bg = boxbg;
-	int idx = b - sheet.boxes;
-
-	/* Determine background color based on state (editing, selected) */
-	if(sheet.editing == idx)
-		bg = boxediting;
-	else if(sheet.editing_label == idx)
-		bg = colors[5];
-	else if(b->selected)
-		bg = boxselected;
-
-	/* Draw box background and border */
-	draw(dst, b->r, bg, nil, ZP);
-	border(dst, b->r, 1, colors[0], ZP);
-
-	/* Draw the cell's label or default name */
-	char cellname[32];
-	if(sheet.editing_label == idx){
-		snprint(cellname, sizeof(cellname), "%s", sheet.labelbuf);
-		string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[4], ZP, font, cellname);
-	} else if(b->label[0]) {
-		snprint(cellname, sizeof(cellname), "%s", b->label);
-		string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[4], ZP, font, cellname);
-	} else {
-		if(idx < 26) {
-			snprint(cellname, sizeof(cellname), "%c", 'A' + idx);
-		} else {
-			snprint(cellname, sizeof(cellname), "%c%c", 'A' + (idx/26)-1, 'A' + (idx%26));
-		}
-		string(dst, Pt(b->r.min.x + 2, b->r.min.y + 2), colors[3], ZP, font, cellname);
-	}
-
-	/* Text wrapping logic */
-	Point p = addpt(b->r.min, Pt(config.box_text_margin, config.box_label_offset_y));
-	char *text_to_draw = (sheet.editing == idx) ? sheet.editbuf : b->content;
-	int max_width = Dx(b->r) - (2 * config.box_text_margin);
-	int line_height = font->height;
-
-	char *text = text_to_draw;
-	char *line_start = text;
-	char line_buffer[MAXCONTENT];
-
-	while (*line_start) {
-		char *word_ptr = line_start;
-		char *line_end = line_start;
-		
-		while (*word_ptr) {
-			char *word_start = word_ptr;
-			while(*word_ptr && !isspace(*word_ptr))
-				word_ptr++;
-			
-			int word_len = word_ptr - line_start;
-			if(word_len >= MAXCONTENT) break;
-
-			strncpy(line_buffer, line_start, word_len);
-			line_buffer[word_len] = '\0';
-
-			if(stringwidth(font, line_buffer) > max_width) {
-				if(line_end == line_start)
-					line_end = word_start;
-				break;
-			}
-			line_end = word_ptr;
-
-			while(*word_ptr && isspace(*word_ptr))
-				word_ptr++;
-		}
-		
-		int len = line_end - line_start;
-		stringn(dst, p, colors[0], ZP, font, line_start, len);
-		p.y += line_height;
-		
-		if (p.y > b->r.max.y - config.box_text_margin - line_height)
-			break;
-
-		line_start = line_end;
-		while(*line_start && isspace(*line_start))
-			line_start++;
-	}
 }
 
 void
--