Fixed a leak

master
Yevgen Muntyan 2006-04-18 01:47:31 -05:00
parent 4fb8afc340
commit 1176fcbb8f
5 changed files with 278 additions and 49 deletions

View File

@ -44,6 +44,7 @@ struct _MooCompletionGroup {
GCompletion *cmpl;
GList *data;
GList *tmp;
MooCompletionStringFunc string_func;
MooCompletionFreeFunc free_func;
@ -225,7 +226,7 @@ moo_completion_update (MooCompletion *cmpl)
while (list)
{
GtkTreeIter iter;
gtk_list_store_prepend (cmpl->priv->store, &iter);
gtk_list_store_append (cmpl->priv->store, &iter);
gtk_list_store_set (cmpl->priv->store, &iter, 0, list->data, -1);
list = list->next;
}
@ -286,7 +287,7 @@ moo_completion_populate (MooCompletion *cmpl,
while (list)
{
GtkTreeIter iter;
gtk_list_store_prepend (cmpl->priv->store, &iter);
gtk_list_store_append (cmpl->priv->store, &iter);
gtk_list_store_set (cmpl->priv->store, &iter, 0, list->data, -1);
list = list->next;
}
@ -392,6 +393,7 @@ moo_completion_set_doc (MooCompletion *cmpl,
gtk_text_buffer_delete_mark (cmpl->priv->buffer, cmpl->priv->start);
if (cmpl->priv->end)
gtk_text_buffer_delete_mark (cmpl->priv->buffer, cmpl->priv->end);
g_object_unref (cmpl->priv->buffer);
g_object_unref (cmpl->priv->doc);
cmpl->priv->start = cmpl->priv->end = NULL;
cmpl->priv->buffer = NULL;
@ -401,7 +403,7 @@ moo_completion_set_doc (MooCompletion *cmpl,
if (doc)
{
cmpl->priv->doc = g_object_ref (doc);
cmpl->priv->buffer = gtk_text_view_get_buffer (doc);
cmpl->priv->buffer = g_object_ref (gtk_text_view_get_buffer (doc));
}
moo_text_popup_set_doc (cmpl->priv->popup, doc);
@ -580,10 +582,6 @@ moo_completion_group_set_data (MooCompletionGroup *group,
g_list_free (group->data);
group->data = data;
if (group->cmp_func)
group->data = g_list_sort (group->data, (GCompareFunc) group->cmp_func);
g_completion_add_items (group->cmpl, group->data);
}
@ -598,12 +596,7 @@ moo_completion_group_add_data (MooCompletionGroup *group,
return;
g_completion_clear_items (group->cmpl);
group->data = g_list_concat (group->data, data);
if (group->cmp_func)
group->data = g_list_sort (group->data, (GCompareFunc) group->cmp_func);
g_completion_add_items (group->cmpl, group->data);
}
@ -652,15 +645,23 @@ moo_completion_group_complete (MooCompletionGroup *group,
char **prefix)
{
char *dummy = NULL;
GList *retval;
GList *list;
if (!prefix)
prefix = &dummy;
retval = g_completion_complete_utf8 (group->cmpl, text, prefix);
list = g_completion_complete_utf8 (group->cmpl, text, prefix);
if (group->cmp_func)
{
g_list_free (group->tmp);
group->tmp = g_list_sort (g_list_copy (list),
(GCompareFunc) group->cmp_func);
list = group->tmp;
}
g_free (dummy);
return retval;
return list;
}
@ -711,6 +712,7 @@ moo_completion_group_set_pattern (MooCompletionGroup *group,
group->n_parens = n_parens;
}
g_free (real_pattern);
return;
err:
@ -758,6 +760,7 @@ moo_completion_group_unref (MooCompletionGroup *group)
if (group->free_func)
g_list_foreach (group->data, (GFunc) group->free_func, NULL);
g_list_free (group->data);
g_list_free (group->tmp);
g_free (group);
}

View File

@ -422,7 +422,7 @@ moo_text_popup_resize (MooTextPopup *popup)
moo_text_popup_get_position (popup, &iter);
gtk_text_view_get_iter_location (popup->priv->doc, &iter, &iter_rect);
gtk_text_view_buffer_to_window_coords (popup->priv->doc, GTK_TEXT_WINDOW_TEXT,
gtk_text_view_buffer_to_window_coords (popup->priv->doc, GTK_TEXT_WINDOW_WIDGET,
iter_rect.x, iter_rect.y,
&iter_rect.x, &iter_rect.y);
gdk_window_get_origin (widget->window, &x, &y);
@ -502,6 +502,7 @@ moo_text_popup_set_doc (MooTextPopup *popup,
popup->priv->pos = NULL;
}
g_object_unref (popup->priv->buffer);
g_object_unref (popup->priv->doc);
popup->priv->doc = NULL;
popup->priv->buffer = NULL;
@ -510,7 +511,7 @@ moo_text_popup_set_doc (MooTextPopup *popup,
if (doc)
{
popup->priv->doc = g_object_ref (doc);
popup->priv->buffer = gtk_text_view_get_buffer (doc);
popup->priv->buffer = g_object_ref (gtk_text_view_get_buffer (doc));
}
g_object_notify (G_OBJECT (popup), "doc");

View File

@ -14,13 +14,19 @@
#include "completion.h"
#include "mooedit/moocompletion.h"
#include "mooutils/mooutils-misc.h"
#include "mooutils/mooconfig.h"
#include <sys/stat.h>
#include <errno.h>
#include <string.h>
typedef enum {
DATA_FILE_SIMPLE,
DATA_FILE_CONFIG
} DataFileType;
typedef struct {
char *path;
DataFileType type;
time_t mtime;
MooCompletion *cmpl;
} CmplData;
@ -49,13 +55,52 @@ _completion_callback (MooEditWindow *window)
}
static GList *
parse_words (const char *string,
const char *prefix,
const char *path)
{
GList *list = NULL;
char **words, **p;
g_return_val_if_fail (string != NULL, NULL);
words = g_strsplit_set (string, " \t\r\n", 0);
for (p = words; p && **p; ++p)
{
if (p[0][0] && p[0][1])
{
if (!g_utf8_validate (*p, -1, NULL))
{
g_critical ("%s: invalid utf8 in '%s'",
G_STRLOC, path);
}
else if (prefix)
{
list = g_list_prepend (list, g_strdup_printf ("%s%s", prefix, *p));
}
else
{
list = g_list_prepend (list, *p);
*p = NULL;
}
}
g_free (*p);
}
g_free (words);
return g_list_reverse (list);
}
static void
cmpl_data_read_file (CmplData *data)
cmpl_data_read_simple_file (CmplData *data)
{
GError *error = NULL;
GList *list;
char *contents;
char **words, **p;
GList *list = NULL;
g_return_if_fail (data->cmpl == NULL);
g_return_if_fail (data->path != NULL);
@ -70,32 +115,201 @@ cmpl_data_read_file (CmplData *data)
return;
}
words = g_strsplit_set (contents, " \t\r\n", 0);
for (p = words; p && **p; ++p)
{
if (p[0][0] && p[0][1])
{
if (!g_utf8_validate (*p, -1, NULL))
{
g_critical ("%s: invalid utf8 in '%s'",
G_STRLOC, data->path);
}
else
{
list = g_list_prepend (list, *p);
*p = NULL;
}
}
g_free (*p);
}
list = parse_words (contents, NULL, data->path);
data->cmpl = moo_completion_new_text (list, TRUE);
g_message ("read %d words from %s", g_list_length (list), data->path);
g_free (contents);
g_free (words);
}
static void
text_cell_data_func (G_GNUC_UNUSED GtkTreeViewColumn *tree_column,
GtkCellRenderer *cell,
GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
gpointer data = NULL;
gtk_tree_model_get (tree_model, iter, 0, &data, -1);
g_return_if_fail (data != NULL);
g_object_set (cell, "text", data, NULL);
}
static guint *
parse_numbers (const char *string,
guint *n_numbers_p)
{
guint *numbers;
guint n_numbers, i;
char **pieces, **p;
GSList *list = NULL;
g_return_val_if_fail (string != NULL, NULL);
pieces = g_strsplit_set (string, " \t,;:", 0);
g_return_val_if_fail (pieces != NULL, NULL);
for (p = pieces; p && *p; ++p)
{
if (**p)
{
guint64 n64;
guint n;
errno = 0;
n64 = g_ascii_strtoull (*p, NULL, 10);
if (errno || n64 > 10000)
{
g_warning ("%s: could not parse number '%s'", G_STRLOC, *p);
goto error;
}
n = n64;
list = g_slist_prepend (list, GUINT_TO_POINTER (n));
}
}
list = g_slist_reverse (list);
n_numbers = g_slist_length (list);
numbers = g_new (guint, n_numbers);
for (i = 0; i < n_numbers; ++i)
{
numbers[i] = GPOINTER_TO_UINT (list->data);
list = g_slist_delete_link (list, list);
}
if (n_numbers_p)
*n_numbers_p = n_numbers;
g_strfreev (pieces);
return numbers;
error:
g_strfreev (pieces);
g_slist_free (list);
return NULL;
}
static void
cmpl_data_read_config_file (CmplData *data)
{
MooConfig *config;
guint i, n_items;
GSList *completion_groups = NULL;
GtkCellRenderer *cell;
MooTextPopup *popup;
g_return_if_fail (data->cmpl == NULL);
g_return_if_fail (data->path != NULL);
config = moo_config_parse_file (data->path);
g_return_if_fail (config != NULL);
n_items = moo_config_n_items (config);
g_return_if_fail (n_items != 0);
for (i = 0; i < n_items; ++i)
{
MooConfigItem *item;
const char *pattern, *prefix;
const char *groups;
guint *parens;
guint n_parens;
GList *words;
MooCompletionGroup *group;
item = moo_config_nth_item (config, i);
pattern = moo_config_item_get_value (item, "pattern");
prefix = moo_config_item_get_value (item, "prefix");
groups = moo_config_item_get_value (item, "group");
groups = groups ? groups : moo_config_item_get_value (item, "groups");
groups = groups ? groups : "0";
if (!pattern)
{
g_warning ("%s: pattern missing", G_STRLOC);
continue;
}
parens = parse_numbers (groups, &n_parens);
if (!parens)
{
g_warning ("%s: invalid group string '%s'", G_STRLOC, groups);
continue;
}
words = parse_words (moo_config_item_get_content (item),
prefix, data->path);
if (!words)
{
g_warning ("%s: empty group", G_STRLOC);
g_free (parens);
continue;
}
g_message ("read %d words for patttern '%s' from %s",
g_list_length (words), pattern, data->path);
group = moo_completion_group_new_text (TRUE);
moo_completion_group_add_data (group, words);
moo_completion_group_set_pattern (group, pattern, parens, n_parens);
g_free (parens);
completion_groups = g_slist_prepend (completion_groups, group);
}
moo_config_free (config);
if (!completion_groups)
{
g_warning ("%s: no completions", G_STRLOC);
data->cmpl = moo_completion_new_text (NULL, TRUE);
return;
}
completion_groups = g_slist_reverse (completion_groups);
data->cmpl = moo_completion_new ();
while (completion_groups)
{
moo_completion_add_group (data->cmpl, completion_groups->data);
moo_completion_group_unref (completion_groups->data);
completion_groups = g_slist_delete_link (completion_groups,
completion_groups);
}
popup = moo_completion_get_popup (data->cmpl);
cell = gtk_cell_renderer_text_new ();
gtk_tree_view_column_pack_start (popup->column, cell, TRUE);
gtk_tree_view_column_set_cell_data_func (popup->column, cell,
(GtkTreeCellDataFunc) text_cell_data_func,
NULL, NULL);
}
static void
cmpl_data_read_file (CmplData *data)
{
g_return_if_fail (data->path != NULL);
g_return_if_fail (data->cmpl == NULL);
switch (data->type)
{
case DATA_FILE_SIMPLE:
return cmpl_data_read_simple_file (data);
case DATA_FILE_CONFIG:
return cmpl_data_read_config_file (data);
}
g_return_if_reached ();
}
@ -152,9 +366,10 @@ cmpl_data_free (CmplData *data)
static void
cmpl_plugin_check_file (CmplPlugin *plugin,
const char *path,
const char *id)
cmpl_plugin_check_file (CmplPlugin *plugin,
const char *path,
DataFileType type,
const char *id)
{
struct stat buf;
CmplData *data;
@ -192,6 +407,7 @@ cmpl_plugin_check_file (CmplPlugin *plugin,
}
data->path = g_strdup (path);
data->type = type;
data->mtime = buf.st_mtime;
g_message ("found file '%s' for lang '%s'", path, id);
}
@ -211,18 +427,25 @@ cmpl_plugin_load_dir (CmplPlugin *plugin,
{
char *file, *name, *id;
guint base_len;
DataFileType type;
base_len = strlen (base);
if (base_len <= strlen (CMPL_FILE_SUFFIX) ||
!g_str_has_suffix (base, CMPL_FILE_SUFFIX))
continue;
if (base_len <= strlen (CMPL_FILE_SUFFIX))
continue;
if (g_str_has_suffix (base, CMPL_FILE_SUFFIX))
type = DATA_FILE_SIMPLE;
else if (g_str_has_suffix (base, CMPL_CONFIG_SUFFIX))
type = DATA_FILE_CONFIG;
else
continue;
name = g_strndup (base, base_len - strlen (CMPL_FILE_SUFFIX));
id = moo_lang_id_from_name (name);
file = g_build_filename (path, base, NULL);
cmpl_plugin_check_file (plugin, file, id);
cmpl_plugin_check_file (plugin, file, type, id);
g_free (name);
g_free (id);

View File

@ -24,6 +24,7 @@ G_BEGIN_DECLS
#define CMPL_DIR "completion"
#define CMPL_FILE_NONE "none"
#define CMPL_FILE_SUFFIX ".lst"
#define CMPL_CONFIG_SUFFIX ".cfg"
typedef struct {

View File

@ -721,6 +721,7 @@ moo_command_type_parse (const char *string)
else if (!strcmp (norm, "python"))
cmd_type = MOO_COMMAND_PYTHON;
g_free (norm);
return cmd_type;
}