Commit 592cd1c3 authored by Morten Welinder's avatar Morten Welinder

GnmFunc: fix life cycle of help texts too.

parent e83e7946
......@@ -464,7 +464,7 @@ call_python_function_args (GnmFuncEvalInfo *ei, GnmValue const * const *args)
ServiceLoaderDataFunctionGroup *loader_data;
PyObject *fn_info_tuple;
PyObject *python_fn;
GnmFunc const * fndef;
GnmFunc *fndef;
gint min_n_args, max_n_args, n_args;
......@@ -675,9 +675,10 @@ gplp_func_load_stub (GOPluginService *service,
PyString_Check (python_args) &&
(python_fn = PyTuple_GetItem (fn_info_obj, 2)) != NULL &&
PyCallable_Check (python_fn)) {
GnmFuncHelp const *help = python_function_get_gnumeric_help
(loader_data->python_fn_info_dict, python_fn, name);
gnm_func_set_fixargs (func, call_python_function_args, PyString_AsString (python_args));
func->help = python_function_get_gnumeric_help (
loader_data->python_fn_info_dict, python_fn, name);
gnm_func_set_help (func, help, -1);
gnm_func_set_impl_status (func, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC);
g_object_set_data (G_OBJECT (func), SERVICE_KEY, service);
return;
......@@ -688,9 +689,10 @@ gplp_func_load_stub (GOPluginService *service,
}
if (PyCallable_Check (fn_info_obj)) {
gnm_func_set_varargs (func, call_python_function_nodes);
func->help = python_function_get_gnumeric_help (
loader_data->python_fn_info_dict, fn_info_obj, name);
GnmFuncHelp const *help = python_function_get_gnumeric_help
(loader_data->python_fn_info_dict, fn_info_obj, name);
gnm_func_set_varargs (func, call_python_function_nodes, NULL);
gnm_func_set_help (func, help, -1);
gnm_func_set_impl_status (func, GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC);
g_object_set_data (G_OBJECT (func), SERVICE_KEY, service);
return;
......
......@@ -739,10 +739,13 @@ describe_new_style (GtkTextBuffer *description,
gboolean seen_extref = FALSE;
gboolean is_TEXT =
g_ascii_strcasecmp (gnm_func_get_name (func, FALSE), "TEXT") == 0;
int n;
gtk_text_buffer_get_end_iter (description, &ti);
for (help = func->help; 1; help++) {
help = gnm_func_get_help (func, &n);
for (; n-- > 0; help++) {
switch (help->type) {
case GNM_FUNC_HELP_NAME: {
const char *text = gnm_func_gettext (func, help->text);
......@@ -839,9 +842,6 @@ describe_new_style (GtkTextBuffer *description,
ADD_TEXT ("\n");
break;
}
case GNM_FUNC_HELP_END:
FINISH_ARGS;
return;
case GNM_FUNC_HELP_EXTREF: {
GtkTextTag *link;
char *uri, *tagname;
......@@ -899,6 +899,7 @@ describe_new_style (GtkTextBuffer *description,
break;
}
}
FINISH_ARGS;
}
#undef ADD_TEXT_WITH_ARGS
......@@ -1063,7 +1064,7 @@ cb_dialog_function_select_fun_selection_changed (GtkTreeSelection *selection,
gnm_func_load_if_stub (func);
if (func->help == NULL)
if (gnm_func_get_help (func, NULL) == NULL)
gtk_text_buffer_set_text (description, "?", -1);
else
describe_new_style (description,
......@@ -1084,14 +1085,15 @@ static const gchar *
dialog_function_select_peek_description (GnmFunc *func)
{
GnmFuncHelp const *help;
int n;
gnm_func_load_if_stub (func);
help = func->help;
help = gnm_func_get_help (func, &n);
if (help == NULL)
return "";
for (; TRUE; help++) {
for (; n-- > 0; help++) {
switch (help->type) {
case GNM_FUNC_HELP_ARG:
case GNM_FUNC_HELP_NOTE:
......@@ -1108,10 +1110,9 @@ dialog_function_select_peek_description (GnmFunc *func)
const char *colon = strchr (text, ':');
return (colon ? colon + 1 : text);
}
case GNM_FUNC_HELP_END:
return "";
}
}
return "";
}
......
......@@ -510,7 +510,7 @@ static GnmFuncDescriptor const builtins [] = {
GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
GNM_FUNC_TEST_STATUS_EXHAUSTIVE
},
{ "table", "",
{ "table", NULL,
help_table, NULL, gnumeric_table,
GNM_FUNC_SIMPLE + GNM_FUNC_INTERNAL,
GNM_FUNC_IMPL_STATUS_UNIQUE_TO_GNUMERIC,
......
......@@ -134,9 +134,8 @@ gnm_func_load_stub (GnmFunc *func)
g_signal_emit (G_OBJECT (func), signals[SIG_LOAD_STUB], 0);
if (func->fn_type == GNM_FUNC_TYPE_STUB) {
static GnmFuncHelp const no_help[] = { { GNM_FUNC_HELP_END } };
gnm_func_set_varargs (func, error_function_no_full_info);
func->help = no_help;
gnm_func_set_varargs (func, error_function_no_full_info, NULL);
gnm_func_set_help (func, NULL, 0);
}
}
......@@ -256,21 +255,21 @@ gnm_func_group_get_nth (int n)
}
static void
gnm_func_group_add_func (GnmFuncGroup *fn_group, GnmFunc *fn_def)
gnm_func_group_add_func (GnmFuncGroup *fn_group, GnmFunc *func)
{
g_return_if_fail (fn_group != NULL);
g_return_if_fail (fn_def != NULL);
g_return_if_fail (func != NULL);
fn_group->functions = g_slist_prepend (fn_group->functions, fn_def);
fn_group->functions = g_slist_prepend (fn_group->functions, func);
}
static void
gnm_func_group_remove_func (GnmFuncGroup *fn_group, GnmFunc *fn_def)
gnm_func_group_remove_func (GnmFuncGroup *fn_group, GnmFunc *func)
{
g_return_if_fail (fn_group != NULL);
g_return_if_fail (fn_def != NULL);
g_return_if_fail (func != NULL);
fn_group->functions = g_slist_remove (fn_group->functions, fn_def);
fn_group->functions = g_slist_remove (fn_group->functions, func);
if (fn_group->functions == NULL) {
categories = g_list_remove (categories, fn_group);
if (unknown_cat == fn_group)
......@@ -282,26 +281,24 @@ gnm_func_group_remove_func (GnmFuncGroup *fn_group, GnmFunc *fn_def)
/******************************************************************************/
static void
gnm_func_create_arg_names (GnmFunc *fn_def)
gnm_func_create_arg_names (GnmFunc *func)
{
int i;
GPtrArray *ptr;
g_return_if_fail (fn_def != NULL);
g_return_if_fail (func != NULL);
ptr = g_ptr_array_new ();
for (i = 0;
fn_def->help && fn_def->help[i].type != GNM_FUNC_HELP_END;
i++) {
for (i = 0; i < func->help_count; i++) {
const char *s;
if (fn_def->help[i].type != GNM_FUNC_HELP_ARG)
if (func->help[i].type != GNM_FUNC_HELP_ARG)
continue;
s = gnm_func_gettext (fn_def, fn_def->help[i].text);
s = gnm_func_gettext (func, func->help[i].text);
g_ptr_array_add (ptr, split_at_colon (s, NULL));
}
fn_def->arg_names = ptr;
func->arg_names = ptr;
}
gboolean
......@@ -339,15 +336,18 @@ gnm_func_set_stub (GnmFunc *func)
func->nodes_func = NULL;
func->args_func = NULL;
gnm_func_set_help (func, NULL, 0);
}
/**
* gnm_func_set_varargs: (skip)
* @func: #GnmFunc
* @fn: evaluation function
* @spec: (optional): argument type specification
*/
void
gnm_func_set_varargs (GnmFunc *func, GnmFuncNodes fn)
gnm_func_set_varargs (GnmFunc *func, GnmFuncNodes fn, const char *spec)
{
g_return_if_fail (GNM_IS_FUNC (func));
g_return_if_fail (fn != NULL);
......@@ -356,8 +356,16 @@ gnm_func_set_varargs (GnmFunc *func, GnmFuncNodes fn)
func->fn_type = GNM_FUNC_TYPE_NODES;
func->nodes_func = fn;
func->arg_spec = g_strdup (spec);
func->min_args = 0;
func->min_args = G_MAXINT;
if (spec) {
const char *p = strchr (spec, '|');
const char *q = strchr (spec, '.'); // "..."
if (p) func->min_args = p - spec;
if (!q) func->min_args = strlen (spec) - (p != NULL);
}
}
/**
......@@ -393,6 +401,61 @@ gnm_func_set_fixargs (GnmFunc *func, GnmFuncArgs fn, const char *spec)
gnm_func_create_arg_names (func);
}
/**
* gnm_func_get_help:
* @func: #GnmFunc
* @n: (out) (optional): number of help items, not counting the end item
*
* Returns: (transfer none) (array length=n) (nullable): @func's help items.
*/
GnmFuncHelp const *
gnm_func_get_help (GnmFunc *func, int *n)
{
if (n) *n = 0;
g_return_val_if_fail (GNM_IS_FUNC (func), NULL);
g_return_val_if_fail (func->help, NULL);
if (n) *n = func->help_count;
return func->help;
}
void
gnm_func_set_help (GnmFunc *func, GnmFuncHelp const *help, int n)
{
g_return_if_fail (GNM_IS_FUNC (func));
g_return_if_fail (n <= 0 || help != NULL);
if (n < 0) {
for (n = 0; help && help[n].type != GNM_FUNC_HELP_END; )
n++;
}
if (func->help) {
int i;
for (i = 0; i <= func->help_count; i++)
g_free ((char *)(func->help[i].text));
g_free (func->help);
func->help = NULL;
}
if (help) {
int i;
func->help = g_new (GnmFuncHelp, n + 1);
for (i = 0; i < n; i++) {
func->help[i].type = help[i].type;
func->help[i].text = g_strdup (help[i].text);
}
func->help[n].type = GNM_FUNC_HELP_END;
func->help[n].text = NULL;
}
func->help_count = n;
}
static void
gnm_func_set_localized_name (GnmFunc *fd, const char *lname)
{
......@@ -580,7 +643,7 @@ gnm_func_set_translation_domain (GnmFunc *func, const char *tdomain)
* @func: #GnmFunc
* @str: string to translate
*
* Returns: (transfer none): @str translated in the relevant translation
* Returns: (transfer none): @str translated in @func's translation
* domain.
*/
char const *
......@@ -589,7 +652,7 @@ gnm_func_gettext (GnmFunc *func, const char *str)
g_return_val_if_fail (GNM_IS_FUNC (func), NULL);
g_return_val_if_fail (str != NULL, NULL);
return dgettext ((func)->tdomain->str, str);
return dgettext (func->tdomain->str, str);
}
......@@ -674,6 +737,8 @@ gnm_func_set_function_group (GnmFunc *func, GnmFuncGroup *group)
void
gnm_func_set_from_desc (GnmFunc *func, GnmFuncDescriptor const *desc)
{
//static char const valid_tokens[] = "fsbraAES?|";
g_return_if_fail (GNM_IS_FUNC (func));
g_return_if_fail (desc != NULL);
......@@ -683,15 +748,13 @@ gnm_func_set_from_desc (GnmFunc *func, GnmFuncDescriptor const *desc)
if (desc->fn_args != NULL) {
gnm_func_set_fixargs (func, desc->fn_args, desc->arg_spec);
} else if (desc->fn_nodes != NULL) {
if (desc->arg_spec && *desc->arg_spec)
g_warning ("Arg spec for node function -- why?");
gnm_func_set_varargs (func, desc->fn_nodes);
gnm_func_set_varargs (func, desc->fn_nodes, desc->arg_spec);
} else {
gnm_func_set_stub (func);
return;
}
func->help = desc->help ? desc->help : NULL;
gnm_func_set_help (func, desc->help, -1);
func->flags = desc->flags;
func->impl_status = desc->impl_status;
func->test_status = desc->test_status;
......@@ -711,7 +774,6 @@ gnm_func_add (GnmFuncGroup *fn_group,
GnmFuncDescriptor const *desc,
const char *tdomain)
{
//static char const valid_tokens[] = "fsbraAES?|";
GnmFunc *func;
g_return_val_if_fail (fn_group != NULL, NULL);
......@@ -916,11 +978,7 @@ gnm_func_get_name (GnmFunc const *func, gboolean localized)
gnm_func_load_if_stub (fd);
for (i = 0;
(func->localized_name == NULL &&
func->help &&
func->help[i].type != GNM_FUNC_HELP_END);
i++) {
for (i = 0; func->localized_name == NULL && i < func->help_count; i++) {
const char *s, *sl;
char *U;
if (func->help[i].type != GNM_FUNC_HELP_NAME)
......@@ -960,9 +1018,7 @@ gnm_func_get_description (GnmFunc *func)
gnm_func_load_if_stub (func);
for (i = 0;
func->help && func->help[i].type != GNM_FUNC_HELP_END;
i++) {
for (i = 0; i < func->help_count; i++) {
const char *desc;
if (func->help[i].type != GNM_FUNC_HELP_NAME)
......@@ -976,7 +1032,7 @@ gnm_func_get_description (GnmFunc *func)
/**
* gnm_func_count_args:
* @fn_def: pointer to function definition
* @func: pointer to function definition
* @min: (out): location for mininum args
* @max: (out): location for mininum args
*
......@@ -984,49 +1040,48 @@ gnm_func_get_description (GnmFunc *func)
* For a vararg function, the maximum will be set to G_MAXINT.
**/
void
gnm_func_count_args (GnmFunc const *fn_def, int *min, int *max)
gnm_func_count_args (GnmFunc *func, int *min, int *max)
{
g_return_if_fail (min != NULL);
g_return_if_fail (max != NULL);
g_return_if_fail (fn_def != NULL);
g_return_if_fail (func != NULL);
gnm_func_load_if_stub ((GnmFunc *)fn_def);
gnm_func_load_if_stub (func);
*min = fn_def->min_args;
*max = fn_def->max_args;
*min = func->min_args;
*max = func->max_args;
}
/**
* gnm_func_get_arg_type:
* @fn_def: the fn defintion
* @func: the fn defintion
* @arg_idx: zero-based argument offset
*
* Returns: the type of the argument
**/
char
gnm_func_get_arg_type (GnmFunc const *fn_def, int arg_idx)
gnm_func_get_arg_type (GnmFunc *func, int arg_idx)
{
g_return_val_if_fail (fn_def != NULL, '?');
g_return_val_if_fail (func != NULL, '?');
gnm_func_load_if_stub ((GnmFunc *)fn_def);
gnm_func_load_if_stub (func);
g_return_val_if_fail (arg_idx >= 0 && arg_idx < fn_def->max_args, '?');
g_return_val_if_fail (arg_idx >= 0 && arg_idx < func->max_args, '?');
return fn_def->arg_types ? fn_def->arg_types[arg_idx] : '?';
return func->arg_types ? func->arg_types[arg_idx] : '?';
}
/**
* gnm_func_get_arg_type_string:
* @fn_def: the fn defintion
* @func: the fn defintion
* @arg_idx: zero-based argument offset
*
* Return value: (transfer none): the type of the argument as a string
**/
char const *
gnm_func_get_arg_type_string (GnmFunc const *fn_def,
int arg_idx)
gnm_func_get_arg_type_string (GnmFunc *func, int arg_idx)
{
switch (gnm_func_get_arg_type (fn_def, arg_idx)) {
switch (gnm_func_get_arg_type (func, arg_idx)) {
case 'f':
return _("Number");
case 's':
......@@ -1085,9 +1140,7 @@ gnm_func_get_arg_description (GnmFunc *func, guint arg_idx)
gnm_func_load_if_stub (func);
for (i = 0;
func->help && func->help[i].type != GNM_FUNC_HELP_END;
i++) {
for (i = 0; i < func->help_count; i++) {
gchar const *desc;
if (func->help[i].type != GNM_FUNC_HELP_ARG)
......
......@@ -76,13 +76,6 @@ typedef enum {
GNM_FUNC_VOLATILE = 1 << 0, /* eg now(), today() */
GNM_FUNC_RETURNS_NON_SCALAR = 1 << 1, /* eg transpose(), mmult() */
/* For functions that are not exactly compatible with various import
* formats. We need to recalc their results to avoid changing values
* unexpectedly when we recalc later. This probably needs to be done
* on a per import format basis. It may not belong here.
*/
/* GNM_FUNC_RECALC_ONLOAD = 1 << 2, */
/* an unknown function that will hopefully be defined later */
GNM_FUNC_IS_PLACEHOLDER = 1 << 3,
GNM_FUNC_IS_WORKBOOK_LOCAL = 1 << 5,
......@@ -184,7 +177,7 @@ struct GnmFunc_ {
GObject base;
char const *name;
GnmFuncHelp const *help;
GnmFuncHelp *help;
/* <private> */
GnmFuncType fn_type;
......@@ -209,6 +202,7 @@ struct GnmFunc_ {
GPtrArray *arg_names;
int min_args, max_args;
char *arg_types;
int help_count;
};
#define GNM_FUNC_TYPE (gnm_func_get_type ())
......@@ -245,10 +239,14 @@ gboolean gnm_func_is_varargs (GnmFunc *func);
gboolean gnm_func_is_fixargs (GnmFunc *func);
void gnm_func_set_stub (GnmFunc *func);
void gnm_func_set_varargs (GnmFunc *func, GnmFuncNodes fn);
void gnm_func_set_varargs (GnmFunc *func, GnmFuncNodes fn,
const char *spec);
void gnm_func_set_fixargs (GnmFunc *func, GnmFuncArgs fn,
const char *spec);
GnmFuncHelp const *gnm_func_get_help (GnmFunc *func, int *n);
void gnm_func_set_help (GnmFunc *func, GnmFuncHelp const *help, int n);
GnmDependentFlags gnm_func_link_dep (GnmFunc *func, GnmFuncEvalInfo *ei, gboolean qlink);
char const *gnm_func_get_name (GnmFunc const *func,
......@@ -270,12 +268,9 @@ GnmFunc *gnm_func_lookup_or_add_placeholder (char const *name);
/* TODO */
char const *gnm_func_get_description (GnmFunc *func);
void gnm_func_count_args (GnmFunc const *fn_def,
gint *min, int *max);
char gnm_func_get_arg_type (GnmFunc const *fn_def,
gint arg_idx);
char const *gnm_func_get_arg_type_string (GnmFunc const *fn_def,
gint arg_idx);
void gnm_func_count_args (GnmFunc *func, gint *min, int *max);
char gnm_func_get_arg_type (GnmFunc *func, gint arg_idx);
char const *gnm_func_get_arg_type_string (GnmFunc *func, gint arg_idx);
char *gnm_func_get_arg_name (GnmFunc const *func, guint arg_idx);
char const *gnm_func_get_arg_description (GnmFunc *func, guint arg_idx);
char *gnm_func_convert_markup_to_pango (char const *desc,
......
......@@ -125,12 +125,13 @@ dump_externals (GPtrArray *defs, FILE *out)
for (ui = 0; ui < defs->len; ui++) {
GnmFunc *fd = g_ptr_array_index (defs, ui);
gboolean any = FALSE;
int j;
int j, n;
GnmFuncHelp const *help = gnm_func_get_help (fd, &n);
for (j = 0; fd->help[j].type != GNM_FUNC_HELP_END; j++) {
const char *s = gnm_func_gettext (fd, fd->help[j].text);
for (j = 0; j < n; j++) {
const char *s = gnm_func_gettext (fd, help[j].text);
switch (fd->help[j].type) {
switch (help[j].type) {
case GNM_FUNC_HELP_EXTREF:
if (!any) {
any = TRUE;
......@@ -201,9 +202,10 @@ dump_samples (GPtrArray *defs, FILE *out)
for (ui = 0; ui < defs->len; ui++) {
GnmFunc *fd = g_ptr_array_index (defs, ui);
int j;
int j, n;
const char *last = NULL;
gboolean has_sample = FALSE;
GnmFuncHelp const *help = gnm_func_get_help (fd, &n);
if (last_group != gnm_func_get_function_group (fd)) {
last_group = gnm_func_get_function_group (fd);
......@@ -211,10 +213,10 @@ dump_samples (GPtrArray *defs, FILE *out)
fputc ('\n', out);
}
for (j = 0; fd->help[j].type != GNM_FUNC_HELP_END; j++) {
const char *s = fd->help[j].text;
for (j = 0; j < n; j++) {
const char *s = help[j].text;
if (fd->help[j].type != GNM_FUNC_HELP_EXAMPLES)
if (help[j].type != GNM_FUNC_HELP_EXAMPLES)
continue;
has_sample = TRUE;
......@@ -446,16 +448,16 @@ function_dump_defs (char const *filename, int dump_type)
GString *seealso = g_string_new (NULL);
gint min, max;
GnmFuncGroup *group = gnm_func_get_function_group (fd);
int n;
GnmFuncHelp const *help = gnm_func_get_help (fd, &n);
fprintf (output_file, "@CATEGORY=%s\n",
gnm_func_gettext (fd, group->display_name->str));
for (i = 0;
fd->help[i].type != GNM_FUNC_HELP_END;
i++) {
switch (fd->help[i].type) {
for (i = 0; i < n; i++) {
switch (help[i].type) {
case GNM_FUNC_HELP_NAME: {
char *short_desc;
char *name = split_at_colon (gnm_func_gettext (fd, fd->help[i].text), &short_desc);
char *name = split_at_colon (gnm_func_gettext (fd, help[i].text), &short_desc);
fprintf (output_file,
"@FUNCTION=%s\n",
name);
......@@ -470,21 +472,21 @@ function_dump_defs (char const *filename, int dump_type)
case GNM_FUNC_HELP_SEEALSO:
if (seealso->len > 0)
g_string_append (seealso, ",");
g_string_append (seealso, gnm_func_gettext (fd, fd->help[i].text));
g_string_append (seealso, gnm_func_gettext (fd, help[i].text));
break;
case GNM_FUNC_HELP_DESCRIPTION:
if (desc->len > 0)
g_string_append (desc, "\n");
g_string_append (desc, gnm_func_gettext (fd, fd->help[i].text));
g_string_append (desc, gnm_func_gettext (fd, help[i].text));
break;
case GNM_FUNC_HELP_NOTE:
if (note->len > 0)
g_string_append (note, " ");
g_string_append (note, gnm_func_gettext (fd, fd->help[i].text));
g_string_append (note, gnm_func_gettext (fd, help[i].text));
break;
case GNM_FUNC_HELP_ARG: {
char *argdesc;
char *name = split_at_colon (gnm_func_gettext (fd, fd->help[i].text), &argdesc);
char *name = split_at_colon (gnm_func_gettext (fd, help[i].text), &argdesc);
if (first_arg)
first_arg = FALSE;
else
......@@ -503,12 +505,12 @@ function_dump_defs (char const *filename, int dump_type)
case GNM_FUNC_HELP_ODF:
if (odf->len > 0)
g_string_append (odf, " ");
g_string_append (odf, gnm_func_gettext (fd, fd->help[i].text));
g_string_append (odf, gnm_func_gettext (fd, help[i].text));
break;
case GNM_FUNC_HELP_EXCEL:
if (excel->len > 0)
g_string_append (excel, " ");
g_string_append (excel, gnm_func_gettext (fd, fd->help[i].text));
g_string_append (excel, gnm_func_gettext (fd, help[i].text));
break;
case GNM_FUNC_HELP_EXTREF:
......@@ -975,12 +977,14 @@ gnm_func_sanity_check1 (GnmFunc *fd)
int res = 0;
size_t nlen = strlen (fd->name);
GHashTable *allargs;
int n;
GnmFuncHelp const *help = gnm_func_get_help (fd, &n);
allargs = g_hash_table_new_full
(g_str_hash, g_str_equal, (GDestroyNotify)g_free, NULL);
memset (counts, 0, sizeof (counts));
for (h = fd->help; h->type != GNM_FUNC_HELP_END; h++) {
for (h = help; n-- > 0; h++) {
g_assert (h->type <= GNM_FUNC_HELP_ODF);
counts[h->type]++;
......
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