Change how word splitting works when completing
Previously, I relied on replxx to correctly split words based on
word-splitting characters. However, as completion gets more complex and
completions possibly insert word-splitting characters, it starts to do
weird stuff like deleting some of your input. Fortunately, replxx allows
you to set the context length for completion - that is, how many
character it should consider as part of the word you're completing.
Change-Id: I035ac5059c8ab125efedb90cbeb2910f20da04a7
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 0ce611d..d99e020 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -337,6 +337,7 @@
{
auto& parserContext = x3::get<parser_context_tag>(context);
parserContext.m_suggestions.clear();
+ parserContext.m_completionIterator = boost::none;
parserContext.m_completionSuffix.clear();
}
};
diff --git a/src/main.cpp b/src/main.cpp
index f1a2603..c6e3fce 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -38,16 +38,15 @@
SysrepoAccess datastore("netconf-cli");
Parser parser(datastore.schema());
replxx::Replxx lineEditor;
- lineEditor.set_completion_callback([&parser](const std::string& input, int&) {
+ lineEditor.set_completion_callback([&parser](const std::string& input, int& context) {
std::stringstream stream;
- auto completionsSet = parser.completeCommand(input, stream);
+ auto completions = parser.completeCommand(input, stream);
std::vector<replxx::Replxx::Completion> res;
- std::transform(completionsSet.begin(), completionsSet.end(), std::back_inserter(res),
- [input](auto it) { return it; });
+ std::copy(completions.m_completions.begin(), completions.m_completions.end(), std::back_inserter(res));
+ context = completions.m_contextLength;
return res;
});
- lineEditor.set_word_break_characters(" '/[");
std::optional<std::string> historyFile;
if (auto xdgHome = getenv("XDG_DATA_HOME")) {
diff --git a/src/parser.cpp b/src/parser.cpp
index de375f8..c3dc088 100644
--- a/src/parser.cpp
+++ b/src/parser.cpp
@@ -21,6 +21,11 @@
m_curDir.m_scope = Scope::Absolute;
}
+bool Completions::operator==(const Completions& b) const
+{
+ return this->m_completions == b.m_completions && this->m_contextLength == b.m_contextLength;
+}
+
command_ Parser::parseCommand(const std::string& line, std::ostream& errorStream)
{
command_ parsedCommand;
@@ -42,7 +47,7 @@
return parsedCommand;
}
-std::set<std::string> Parser::completeCommand(const std::string& line, std::ostream& errorStream) const
+Completions Parser::completeCommand(const std::string& line, std::ostream& errorStream) const
{
std::set<std::string> completions;
command_ parsedCommand;
@@ -57,11 +62,15 @@
];
x3::phrase_parse(it, line.end(), grammar, space, parsedCommand);
- auto set = filterByPrefix(ctx.m_suggestions, std::string(ctx.m_completionIterator, line.end()));
+ auto completionIterator = ctx.m_completionIterator ? *ctx.m_completionIterator : line.end();
+
+ int completionContext = line.end() - completionIterator;
+
+ auto set = filterByPrefix(ctx.m_suggestions, std::string(completionIterator, line.end()));
if (set.size() == 1) {
- return {(*set.begin()) + ctx.m_completionSuffix};
+ return {{(*set.begin()) + ctx.m_completionSuffix}, completionContext};
}
- return set;
+ return {set, completionContext};
}
void Parser::changeNode(const dataPath_& name)
diff --git a/src/parser.hpp b/src/parser.hpp
index 3c009e6..c2cd8d6 100644
--- a/src/parser.hpp
+++ b/src/parser.hpp
@@ -24,6 +24,12 @@
~TooManyArgumentsException() override;
};
+struct Completions {
+ bool operator==(const Completions& b) const;
+ std::set<std::string> m_completions;
+ int m_contextLength;
+};
+
class Parser {
public:
Parser(const std::shared_ptr<const Schema> schema);
@@ -31,7 +37,7 @@
void changeNode(const dataPath_& name);
std::string currentNode() const;
std::set<std::string> availableNodes(const boost::optional<boost::variant<boost::variant<dataPath_, schemaPath_>, module_>>& path, const Recursion& option) const;
- std::set<std::string> completeCommand(const std::string& line, std::ostream& errorStream) const;
+ Completions completeCommand(const std::string& line, std::ostream& errorStream) const;
private:
const std::shared_ptr<const Schema> m_schema;
diff --git a/src/parser_context.hpp b/src/parser_context.hpp
index 10a6634..77357e7 100644
--- a/src/parser_context.hpp
+++ b/src/parser_context.hpp
@@ -32,7 +32,7 @@
bool m_completing = false;
std::set<std::string> m_suggestions;
// Iterator pointing to where suggestions were created
- std::string::const_iterator m_completionIterator;
+ boost::optional<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)