Commit 9ea964ac authored by Andreas J. Guelzow 's avatar Andreas J. Guelzow

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
parent cd44a63b
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]
......
......@@ -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]
......
......@@ -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);
......
......@@ -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;
}
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
......
......@@ -734,18 +734,35 @@ gee_set_tooltip (GnmExprEntry *gee, GnmFunc *fd, gint args, gboolean had_stuff)
g_string_free (str, TRUE);
}
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;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment