[gnome-builder/wip/slaf/xml-pack: 11/11] xml-pack: get completion items
- From: Sébastien Lafargue <slafargue src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-builder/wip/slaf/xml-pack: 11/11] xml-pack: get completion items
- Date: Tue, 27 Jun 2017 21:53:09 +0000 (UTC)
commit abd420517d513c23251b56402419a10c5e09527c
Author: Sebastien Lafargue <slafargue gnome org>
Date: Tue Jun 27 23:50:09 2017 +0200
xml-pack: get completion items
plugins/xml-pack/ide-xml-completion-provider.c | 623 ++++++++++++++++++++++--
plugins/xml-pack/ide-xml-parser-generic.c | 2 +-
plugins/xml-pack/ide-xml-path.c | 2 +-
plugins/xml-pack/ide-xml-service.c | 89 +++-
plugins/xml-pack/ide-xml-symbol-node.c | 1 -
5 files changed, 663 insertions(+), 54 deletions(-)
---
diff --git a/plugins/xml-pack/ide-xml-completion-provider.c b/plugins/xml-pack/ide-xml-completion-provider.c
index 59d96aa..7356688 100644
--- a/plugins/xml-pack/ide-xml-completion-provider.c
+++ b/plugins/xml-pack/ide-xml-completion-provider.c
@@ -33,7 +33,48 @@ struct _IdeXmlCompletionProvider
IdeObject parent_instance;
};
-static void completion_provider_init (GtkSourceCompletionProviderIface *);
+typedef struct _MatchingState
+{
+ GArray *stack;
+ IdeXmlSymbolNode *parent_node;
+ IdeXmlSymbolNode *candidate_node;
+ IdeXmlPosition *position;
+ IdeXmlRngDefine *define;
+ GPtrArray *children;
+ GPtrArray *items;
+ const gchar *prefix;
+ gint child_cursor;
+ gint define_cursor;
+
+ guint is_initial_state : 1;
+ guint retry : 1;
+} MatchingState;
+
+typedef struct _StateStackItem
+{
+ GPtrArray *children;
+ IdeXmlSymbolNode *candidate_node;
+} StateStackItem;
+
+typedef struct
+{
+ IdeXmlCompletionProvider *self;
+ GtkSourceCompletionContext *completion_context;
+ IdeFile *ifile;
+ IdeBuffer *buffer;
+ gint line;
+ gint line_offset;
+} PopulateState;
+
+typedef struct _CompletionItem
+{
+ gchar *label;
+ gchar *content;
+} CompletionItem;
+
+static void completion_provider_init (GtkSourceCompletionProviderIface *);
+static gboolean process_matching_state (MatchingState *state,
+ IdeXmlRngDefine *define);
G_DEFINE_DYNAMIC_TYPE_EXTENDED (IdeXmlCompletionProvider,
ide_xml_completion_provider,
@@ -49,16 +90,6 @@ enum {
static GParamSpec *properties [N_PROPS];
-typedef struct
-{
- IdeXmlCompletionProvider *self;
- GtkSourceCompletionContext *completion_context;
- IdeFile *ifile;
- IdeBuffer *buffer;
- gint line;
- gint line_offset;
-} PopulateState;
-
static void
populate_state_free (PopulateState *state)
{
@@ -70,6 +101,112 @@ populate_state_free (PopulateState *state)
g_object_unref (state->buffer);
}
+static GPtrArray *
+copy_children (GPtrArray *children)
+{
+ GPtrArray *copy;
+
+ g_assert (children != NULL);
+
+ copy = g_ptr_array_new ();
+ for (gint i = 0; i < children->len; ++i)
+ g_ptr_array_add (copy, g_ptr_array_index (children, i));
+
+ return copy;
+}
+
+static void
+state_stack_item_free (gpointer *data)
+{
+ StateStackItem *item;
+
+ g_assert (data != NULL);
+
+ item = (StateStackItem *)data;
+ g_ptr_array_unref (item->children);
+}
+
+static GArray *
+state_stack_new (void)
+{
+ GArray *stack;
+
+ stack = g_array_new (FALSE, TRUE, sizeof (StateStackItem));
+ g_array_set_clear_func (stack, (GDestroyNotify)state_stack_item_free);
+
+ return stack;
+}
+
+static void
+state_stack_push (MatchingState *state)
+{
+ StateStackItem item;
+
+ g_assert (state->stack != NULL);
+
+ item.children = copy_children (state->children);
+ item.candidate_node = state->candidate_node;
+
+ g_array_append_val (state->stack, item);
+}
+
+static gboolean
+state_stack_pop (MatchingState *state)
+{
+ StateStackItem *item;
+ guint len;
+
+ g_assert (state->stack != NULL);
+
+ len = state->stack->len;
+ if (len == 0)
+ return FALSE;
+
+ item = &g_array_index (state->stack, StateStackItem, len - 1);
+ g_clear_pointer (&state->children, g_ptr_array_unref);
+
+ state->children = item->children;
+ state->candidate_node = item->candidate_node;
+
+ g_array_remove_index (state->stack, len - 1);
+ return TRUE;
+}
+
+static gboolean
+state_stack_drop (MatchingState *state)
+{
+ guint len;
+
+ g_assert (state->stack != NULL);
+
+ len = state->stack->len;
+ if (len == 0)
+ return FALSE;
+
+ g_array_remove_index (state->stack, len - 1);
+ return TRUE;
+}
+
+static gboolean
+state_stack_copy (MatchingState *state)
+{
+ StateStackItem *item;
+ guint len;
+
+ g_assert (state->stack != NULL);
+
+ len = state->stack->len;
+ if (len == 0)
+ return FALSE;
+
+ item = &g_array_index (state->stack, StateStackItem, len - 1);
+ state->children = copy_children (item->children);
+ state->candidate_node = item->candidate_node;
+
+ g_array_remove_index (state->stack, len - 1);
+ return TRUE;
+}
+
static IdeXmlPath *
get_path (IdeXmlSymbolNode *node,
IdeXmlSymbolNode *root_node)
@@ -226,6 +363,402 @@ get_matching_candidates (IdeXmlCompletionProvider *self,
return candidates;
}
+static CompletionItem *
+completion_item_new (const gchar *label,
+ const gchar *content)
+{
+ CompletionItem *item;
+
+ g_assert (!ide_str_empty0 (label));
+ g_assert (!ide_str_empty0 (content));
+
+ item = g_slice_new0 (CompletionItem);
+
+ item->label = g_strdup (label);
+ item->content = g_strdup (content);
+
+ return item;
+}
+
+static void
+completion_item_free (CompletionItem *item)
+{
+ g_clear_pointer (&item->label, g_free);
+ g_clear_pointer (&item->content, g_free);
+}
+
+static MatchingState *
+matching_state_new (IdeXmlPosition *position,
+ IdeXmlRngDefine *define,
+ GPtrArray *items)
+{
+ MatchingState *state;
+ const gchar *prefix;
+
+ g_assert (IDE_IS_XML_SYMBOL_NODE (position->node));
+ g_assert (define != NULL);
+
+ state = g_slice_new0 (MatchingState);
+
+ state->parent_node = NULL;
+ state->position = position;
+ state->define = define;
+ state->items = items;
+ state->candidate_node = ide_xml_position_get_child_node (position);
+
+ state->children = g_ptr_array_new ();
+ state->stack = state_stack_new ();
+
+ prefix = ide_xml_position_get_prefix (position);
+ state->prefix = (prefix != NULL) ? g_strdup (prefix) : NULL;
+
+ return state;
+}
+
+static MatchingState *
+matching_state_copy (MatchingState *state)
+{
+ MatchingState *new_state;
+
+ new_state = g_slice_new0 (MatchingState);
+
+ new_state->parent_node = (state->parent_node != NULL) ? g_object_ref (state->parent_node) : NULL;
+ new_state->candidate_node = (state->candidate_node != NULL) ? g_object_ref (state->candidate_node) : NULL;
+ new_state->position = state->position;
+
+ new_state->define = state->define;
+ new_state->define_cursor = state->define_cursor;
+
+ new_state->child_cursor = state->child_cursor;
+
+ new_state->prefix = (state->prefix != NULL) ? g_strdup (state->prefix) : NULL;
+ new_state->items = state->items;
+
+ if (state->children != NULL)
+ {
+ new_state->children = g_ptr_array_new ();
+ for (gint i = 0; i < state->children->len; ++i)
+ g_ptr_array_add (new_state->children, g_ptr_array_index (state->children, i));
+ }
+
+ new_state->items = state->items;
+
+ return new_state;
+}
+
+static void
+matching_state_free (MatchingState *state)
+{
+ g_clear_object (&state->parent_node);
+ g_clear_object (&state->candidate_node);
+
+ g_clear_pointer (&state->prefix, g_free);
+ g_clear_pointer (&state->children, g_ptr_array_unref);
+ g_clear_pointer (&state->stack, g_array_unref);
+}
+
+static MatchingState *
+create_initial_matching_state (IdeXmlPosition *position,
+ IdeXmlRngDefine *define,
+ GPtrArray *items)
+{
+ MatchingState *state;
+ IdeXmlSymbolNode *node, *pos_node, *candidate_node;
+ guint nb_nodes;
+ gint child_pos;
+
+ g_assert (define != NULL);
+ g_assert (items != NULL);
+
+ state = matching_state_new (position, define, items);
+ child_pos = ide_xml_position_get_child_pos (position);
+
+ candidate_node = ide_xml_position_get_child_node (position);
+ pos_node = ide_xml_position_get_node (position);
+ g_assert (IDE_IS_XML_SYMBOL_NODE (pos_node));
+
+ nb_nodes = ide_xml_symbol_node_get_n_direct_children (pos_node);
+ for (gint i = 0; i < nb_nodes; ++i)
+ {
+ /* Inject a fake node at child_pos */
+ if (child_pos == i)
+ g_ptr_array_add (state->children, candidate_node);
+
+ node = (IdeXmlSymbolNode *)ide_xml_symbol_node_get_nth_direct_child (pos_node, i);
+ g_ptr_array_add (state->children, node);
+ }
+
+ state->candidate_node = g_object_ref (candidate_node);
+ state->is_initial_state = TRUE;
+ return state;
+}
+
+static gboolean
+is_define_equal_node (IdeXmlRngDefine *define,
+ IdeXmlSymbolNode *node)
+{
+ g_assert (define != NULL);
+ g_assert (IDE_IS_XML_SYMBOL_NODE (node));
+
+ return ide_str_equal0 (ide_xml_symbol_node_get_element_name (node), define->name);
+}
+
+static gboolean
+is_element_matching (MatchingState *state)
+{
+ IdeXmlSymbolNode *node;
+ CompletionItem *item;
+ const gchar *name;
+
+ g_assert (state->define->type == IDE_XML_RNG_DEFINE_ELEMENT);
+
+ /* XXX: we skip element without a name for now */
+ if (ide_str_empty0 ((gchar *)state->define->name))
+ return FALSE;
+
+ if (state->children->len == 0)
+ return FALSE;
+
+ state->retry = FALSE;
+ node = g_ptr_array_index (state->children, 0);
+
+ if (state->candidate_node == node)
+ {
+ name = (gchar *)state->define->name;
+ if (ide_str_empty0 (state->prefix) || g_str_has_prefix ((gchar *)state->define->name, state->prefix))
+ {
+ state->candidate_node = NULL;
+ state->retry = TRUE;
+
+ item = completion_item_new (name, name);
+ g_ptr_array_add (state->items, item);
+
+ return TRUE;
+ }
+ else
+ return FALSE;
+ }
+ else if (is_define_equal_node (state->define, node))
+ {
+ g_ptr_array_remove_index (state->children, 0);
+ return TRUE;
+ }
+ else
+ return FALSE;
+}
+
+static gboolean
+is_choice_matching (MatchingState *state)
+{
+ IdeXmlRngDefine *defines;
+
+ g_assert (state->define->type == IDE_XML_RNG_DEFINE_CHOICE);
+
+ if (NULL == (defines = state->define->content))
+ return TRUE;
+
+ state_stack_push (state);
+
+ while (defines != NULL)
+ {
+ if (process_matching_state (state, defines))
+ {
+ if (state->retry)
+ {
+ state->retry = FALSE;
+ }
+ else
+ {
+ state_stack_drop (state);
+ return TRUE;
+ }
+ }
+
+ if (NULL != (defines = defines->next))
+ {
+ state_stack_copy (state);
+ }
+ else
+ {
+ state_stack_pop (state);
+ }
+ }
+
+ state->retry = FALSE;
+ return FALSE;
+}
+
+static gboolean
+is_n_matching (MatchingState *state)
+{
+ IdeXmlRngDefine *defines;
+ IdeXmlRngDefineType type = state->define->type;
+ gboolean is_child_matching;
+ gboolean is_matching = FALSE;
+
+ g_assert (type == IDE_XML_RNG_DEFINE_ZEROORMORE ||
+ type == IDE_XML_RNG_DEFINE_ONEORMORE ||
+ type == IDE_XML_RNG_DEFINE_OPTIONAL);
+
+ /* Only ZeroOrMore or optionnal match if there's no children */
+ if (NULL == (defines = state->define->content))
+ return !(type == IDE_XML_RNG_DEFINE_ONEORMORE);
+
+ state_stack_push (state);
+
+loop:
+ is_child_matching = TRUE;
+ while (defines != NULL)
+ {
+ if (!process_matching_state (state, defines))
+ {
+ is_child_matching = FALSE;
+ break;
+ }
+
+ defines = defines->next;
+ }
+
+ if (is_child_matching)
+ {
+ is_matching = TRUE;
+ state_stack_drop (state);
+ if ((type == IDE_XML_RNG_DEFINE_ONEORMORE || type == IDE_XML_RNG_DEFINE_ZEROORMORE) &&
+ state->candidate_node != NULL)
+ {
+ state_stack_push (state);
+ goto loop;
+ }
+ }
+ else
+ {
+ state_stack_pop (state);
+ }
+
+ state->retry = FALSE;
+ if (type == IDE_XML_RNG_DEFINE_OPTIONAL || type == IDE_XML_RNG_DEFINE_ZEROORMORE)
+ return TRUE;
+
+ return is_matching;
+}
+
+static gboolean
+is_group_matching (MatchingState *state)
+{
+ IdeXmlRngDefine *defines;
+ gboolean is_matching = TRUE;
+
+ g_assert (state->define->type == IDE_XML_RNG_DEFINE_GROUP ||
+ state->define->type == IDE_XML_RNG_DEFINE_ELEMENT);
+
+ if (NULL == (defines = state->define->content))
+ return TRUE;
+
+ state_stack_push (state);
+ while (defines != NULL)
+ {
+ if (!process_matching_state (state, defines))
+ {
+ is_matching = FALSE;
+ break;
+ }
+
+ if (NULL != (defines = defines->next))
+ {
+ state_stack_drop (state);
+ state_stack_push (state);
+ }
+ }
+
+ state->retry = FALSE;
+ if (is_matching)
+ {
+ state_stack_drop (state);
+ return TRUE;
+ }
+
+ return is_matching;
+}
+
+static gboolean
+process_matching_state (MatchingState *state,
+ IdeXmlRngDefine *define)
+{
+ IdeXmlRngDefine *old_define;
+ IdeXmlRngDefineType type;
+ gboolean is_matching = FALSE;
+
+ g_assert (state != NULL);
+ g_assert (define != NULL);
+
+ if (state->candidate_node == NULL)
+ return TRUE;
+
+ old_define = state->define;
+ state->define = define;
+
+ if (state->is_initial_state)
+ {
+ state->is_initial_state = FALSE;
+ type = IDE_XML_RNG_DEFINE_GROUP;
+ }
+ else
+ type = define->type;
+
+ switch (type)
+ {
+ case IDE_XML_RNG_DEFINE_ELEMENT:
+ is_matching = is_element_matching (state);
+ break;
+
+ case IDE_XML_RNG_DEFINE_NOOP:
+ case IDE_XML_RNG_DEFINE_NOTALLOWED:
+ case IDE_XML_RNG_DEFINE_TEXT:
+ case IDE_XML_RNG_DEFINE_DATATYPE:
+ case IDE_XML_RNG_DEFINE_VALUE:
+ case IDE_XML_RNG_DEFINE_EMPTY:
+ case IDE_XML_RNG_DEFINE_ATTRIBUTE:
+ case IDE_XML_RNG_DEFINE_START:
+ case IDE_XML_RNG_DEFINE_PARAM:
+ case IDE_XML_RNG_DEFINE_EXCEPT:
+ case IDE_XML_RNG_DEFINE_LIST:
+ is_matching = FALSE;
+ break;
+
+ case IDE_XML_RNG_DEFINE_DEFINE:
+ case IDE_XML_RNG_DEFINE_REF:
+ case IDE_XML_RNG_DEFINE_PARENTREF:
+ case IDE_XML_RNG_DEFINE_EXTERNALREF:
+ is_matching = process_matching_state (state, define->content);
+ break;
+
+ case IDE_XML_RNG_DEFINE_ZEROORMORE:
+ case IDE_XML_RNG_DEFINE_ONEORMORE:
+ case IDE_XML_RNG_DEFINE_OPTIONAL:
+ is_matching = is_n_matching (state);
+ break;
+
+ case IDE_XML_RNG_DEFINE_CHOICE:
+ is_matching = is_choice_matching (state);
+ break;
+
+ case IDE_XML_RNG_DEFINE_INTERLEAVE:
+ is_matching = FALSE;
+ break;
+
+ case IDE_XML_RNG_DEFINE_GROUP:
+ is_matching = is_group_matching (state);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ state->define = old_define;
+
+ return is_matching;
+}
+
static void
populate_cb (GObject *object,
GAsyncResult *result,
@@ -235,17 +768,21 @@ populate_cb (GObject *object,
PopulateState *state = (PopulateState *)user_data;
IdeXmlCompletionProvider *self = state->self;
g_autoptr (IdeXmlPosition) position = NULL;
- IdeXmlSymbolNode *root_node, *node;
+ IdeXmlSymbolNode *root_node, *node, *candidate_node;
IdeXmlAnalysis *analysis;
IdeXmlPositionKind kind;
+ IdeXmlPositionDetail detail;
g_autoptr (IdeXmlPath) path = NULL;
GtkSourceCompletionItem *item;
- g_autofree gchar *text = NULL;
- g_autofree gchar *label = NULL;
g_autoptr (GList) results = NULL;
GPtrArray *schemas;
g_autoptr (GPtrArray) candidates = NULL;
+ IdeXmlRngDefine *def;
+ MatchingState *initial_state;
+ g_autoptr (GPtrArray) items = NULL;
+ CompletionItem *completion_item;
GError *error = NULL;
+ gint child_pos;
g_assert (IDE_IS_XML_COMPLETION_PROVIDER (self));
g_assert (IDE_IS_XML_SERVICE (service));
@@ -256,29 +793,57 @@ populate_cb (GObject *object,
root_node = ide_xml_analysis_get_root_node (analysis);
node = ide_xml_position_get_node (position);
kind = ide_xml_position_get_kind (position);
+ detail = ide_xml_position_get_detail (position);
+ child_pos = ide_xml_position_get_child_pos (position);
+ }
path = get_path (node, root_node);
- if (schemas != NULL)
- candidates = get_matching_candidates (self, schemas, path);
+ if (schemas == NULL)
+ goto cleanup;
+
+ candidates = get_matching_candidates (self, schemas, path);
+ if (candidates != NULL)
+ {
+
+ if (child_pos != -1)
+ {
+ candidate_node = ide_xml_symbol_node_new ("internal", NULL, "", IDE_SYMBOL_XML_ELEMENT);
+ ide_xml_position_set_child_node (position, candidate_node);
+ }
+
+ items = g_ptr_array_new_with_free_func ((GDestroyNotify)completion_item_free);
+ for (gint i = 0; i < candidates->len; ++i)
+ {
+ def = g_ptr_array_index (candidates, i);
+ ide_xml_rng_define_dump_tree (def, FALSE);
+
+ initial_state = create_initial_matching_state (position, def, items);
+ process_matching_state (initial_state, def);
+ matching_state_free (initial_state);
- text = g_strdup ("xml item text");
- label = g_strdup ("xml item label");
- item = g_object_new (GTK_SOURCE_TYPE_COMPLETION_ITEM,
- "text", text,
- "label", label,
- NULL);
+ printf ("----------\n");
+ }
- ide_xml_position_print (position);
- ide_xml_path_dump (path);
+ for (gint j = 0; j < items->len; ++j)
+ {
+ completion_item = g_ptr_array_index (items, j);
+ item = g_object_new (GTK_SOURCE_TYPE_COMPLETION_ITEM,
+ "text", completion_item->content,
+ "label", completion_item->label,
+ NULL);
- results = g_list_prepend (results, item);
- gtk_source_completion_context_add_proposals (state->completion_context,
- GTK_SOURCE_COMPLETION_PROVIDER (self),
- results,
- TRUE);
+ results = g_list_prepend (results, item);
+ }
+
+ gtk_source_completion_context_add_proposals (state->completion_context,
+ GTK_SOURCE_COMPLETION_PROVIDER (self),
+ results,
+ TRUE);
+ }
+cleanup:
populate_state_free (state);
}
diff --git a/plugins/xml-pack/ide-xml-parser-generic.c b/plugins/xml-pack/ide-xml-parser-generic.c
index 0d6d307..b2d75b9 100644
--- a/plugins/xml-pack/ide-xml-parser-generic.c
+++ b/plugins/xml-pack/ide-xml-parser-generic.c
@@ -67,7 +67,7 @@ ide_xml_parser_generic_start_element_sax_cb (ParserState *state,
attr = collect_attributes (self, (const gchar **)attributes);
label = g_strconcat ((const gchar *)name, attr, NULL);
- node = ide_xml_symbol_node_new (label, NULL, NULL, IDE_SYMBOL_XML_ELEMENT);
+ node = ide_xml_symbol_node_new (label, NULL, (gchar *)name, IDE_SYMBOL_XML_ELEMENT);
g_object_set (node, "use-markup", TRUE, NULL);
state->attributes = (const gchar **)attributes;
diff --git a/plugins/xml-pack/ide-xml-path.c b/plugins/xml-pack/ide-xml-path.c
index e220d48..63bb167 100644
--- a/plugins/xml-pack/ide-xml-path.c
+++ b/plugins/xml-pack/ide-xml-path.c
@@ -50,7 +50,7 @@ ide_xml_path_dump (IdeXmlPath *self)
for (gint i = 0; i < self->nodes->len; ++i)
{
node = g_ptr_array_index (self->nodes, i);
- ide_xml_symbol_node_print (node, TRUE, TRUE);
+ ide_xml_symbol_node_print (node, 0, FALSE, TRUE, TRUE);
}
}
diff --git a/plugins/xml-pack/ide-xml-service.c b/plugins/xml-pack/ide-xml-service.c
index 50b3def..631fc0f 100644
--- a/plugins/xml-pack/ide-xml-service.c
+++ b/plugins/xml-pack/ide-xml-service.c
@@ -629,24 +629,30 @@ position_state_free (PositionState *state)
static IdeXmlPosition *
get_position (IdeXmlService *self,
IdeXmlAnalysis *analysis,
+ GtkTextBuffer *buffer,
gint line,
gint line_offset)
{
IdeXmlPosition *position;
IdeXmlSymbolNode *root_node;
- IdeXmlSymbolNodeRelativePosition rel_pos;
- IdeXmlPositionKind candidate_kind;
- IdeXmlSymbolNode *current_node;
- IdeXmlSymbolNode *child_node;
- IdeXmlSymbolNode *candidate_node;
+ IdeXmlSymbolNode *current_node, *child_node, *candidate_node;
+ IdeXmlSymbolNode *previous_node = NULL;
IdeXmlSymbolNode *previous_sibling_node = NULL;
IdeXmlSymbolNode *next_sibling_node = NULL;
+ IdeXmlSymbolNodeRelativePosition rel_pos;
+ IdeXmlPositionKind candidate_kind;
+ IdeXmlPositionDetail detail = IDE_XML_POSITION_DETAIL_NONE;
+ g_autofree gchar *prefix = NULL;
+ GtkTextIter start, end;
+ gint start_line, start_line_offset;
guint n_children;
gint child_pos = -1;
gint n = 0;
+ gboolean has_prefix = FALSE;
g_assert (IDE_IS_XML_SERVICE (self));
g_assert (analysis != NULL);
+ g_assert (GTK_IS_TEXT_BUFFER (buffer));
current_node = root_node = ide_xml_analysis_get_root_node (analysis);
while (TRUE)
@@ -658,6 +664,7 @@ loop:
for (n = 0; n < n_children; ++n)
{
child_node = IDE_XML_SYMBOL_NODE (ide_xml_symbol_node_get_nth_direct_child (current_node, n));
+ child_pos = n;
rel_pos = ide_xml_symbol_node_compare_location (child_node, line, line_offset);
printf ("node:%s rel pos:%d\n", ide_xml_symbol_node_get_element_name (child_node), rel_pos);
switch (rel_pos)
@@ -665,34 +672,37 @@ loop:
case IDE_XML_SYMBOL_NODE_RELATIVE_POSITION_IN_START_TAG:
candidate_node = child_node;
candidate_kind = IDE_XML_POSITION_KIND_IN_START_TAG;
+ detail = IDE_XML_POSITION_DETAIL_IN_NAME;
+ has_prefix = TRUE;
goto result;
case IDE_XML_SYMBOL_NODE_RELATIVE_POSITION_IN_END_TAG:
candidate_node = child_node;
candidate_kind = IDE_XML_POSITION_KIND_IN_END_TAG;
+ detail = IDE_XML_POSITION_DETAIL_IN_NAME;
+ has_prefix = TRUE;
goto result;
case IDE_XML_SYMBOL_NODE_RELATIVE_POSITION_BEFORE:
- child_pos = n;
candidate_node = current_node;
candidate_kind = IDE_XML_POSITION_KIND_IN_CONTENT;
goto result;
case IDE_XML_SYMBOL_NODE_RELATIVE_POSITION_AFTER:
+ previous_node = child_node;
+
if (n == (n_children - 1))
{
- child_pos = (n_children + 1);
+ child_pos = n_children;
candidate_node = current_node;
candidate_kind = IDE_XML_POSITION_KIND_IN_CONTENT;
goto result;
}
- else
- continue;
break;
case IDE_XML_SYMBOL_NODE_RELATIVE_POSITION_IN_CONTENT:
- current_node = child_node;
+ current_node = previous_node = child_node;
goto loop;
case IDE_XML_POSITION_KIND_UNKNOW:
@@ -709,25 +719,60 @@ result:
candidate_node = root_node;
candidate_kind = IDE_XML_POSITION_KIND_IN_CONTENT;
}
+ else if (candidate_kind == IDE_XML_POSITION_KIND_IN_CONTENT &&
+ previous_node != NULL &&
+ ide_xml_symbol_node_get_state (previous_node) == IDE_XML_SYMBOL_NODE_STATE_NOT_CLOSED)
+ {
+ candidate_node = previous_node;
+ /* TODO: fetch detail and more infos */
+ /* TODO: detect the IN_END_TAG case */
+ candidate_kind = IDE_XML_POSITION_KIND_IN_START_TAG;
+ detail = IDE_XML_POSITION_DETAIL_IN_NAME;
+ has_prefix = TRUE;
+ }
+
+ if (has_prefix)
+ {
+ ide_xml_symbol_node_get_location (candidate_node, &start_line, &start_line_offset, NULL, NULL, NULL);
+ gtk_text_buffer_get_iter_at_line_index (buffer, &start, start_line - 1, start_line_offset - 1);
+ gtk_text_buffer_get_iter_at_line_index (buffer, &end, line - 1, line_offset - 1);
- position = ide_xml_position_new (candidate_node, candidate_kind);
- ide_xml_position_set_analysis (position, analysis);
+ if (gtk_text_iter_get_char (&start) == '<')
+ gtk_text_iter_forward_char (&start);
+
+ if (!gtk_text_iter_equal (&start, &end))
+ prefix = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
+ }
if (candidate_kind == IDE_XML_POSITION_KIND_IN_CONTENT)
{
- if (child_pos > 0)
- {
- previous_sibling_node = IDE_XML_SYMBOL_NODE (ide_xml_symbol_node_get_nth_direct_child
(candidate_node, child_pos - 1));
- printf ("previous sibling:%p at %d\n", previous_sibling_node, child_pos - 1);
- }
+ position = ide_xml_position_new (candidate_node, prefix, candidate_kind, detail);
+ ide_xml_position_set_analysis (position, analysis);
+ ide_xml_position_set_child_pos (position, child_pos);
+ }
+ else if (candidate_kind == IDE_XML_POSITION_KIND_IN_START_TAG ||
+ candidate_kind == IDE_XML_POSITION_KIND_IN_END_TAG)
+ {
+ child_node = candidate_node;
+ candidate_node = ide_xml_symbol_node_get_parent (child_node);
- if (child_pos <= n_children)
- next_sibling_node = IDE_XML_SYMBOL_NODE (ide_xml_symbol_node_get_nth_direct_child (candidate_node,
child_pos));
+ position = ide_xml_position_new (candidate_node, prefix, candidate_kind, detail);
+ ide_xml_position_set_analysis (position, analysis);
+ ide_xml_position_set_child_node (position, child_node);
+ }
+ else
+ g_assert_not_reached ();
- ide_xml_position_set_siblings (position, previous_sibling_node, next_sibling_node);
- ide_xml_position_set_child_pos (position, child_pos);
+ if (child_pos > 0)
+ {
+ previous_sibling_node = IDE_XML_SYMBOL_NODE (ide_xml_symbol_node_get_nth_direct_child (candidate_node,
child_pos - 1));
}
+ if (child_pos < n_children)
+ next_sibling_node = IDE_XML_SYMBOL_NODE (ide_xml_symbol_node_get_nth_direct_child (candidate_node,
child_pos));
+
+ ide_xml_position_set_siblings (position, previous_sibling_node, next_sibling_node);
+
return position;
}
@@ -751,7 +796,7 @@ ide_xml_service_get_position_from_cursor_cb (GObject *object,
analysis = ide_xml_service_get_analysis_finish (self, result, &error);
if (analysis != NULL)
{
- position = get_position (self, analysis, state->line, state->line_offset);
+ position = get_position (self, analysis, (GtkTextBuffer *)state->buffer, state->line,
state->line_offset);
g_task_return_pointer (task, position, g_object_unref);
}
else
diff --git a/plugins/xml-pack/ide-xml-symbol-node.c b/plugins/xml-pack/ide-xml-symbol-node.c
index b58795c..85a4934 100644
--- a/plugins/xml-pack/ide-xml-symbol-node.c
+++ b/plugins/xml-pack/ide-xml-symbol-node.c
@@ -433,7 +433,6 @@ ide_xml_symbol_node_set_location (IdeXmlSymbolNode *self,
{
g_return_if_fail (IDE_IS_XML_SYMBOL_NODE (self));
g_return_if_fail (G_IS_FILE (file) || file == NULL);
- g_return_if_fail (size >= 2);
g_clear_object (&self->file);
if (file != NULL)
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]