Fix path completion on schema paths
The problem was that the grammar was deisgned wrongly. Before this, we
allowed the parser to leave some part of the string unparsed, if
completion was active. However, that lead to some problems where the
stopped prematurely on data path (because we allowed it to end with
unparsed output) while it was possible, to parse more stuff as a schema
path (for example a list without its keys).
The new grammar is a better take on this: first of all
createPathSuggestions is only used if there is a trailing slash (if
there isn't, the completions get created inside the dataNode parser).
Then, if we are doing completion, we parse characters until a next slash
or space. If there actually is another slash, it means that this type of
path wasn't parsed completely, so this whole path can be possibly parsed
even more with other types of path parsers.
Issue: https://tree.taiga.io/project/jktjkt-netconf-cli/issue/151
Change-Id: I7eb1712b28d987dde1192c8438dd055bed71360a
diff --git a/src/grammars.hpp b/src/grammars.hpp
index dd4e16f..dd13c6a 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -179,12 +179,13 @@
// This is a pseudo-parser, that fails if we're not completing a command
auto const completing_def =
- x3::eps;
+ x3::no_skip[x3::eps];
+
+auto const rest =
+ x3::omit[x3::no_skip[+(char_ - '/' - space_separator)]];
// I have to insert an empty vector to the first alternative, otherwise they won't have the same attribute
-auto const dataPath_def =
- initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi |
- initializePath >> -(absoluteStart >> createPathSuggestions) >> dataNode % '/' >> (trailingSlash >> createPathSuggestions >> (completing | x3::eoi) | (&space_separator | x3::eoi));
+auto const dataPath_def = initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi | initializePath >> -(absoluteStart >> createPathSuggestions) >> dataNode % '/' >> (-(trailingSlash >> createPathSuggestions) >> -(completing >> rest) >> (&space_separator | x3::eoi));
auto const dataNodeList_def =
createPathSuggestions >> -(module) >> list;
@@ -197,13 +198,9 @@
dataNode % '/' >> '/' >> dataNodeList >> -(&char_('/') >> createPathSuggestions) |
x3::attr(decltype(dataPath_::m_nodes)()) >> dataNodeList;
-auto const dataPathListEnd_def =
- initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi |
- initializePath >> -(absoluteStart >> createPathSuggestions) >> dataNodesListEnd >> (trailingSlash >> createPathSuggestions >> (completing | x3::eoi) | (&space_separator | x3::eoi));
+auto const dataPathListEnd_def = initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(dataPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi | initializePath >> -(absoluteStart >> createPathSuggestions) >> dataNodesListEnd >> (-(trailingSlash >> createPathSuggestions) >> -(completing >> rest) >> (&space_separator | x3::eoi));
-auto const schemaPath_def =
- initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(schemaPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi |
- initializePath >> -(absoluteStart >> createPathSuggestions) >> schemaNode % '/' >> (trailingSlash >> createPathSuggestions >> (completing | x3::eoi) | (&space_separator | x3::eoi));
+auto const schemaPath_def = initializePath >> absoluteStart >> createPathSuggestions >> x3::attr(decltype(schemaPath_::m_nodes)()) >> x3::attr(TrailingSlash::NonPresent) >> x3::eoi | initializePath >> -(absoluteStart >> createPathSuggestions) >> schemaNode % '/' >> (-(trailingSlash >> createPathSuggestions) >> -(completing >> rest) >> (&space_separator | x3::eoi));
auto const leafPath_def =
dataPath;
diff --git a/tests/path_completion.cpp b/tests/path_completion.cpp
index 0715639..2403f9d 100644
--- a/tests/path_completion.cpp
+++ b/tests/path_completion.cpp
@@ -133,6 +133,13 @@
expectedContextLength = 1;
}
+ SECTION("ls /example:list/")
+ {
+ input = "ls /example:list/";
+ expectedCompletions = {"example:contInList/", "example:number "};
+ expectedContextLength = 0;
+ }
+
SECTION("ls /example:list[number=3]/")
{
input = "ls /example:list[number=3]/";
@@ -153,6 +160,13 @@
expectedCompletions = {};
expectedContextLength = 1;
}
+
+ SECTION("ls /example:list/example:contInList/")
+ {
+ input = "ls /example:list/example:contInList/";
+ expectedCompletions = {};
+ expectedContextLength = 0;
+ }
}
SECTION("list keys completion")