[gnumeric] Improve function tooltips. [#623322]



commit 9ea964acfe00fd01754373c863f0262800f2e17f
Author: Andreas J Guelzow <aguelzow pyrshep ca>
Date:   Tue Jul 13 14:30:54 2010 -0600

    Improve function tooltips. [#623322]
    
    2010-07-13  Andreas J. Guelzow <aguelzow pyrshep ca>
    
    	* gnumeric-expr-entry.c (gee_dump_lexer): new
    	(gee_check_tooltip): rewrite using gnm_expr_lex_all
    
    2010-07-13  Morten Welinder  <terra gnome org>
    
    	* src/parse-util.h (gnm_expr_lex_all): new
    	(GnmLexerItem): new type
    	* src/parser.y (setup_state): new (code from gnm_expr_parse_str)
    	(gnm_expr_lex_all): new
    	(gnm_expr_parse_str): use setup_state

 ChangeLog                         |    8 ++
 NEWS                              |    1 +
 src/parse-util.h                  |   10 ++
 src/parser.y                      |  155 ++++++++++++++++++++++---------
 src/widgets/ChangeLog             |    5 +
 src/widgets/gnumeric-expr-entry.c |  184 ++++++++++++++++++++++--------------
 6 files changed, 245 insertions(+), 118 deletions(-)
---
diff --git a/ChangeLog b/ChangeLog
index 700293f..33900ca 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2010-07-13  Morten Welinder  <terra gnome org>
+
+	* src/parse-util.h (gnm_expr_lex_all): new
+	(GnmLexerItem): new type
+	* src/parser.y (setup_state): new (code from gnm_expr_parse_str)
+	(gnm_expr_lex_all): new
+	(gnm_expr_parse_str): use setup_state
+
 2010-07-13  Jean Brefort  <jean brefort normalesup org>
 
 	* src/cellspan.c (cell_calc_span): fixed crash introduced earlier. [#624274]
diff --git a/NEWS b/NEWS
index 9313104..6031fb8 100644
--- a/NEWS
+++ b/NEWS
@@ -28,6 +28,7 @@ Andreas:
 	* Add new function SORT. [#59144]
 	* Add menu item to wrap SORT around an existing range.
 	* Show the number of rows filtered by the auto filter. [#346002]
+	* Improve function tooltips. [#623322]
 
 Jean:
 	* Fix strong/weak cursor display. [#623241]
diff --git a/src/parse-util.h b/src/parse-util.h
index 4da653a..ed52b42 100644
--- a/src/parse-util.h
+++ b/src/parse-util.h
@@ -76,6 +76,11 @@ struct _GnmParseError {
 	int begin_char, end_char;
 };
 
+typedef struct {
+	gsize start, end;
+	int token;
+} GnmLexerItem;
+
 GnmParseError *parse_error_init (GnmParseError *pe);
 void        parse_error_free (GnmParseError *pe);
 
@@ -200,6 +205,11 @@ GnmExprTop const *gnm_expr_parse_str (char const *str, GnmParsePos const *pp,
 				      GnmConventions const *convs,
 				      GnmParseError *error);
 
+GnmLexerItem *gnm_expr_lex_all (char const *str, GnmParsePos const *pp,
+				GnmExprParseFlags flags,
+				GnmConventions const *convs);
+
+
 /* Is this string potentially the start of an expression */
 char const *gnm_expr_char_start_p (char const *c);
 
diff --git a/src/parser.y b/src/parser.y
index 4eb6ec9..4c7c811 100644
--- a/src/parser.y
+++ b/src/parser.y
@@ -1440,6 +1440,59 @@ yyerror (char const *s)
 	return 0;
 }
 
+static void
+setup_state (ParserState *pstate, const char *str,
+	     GnmParsePos const *pp,
+	     GnmExprParseFlags flags,
+	     GnmConventions const *convs,
+	     GnmParseError *error)
+{
+	pstate->start = pstate->ptr = str;
+	pstate->pos   = pp;
+
+	pstate->flags		= flags;
+	pstate->convs                                    =
+		(NULL != convs) ? convs : ((NULL != pp->sheet) ? pp->sheet->convs : gnm_conventions_default);
+
+
+	pstate->decimal_point = pstate->convs->decimal_sep_dot
+		? '.'
+		: g_utf8_get_char (go_locale_get_decimal ()->str); /* FIXME: one char handled.  */
+
+	if (pstate->convs->arg_sep != 0)
+		pstate->arg_sep = pstate->convs->arg_sep;
+	else
+		pstate->arg_sep = go_locale_get_arg_sep ();
+	if (pstate->convs->array_col_sep != 0)
+		pstate->array_col_sep = pstate->convs->array_col_sep;
+	else
+		pstate->array_col_sep = go_locale_get_col_sep ();
+	if (pstate->convs->array_row_sep != 0)
+		pstate->array_row_sep = pstate->convs->array_row_sep;
+	else
+		pstate->array_row_sep = go_locale_get_row_sep ();
+
+	/* Some locales/conventions have ARG_SEP == ARRAY_ROW_SEP
+	 * 	eg {1\2\3;4\5\6} for XL style with ',' as a decimal
+	 * some have ARG_SEP == ARRAY_COL_SEPARATOR
+	 * 	eg {1,2,3;4,5,6} for XL style with '.' as a decimal
+	 * 	or {1;2;3|4;5;6} for OOo/
+	 * keep track of whether we are in an array to allow the lexer to
+	 * dis-ambiguate. */
+	if (pstate->arg_sep == pstate->array_col_sep)
+		pstate->in_array_sep_is = ARRAY_COL_SEP;
+	else if (pstate->arg_sep == pstate->array_row_sep)
+		pstate->in_array_sep_is = ARRAY_ROW_SEP;
+	else
+		pstate->in_array_sep_is = ARG_SEP;
+	pstate->in_array = 0;
+
+	pstate->result = NULL;
+	pstate->error = error;
+
+	state = pstate;
+}
+
 /**
  * gnm_expr_parse_str:
  *
@@ -1466,56 +1519,12 @@ gnm_expr_parse_str (char const *str, GnmParsePos const *pp,
 
 	g_return_val_if_fail (str != NULL, NULL);
 	g_return_val_if_fail (pp != NULL, NULL);
-
-	pstate.start = pstate.ptr = str;
-	pstate.pos   = pp;
-
-	pstate.flags		= flags;
-	pstate.convs                                    =
-		(NULL != convs) ? convs : ((NULL != pp->sheet) ? pp->sheet->convs : gnm_conventions_default);
-
-
-	pstate.decimal_point = pstate.convs->decimal_sep_dot
-		? '.'
-		: g_utf8_get_char (go_locale_get_decimal ()->str); /* FIXME: one char handled.  */
-
-	if (pstate.convs->arg_sep != 0)
-		pstate.arg_sep = pstate.convs->arg_sep;
-	else
-		pstate.arg_sep = go_locale_get_arg_sep ();
-	if (pstate.convs->array_col_sep != 0)
-		pstate.array_col_sep = pstate.convs->array_col_sep;
-	else
-		pstate.array_col_sep = go_locale_get_col_sep ();
-	if (pstate.convs->array_row_sep != 0)
-		pstate.array_row_sep = pstate.convs->array_row_sep;
-	else
-		pstate.array_row_sep = go_locale_get_row_sep ();
-
-	/* Some locales/conventions have ARG_SEP == ARRAY_ROW_SEP
-	 * 	eg {1\2\3;4\5\6} for XL style with ',' as a decimal
-	 * some have ARG_SEP == ARRAY_COL_SEPARATOR
-	 * 	eg {1,2,3;4,5,6} for XL style with '.' as a decimal
-	 * 	or {1;2;3|4;5;6} for OOo/
-	 * keep track of whether we are in an array to allow the lexer to
-	 * dis-ambiguate. */
-	if (pstate.arg_sep == pstate.array_col_sep)
-		pstate.in_array_sep_is = ARRAY_COL_SEP;
-	else if (pstate.arg_sep == pstate.array_row_sep)
-		pstate.in_array_sep_is = ARRAY_ROW_SEP;
-	else
-		pstate.in_array_sep_is = ARG_SEP;
-	pstate.in_array = 0;
-
-	pstate.result = NULL;
-	pstate.error = error;
+	g_return_val_if_fail (state == NULL, NULL);
 
 	if (deallocate_stack == NULL)
 		deallocate_init ();
 
-	g_return_val_if_fail (state == NULL, NULL);
-
-	state = &pstate;
+	setup_state (&pstate, str, pp, flags, convs, error);
 	yyparse ();
 	state = NULL;
 
@@ -1586,3 +1595,57 @@ gnm_expr_parse_str (char const *str, GnmParsePos const *pp,
 
 	return gnm_expr_top_new (expr);
 }
+
+GnmLexerItem *
+gnm_expr_lex_all (char const *str, GnmParsePos const *pp,
+		  GnmExprParseFlags flags,
+		  GnmConventions const *convs)
+{
+	GnmLexerItem *res = NULL;
+	int n = 0, alloc = 0;
+	ParserState pstate;
+	GnmParseError *error = NULL;
+
+	g_return_val_if_fail (str != NULL, NULL);
+	g_return_val_if_fail (pp != NULL, NULL);
+
+	if (deallocate_stack == NULL)
+		deallocate_init ();
+
+	setup_state (&pstate, str, pp, flags, convs, error);
+
+	while (1) {
+		int len;
+
+		if (alloc <= n) {
+			alloc = alloc * 2 + 20;
+			res = g_renew (GnmLexerItem, res, alloc);
+		}
+
+		res[n].start = pstate.ptr - pstate.start;
+		res[n].token = yylex ();
+		res[n].end = pstate.ptr - pstate.start;
+
+		if (res[n].token == 0)
+			break;
+
+		len = res[n].end - res[n].start;
+		/* Kill spaces that got eaten, but not a space operator */
+		while (len > 1 && str[res[n].start] == ' ') {
+			res[n].start++;
+			len--;
+		}
+		while (len > 1 && str[res[n].end - 1] == ' ') {
+			res[n].end--;
+			len--;
+		}
+
+		n++;
+	}
+
+	deallocate_all ();
+
+	state = NULL;
+
+	return res;
+}
diff --git a/src/widgets/ChangeLog b/src/widgets/ChangeLog
index c9953d8..029e10a 100644
--- a/src/widgets/ChangeLog
+++ b/src/widgets/ChangeLog
@@ -1,5 +1,10 @@
 2010-07-13  Andreas J. Guelzow <aguelzow pyrshep ca>
 
+	* gnumeric-expr-entry.c (gee_dump_lexer): new
+	(gee_check_tooltip): rewrite using gnm_expr_lex_all
+
+2010-07-13  Andreas J. Guelzow <aguelzow pyrshep ca>
+
 	* gnm-filter-combo-view.c: show the number of filtered rows in
 	  the progress bar region
 
diff --git a/src/widgets/gnumeric-expr-entry.c b/src/widgets/gnumeric-expr-entry.c
index 7b615f3..ea5f46d 100644
--- a/src/widgets/gnumeric-expr-entry.c
+++ b/src/widgets/gnumeric-expr-entry.c
@@ -735,17 +735,34 @@ gee_set_tooltip (GnmExprEntry *gee, GnmFunc *fd, gint args, gboolean had_stuff)
 }
 
 static void
+gee_dump_lexer (GnmLexerItem *gli) {
+	g_print ("************\n");
+	while (gli->token != 0) {
+		g_print ("%2d to %2d: %d\n", 
+			 gli->start, gli->end, gli->token);
+		gli++;
+	}
+	g_print ("************\n");
+	
+}
+
+#warning We should replace these token names with the correct values
+#define  TOKEN_UNMATCHED_APOSTROPHY 273
+#define  TOKEN_PARENTHESIS_OPEN 40
+#define  TOKEN_PARENTHESIS_CLOSED 41
+#define  TOKEN_BRACE_OPEN 123
+#define  TOKEN_BRACE_CLOSED 125
+#define  TOKEN_SEPARATOR 269
+#define  TOKEN_NAME 258
+
+static void
 gee_check_tooltip (GnmExprEntry *gee)
 {
 	GtkEditable *editable = GTK_EDITABLE (gee->entry);
-	gint  end;
+	gint  end, args = 0;
 	char *str;
-	char *prefix, *start;
-	char *str_end;
-	int   args = 0;
-	gchar sep = go_locale_get_arg_sep ();
-	gint  para = 0, stuff = 0;
-	char quote;
+	gboolean stuff = FALSE;
+	GnmLexerItem *gli, *gli_c;
 
 	if (!gee->tooltip.enabled || gee->is_cell_renderer ||
 	    (gee->flags & GNM_EE_SINGLE_RANGE) ||
@@ -760,83 +777,106 @@ gee_check_tooltip (GnmExprEntry *gee)
 	}
 
 	str = gtk_editable_get_chars (editable, 0, end);
-	prefix = str_end = str + strlen (str) - 1;
 
+	gli = gnm_expr_lex_all (str, &gee->pp,
+				GNM_EXPR_PARSE_UNKNOWN_NAMES_ARE_STRINGS,
+				NULL);
+	if (gnm_debug_flag ("functooltip"))
+		gee_dump_lexer (gli);
 	/*
 	 * If we have an open string at the end of the entry, we
-	 * need to adjust "prefix" to be in front of that.
+	 * need to adjust
 	 */
-	start = str;
-	while (*start) {
-		if (*start == '"' || *start == '\'') {
-			GString *dummy = g_string_new (NULL);
-			const char *e = go_strunescape (dummy, start);
-			g_string_free (dummy, TRUE);
-			if (!e) {
-				/* We never saw the end of the string */
-				prefix = start;
-				if (prefix != str)
-					prefix--;
-				stuff = 1;
-				break;
-			}
-			start = (char *)e;
-		} else
-			start++;
-	}
 
-	while (str < prefix) {
-		if (*prefix == ')') {
-			para--;
-		} else if (*prefix == '(') {
-			para++;
-			if (para == 1) {
-				/* last opened and yet not closed ( */
-				*prefix='\0';
-
-				do {
-					prefix--;
-				} while (prefix >= str &&
-					 (g_ascii_isalnum (*prefix) ||
-					  *prefix == '.' ||
-					  *prefix == '_'));
-				prefix++;
-
-				if (*prefix != '\0') {
-					GnmFunc	*fd = gnm_func_lookup (prefix, NULL);
-					if (fd != NULL) {
-						gee_set_tooltip (gee, fd, args, !!stuff);
-						g_free (str);
-						return;
-					}
+	for (gli_c = gli; gli->token != 0; gli++) {
+		if (gli->token != TOKEN_UNMATCHED_APOSTROPHY)
+			continue;
+		if (gli->start == 0)
+			goto not_found;
+		end = gli->start - 1;
+		gli->token = 0;
+		stuff = TRUE;
+	}
+	gli--;
+
+	while (gli->start > 1) {
+		switch (gli->token) {
+		case TOKEN_PARENTHESIS_OPEN:
+			if ((gli - 1)->token == TOKEN_NAME) {
+				gint start_t = (gli - 1)->start;
+				gint end_t = (gli - 1)->end;
+				char *name = g_strndup (str + start_t, 
+							end_t - start_t);
+				GnmFunc	*fd = gnm_func_lookup (name, NULL);
+				g_free (name);
+				if (fd != NULL) {
+					gee_set_tooltip (gee, fd, args, stuff);
+					g_free (str);
+					g_free (gli_c);
+					return;
 				}
-				args = 0;
-				para--;
 			}
-			stuff++;
-		} else if (*prefix == sep && para == 0) {
-			stuff = 0;
-			args++;
-		} else if (*prefix != ' ')
-			stuff++;
-
-		if (*prefix == '\'' || *prefix == '"') {
-			quote = *prefix--;
-
-			while (*prefix != quote ||
-			       (prefix > str && prefix[-1] == '\\')) {
-				if (prefix == str)
-					goto not_found;
-				prefix--;
+			stuff = TRUE;
+			args = 0;
+			break;
+		case TOKEN_BRACE_OPEN:
+			stuff = (args == 0);
+			args = 0;
+			break;
+		case TOKEN_PARENTHESIS_CLOSED: {
+			gint para = 1;
+			gli--;
+			while (gli->start > 1 && para > 0) {
+				switch (gli->token) {
+				case TOKEN_PARENTHESIS_CLOSED:
+					para++;
+					break;
+				case TOKEN_PARENTHESIS_OPEN:
+					para--; 
+					break;
+				default:
+					break;
+				}
+				gli--;
 			}
-
-			if (prefix == str)
-				goto not_found;
+			gli++;
+			stuff = (args == 0);
+			break;
 		}
-		prefix--;
+		case TOKEN_BRACE_CLOSED: {
+			gint para = 1;
+			gli--;
+			while (gli->start > 1 && para > 0) {
+				switch (gli->token) {
+				case TOKEN_BRACE_CLOSED:
+					para++;
+					break;
+				case TOKEN_BRACE_OPEN:
+					para--; 
+					break;
+				default:
+					break;
+				}
+				gli--;
+			}
+			gli++;
+			stuff = (args == 0);
+			break;
+		}
+		case TOKEN_SEPARATOR:
+			args++;
+			break;
+		default:
+			stuff = (args == 0);
+			break;
+		}
+		if (gli->start > 1)
+			gli--;
 	}
+
  not_found:
 	g_free (str);
+	g_free (gli_c);
 	gee_delete_tooltip (gee);
 	return;
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]