Skip to content

Commit

Permalink
Merge pull request #57 from galaxyproject/improve-completion
Browse files Browse the repository at this point in the history
Improve completion
  • Loading branch information
bgruening authored Nov 13, 2020
2 parents 1c8ea71 + adc226c commit 7d8df67
Show file tree
Hide file tree
Showing 3 changed files with 55 additions and 12 deletions.
13 changes: 10 additions & 3 deletions server/galaxyls/services/completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def get_completion_at_context(
elif triggerKind == CompletionTriggerKind.Invoked:
if context.is_attribute_value:
return self.get_attribute_value_completion(context)
if context.is_tag:
if context.is_tag and not context.is_closing_tag:
if context.token.name:
return self.get_attribute_completion(context)
return self.get_node_completion(context)
Expand All @@ -62,7 +62,8 @@ def get_node_completion(self, context: XmlContext) -> CompletionList:
result.append(self._build_node_completion_item(context.xsd_element))
elif context.xsd_element:
for child in context.xsd_element.children:
result.append(self._build_node_completion_item(child, len(result)))
if not context.has_reached_max_occurs(child):
result.append(self._build_node_completion_item(child, len(result)))
result.append(self._build_node_completion_item(self.xsd_tree.expand_element, len(result)))
return CompletionList(items=result, is_incomplete=False)

Expand All @@ -78,7 +79,13 @@ def get_attribute_completion(self, context: XmlContext) -> CompletionList:
CompletionList: The completion item with the basic information
about the attributes.
"""
if context.is_empty or context.is_content or context.is_attribute_value or context.is_closing_tag:
if (
context.is_empty
or context.is_content
or context.is_attribute_value
or context.is_closing_tag
or not context.token.name
):
return CompletionList(is_incomplete=False)

result = []
Expand Down
23 changes: 21 additions & 2 deletions server/galaxyls/services/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ def is_empty(self) -> bool:
@property
def is_root(self) -> bool:
"""Indicates if the element at context is the root element."""
return self._node and len(self._node.ancestors) == 1
return self._node is not None and len(self._node.ancestors) == 1

@property
def is_tag(self) -> bool:
Expand All @@ -86,7 +86,7 @@ def is_attribute_value(self) -> bool:
@property
def attribute_name(self) -> Optional[str]:
"""The name of the attribute if the context is an attribute or None."""
return self._node is not None and self._node.get_attribute_name()
return self._node and self._node.get_attribute_name()

@property
def is_content(self) -> bool:
Expand All @@ -107,6 +107,25 @@ def stack(self) -> List[str]:
return []
return self._node.stack

def has_reached_max_occurs(self, node: XsdNode) -> bool:
"""Checks if the given node has reached the maximum number
of ocurrences.
Args:
child (XsdNode): The node to check.
Returns:
bool: True if the node has reached the maximum number
of ocurrences permitted.
"""
if node.max_occurs < 0:
return False
target = self._node.parent or self._node
if target:
existing_count = sum(1 for child_node in target.children if child_node.name == node.name)
return existing_count >= node.max_occurs
return False


class XmlContextService:
"""This service provides information about the XML context at
Expand Down
31 changes: 24 additions & 7 deletions server/galaxyls/tests/unit/test_completion.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ def fake_tree(mocker: MockerFixture) -> XsdTree:
fake_attr = XsdAttribute("attr", element=mocker.Mock())
fake_attr.enumeration = ["v1", "v2"]
fake_root.attributes[fake_attr.name] = fake_attr
XsdNode("child", element=mocker.Mock(), parent=fake_root)
child = XsdNode("child", element=mocker.Mock(), parent=fake_root)
child.max_occurs = 1
return XsdTree(fake_root)


Expand Down Expand Up @@ -85,7 +86,7 @@ def test_get_completion_at_context_with_open_tag_trigger_returns_expected_node(s
assert actual.items[1].label == "expand"
assert actual.items[1].kind == CompletionItemKind.Class

def test_get_completion_at_context_with_open_tag_invoke_returns_expected_node(self, fake_tree: XsdTree) -> None:
def test_get_completion_at_context_with_closing_tag_invoke_returns_empty(self, fake_tree: XsdTree) -> None:
fake_element = XmlElement()
fake_context = XmlContext(fake_tree.root, fake_element)
fake_completion_context = CompletionContext(CompletionTriggerKind.Invoked)
Expand All @@ -94,14 +95,11 @@ def test_get_completion_at_context_with_open_tag_invoke_returns_expected_node(se
actual = service.get_completion_at_context(fake_context, fake_completion_context)

assert actual
assert len(actual.items) == 2
assert actual.items[0].label == "child"
assert actual.items[0].kind == CompletionItemKind.Class
assert actual.items[1].label == "expand"
assert actual.items[1].kind == CompletionItemKind.Class
assert len(actual.items) == 0

def test_get_completion_at_context_on_node_returns_expected_attributes(self, fake_tree: XsdTree) -> None:
fake_node = XmlElement()
fake_node.name = "root"
fake_node.end_tag_open_offset = 10
fake_node.end_tag_close_offset = 12
fake_context = XmlContext(fake_tree.root, fake_node)
Expand All @@ -119,6 +117,7 @@ def test_get_completion_at_context_on_node_with_attribute_returns_expected_attri
self, fake_tree_with_attrs: XsdTree
) -> None:
fake_node = XmlElement()
fake_node.name = "root"
fake_node.end_tag_open_offset = 10
fake_node.end_tag_close_offset = 12
fake_node.attributes["one"] = XmlAttribute("one", 0, 0, fake_node)
Expand Down Expand Up @@ -160,6 +159,24 @@ def test_return_valid_completion_with_node_context(self, fake_tree: XsdTree, fak
assert actual.items[0].label == fake_tree.root.children[0].name
assert actual.items[1].label == "expand"

def test_completion_node_reached_max_occurs_return_expected(self, fake_tree: XsdTree, mocker: MockerFixture) -> None:
fake_root = XmlElement()
fake_root.name = fake_tree.root.name
fake_root.end_tag_open_offset = 10
fake_root.end_tag_close_offset = 15
fake_child = XmlElement()
fake_child.name = "child"
fake_child.parent = fake_root
fake_child = XmlElement()
fake_child.parent = fake_root
fake_context = XmlContext(fake_tree.root, fake_root)
service = XmlCompletionService(fake_tree)

actual = service.get_node_completion(fake_context)

assert len(actual.items) == 1
assert actual.items[0].label == "expand"

def test_completion_return_root_node_when_empty_context(self, fake_tree: XsdTree, fake_empty_context) -> None:
service = XmlCompletionService(fake_tree)

Expand Down

0 comments on commit 7d8df67

Please sign in to comment.