Suggest opening bracket for list keys
Change-Id: I570f11aebfd68614b7a9af80c42d9f172c64e32f
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index fede04c..dd80889 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -619,11 +619,21 @@
if (generateMissingKeyCompletionSet(keysNeeded, parserContext.m_tmpListKeys).empty()) {
parserContext.m_suggestions = {"]/"};
} else {
- parserContext.m_suggestions = {"]"};
+ parserContext.m_suggestions = {"]["};
}
}
};
+struct suggestKeysStart_class {
+ template <typename T, typename Iterator, typename Context>
+ void on_success(Iterator const&, Iterator const&, T&, Context const& context)
+ {
+ auto& parserContext = x3::get<parser_context_tag>(context);
+
+ parserContext.m_completionSuffix = "[";
+ }
+};
+
struct commandNamesVisitor {
template <typename T>
auto operator()(boost::type<T>)
diff --git a/src/grammars.hpp b/src/grammars.hpp
index e6a7fc7..583a960 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -63,6 +63,7 @@
x3::rule<initializePath_class, x3::unused_type> const initializePath = "initializePath";
x3::rule<createPathSuggestions_class, x3::unused_type> const createPathSuggestions = "createPathSuggestions";
x3::rule<createKeySuggestions_class, x3::unused_type> const createKeySuggestions = "createKeySuggestions";
+x3::rule<suggestKeysStart_class, x3::unused_type> const suggestKeysStart = "suggestKeysStart";
x3::rule<suggestKeysEnd_class, x3::unused_type> const suggestKeysEnd = "suggestKeysEnd";
x3::rule<createCommandSuggestions_class, x3::unused_type> const createCommandSuggestions = "createCommandSuggestions";
x3::rule<completing_class, x3::unused_type> const completing = "completing";
@@ -89,6 +90,9 @@
auto const createKeySuggestions_def =
x3::eps;
+auto const suggestKeysStart_def =
+ x3::eps;
+
auto const suggestKeysEnd_def =
x3::eps;
@@ -109,14 +113,14 @@
];
auto const listPrefix_def =
- node_identifier >> &char_('[');
+ node_identifier;
// even though we don't allow no keys to be supplied, the star allows me to check which keys are missing
auto const listSuffix_def =
*keyValueWrapper;
auto const listElement_def =
- listPrefix > listSuffix;
+ listPrefix >> -(!char_('[') >> suggestKeysStart) >> &char_('[') > listSuffix;
auto const list_def =
node_identifier >> !char_('[');
@@ -348,6 +352,7 @@
BOOST_SPIRIT_DEFINE(command)
BOOST_SPIRIT_DEFINE(createPathSuggestions)
BOOST_SPIRIT_DEFINE(createKeySuggestions)
+BOOST_SPIRIT_DEFINE(suggestKeysStart)
BOOST_SPIRIT_DEFINE(suggestKeysEnd)
BOOST_SPIRIT_DEFINE(createCommandSuggestions)
BOOST_SPIRIT_DEFINE(completing)
diff --git a/src/parser.cpp b/src/parser.cpp
index cf433e2..26e417f 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -54,7 +54,11 @@
];
x3::phrase_parse(it, line.end(), grammar, space, parsedCommand);
- return filterByPrefix(ctx.m_suggestions, std::string(ctx.m_completionIterator, line.end()));
+ auto set = filterByPrefix(ctx.m_suggestions, std::string(ctx.m_completionIterator, line.end()));
+ if (set.size() == 1) {
+ return {(*set.begin()) + ctx.m_completionSuffix};
+ }
+ return set;
}
void Parser::changeNode(const dataPath_& name)
diff --git a/src/parser_context.hpp b/src/parser_context.hpp
index 3871192..5bf1b26 100644
--- a/src/parser_context.hpp
+++ b/src/parser_context.hpp
@@ -22,4 +22,8 @@
std::set<std::string> m_suggestions;
// Iterator pointing to where suggestions were created
std::string::const_iterator m_completionIterator;
+ // If the parser determines that suggestions are unambiguous (after
+ // filtering by prefix), this suffix gets added to the completion (for
+ // example a left bracket after a list)
+ std::string m_completionSuffix;
};
diff --git a/tests/path_completion.cpp b/tests/path_completion.cpp
index 0359675..0e66595 100644
--- a/tests/path_completion.cpp
+++ b/tests/path_completion.cpp
@@ -26,6 +26,8 @@
schema->addContainer("example:ano/example:a2", "example:a3");
schema->addContainer("example:bota/example:b2", "example:b3");
schema->addList("", "example:list", {"number"});
+ schema->addList("", "example:ovoce", {"name"});
+ schema->addList("", "example:ovocezelenina", {"name"});
schema->addContainer("example:list", "example:contInList");
schema->addList("", "example:twoKeyList", {"number", "name"});
Parser parser(schema);
@@ -38,13 +40,13 @@
SECTION("ls ")
{
input = "ls ";
- expected = {"example:ano", "example:anoda", "example:bota", "second:amelie", "example:list", "example:twoKeyList"};
+ expected = {"example:ano", "example:anoda", "example:bota", "second:amelie", "example:list", "example:twoKeyList", "example:ovoce", "example:ovocezelenina"};
}
SECTION("ls e")
{
input = "ls e";
- expected = {"example:ano", "example:anoda", "example:bota", "example:list", "example:twoKeyList"};
+ expected = {"example:ano", "example:anoda", "example:bota", "example:list", "example:twoKeyList", "example:ovoce", "example:ovocezelenina"};
}
SECTION("ls example:ano")
@@ -68,13 +70,13 @@
SECTION("ls /")
{
input = "ls /";
- expected = {"example:ano", "example:anoda", "example:bota", "second:amelie", "example:list", "example:twoKeyList"};
+ expected = {"example:ano", "example:anoda", "example:bota", "second:amelie", "example:list", "example:twoKeyList", "example:ovoce", "example:ovocezelenina"};
}
SECTION("ls /e")
{
input = "ls /e";
- expected = {"example:ano", "example:anoda", "example:bota", "example:list", "example:twoKeyList"};
+ expected = {"example:ano", "example:anoda", "example:bota", "example:list", "example:twoKeyList", "example:ovoce", "example:ovocezelenina"};
}
SECTION("ls /s")
@@ -113,7 +115,13 @@
SECTION("set example:list")
{
input = "set example:list";
- expected = {"example:list"};
+ expected = {"example:list["};
+ }
+
+ SECTION("cd example:list")
+ {
+ input = "cd example:list";
+ expected = {"example:list["};
}
SECTION("cd example:list[")
@@ -152,6 +160,18 @@
expected = {"name=", "number="};
}
+ SECTION("cd example:twoKeyList[name=\"AHOJ\"")
+ {
+ input = "cd example:twoKeyList[name=\"AHOJ\"";
+ expected = {"]["};
+ }
+
+ SECTION("cd example:twoKeyList[name=\"AHOJ\"]")
+ {
+ input = "cd example:twoKeyList[name=\"AHOJ\"]";
+ expected = {"]["};
+ }
+
SECTION("cd example:twoKeyList[name=\"AHOJ\"][")
{
input = "cd example:twoKeyList[name=\"AHOJ\"][";
@@ -175,6 +195,12 @@
input = "cd example:twoKeyList[name=\"AHOJ\"][number=123]";
expected = {"]/"};
}
+
+ SECTION("cd example:ovoce")
+ {
+ input = "cd example:ovoce";
+ expected = {"example:ovoce", "example:ovocezelenina"};
+ }
}
REQUIRE(parser.completeCommand(input, errorStream) == expected);