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/tests/command_completion.cpp b/tests/command_completion.cpp
index 015b4db..d439394 100644
--- a/tests/command_completion.cpp
+++ b/tests/command_completion.cpp
@@ -8,6 +8,7 @@
#include "trompeloeil_doctest.h"
#include "parser.hpp"
+#include "pretty_printers.hpp"
#include "static_schema.hpp"
TEST_CASE("command completion")
@@ -16,49 +17,57 @@
Parser parser(schema);
std::string input;
std::ostringstream errorStream;
- std::set<std::string> expected;
+ std::set<std::string> expectedCompletions;
+ int expectedContextLength;
SECTION("")
{
input = "";
- expected = {"cd", "create", "delete", "set", "commit", "get", "ls", "discard", "help"};
+ expectedCompletions = {"cd", "create", "delete", "set", "commit", "get", "ls", "discard", "help"};
+ expectedContextLength = 0;
}
SECTION(" ")
{
input = " ";
- expected = {"cd", "create", "delete", "set", "commit", "get", "ls", "discard", "help"};
+ expectedCompletions = {"cd", "create", "delete", "set", "commit", "get", "ls", "discard", "help"};
+ expectedContextLength = 0;
}
SECTION("c")
{
input = "c";
- expected = {"cd", "commit", "create"};
+ expectedCompletions = {"cd", "commit", "create"};
+ expectedContextLength = 1;
}
SECTION("d")
{
input = "d";
- expected = {"delete", "discard"};
+ expectedCompletions = {"delete", "discard"};
+ expectedContextLength = 1;
}
SECTION("x")
{
input = "x";
- expected = {};
+ expectedCompletions = {};
+ expectedContextLength = 1;
}
SECTION("cd")
{
input = "cd";
// TODO: depending on how Readline works, this will have to be changed to include a space
- expected = {"cd"};
+ expectedCompletions = {"cd"};
+ expectedContextLength = 2;
}
SECTION("create")
{
input = "create";
- expected = {"create"};
+ expectedCompletions = {"create"};
+ expectedContextLength = 6;
}
- REQUIRE(parser.completeCommand(input, errorStream) == expected);
+ REQUIRE(parser.completeCommand(input, errorStream) == (Completions{expectedCompletions, expectedContextLength}));
}
diff --git a/tests/enum_completion.cpp b/tests/enum_completion.cpp
index d7dfd58..29f23a7 100644
--- a/tests/enum_completion.cpp
+++ b/tests/enum_completion.cpp
@@ -9,6 +9,7 @@
#include "trompeloeil_doctest.h"
#include "parser.hpp"
+#include "pretty_printers.hpp"
#include "static_schema.hpp"
TEST_CASE("enum completion")
@@ -25,38 +26,44 @@
std::string input;
std::ostringstream errorStream;
- std::set<std::string> expected;
+ std::set<std::string> expectedCompletions;
+ int expectedContextLength;
SECTION("set mod:leafEnum ")
{
input = "set mod:leafEnum ";
- expected = {"lala", "lol", "data", "coze"};
+ expectedCompletions = {"lala", "lol", "data", "coze"};
+ expectedContextLength = 0;
}
SECTION("set mod:leafEnum c")
{
input = "set mod:leafEnum c";
- expected = {"coze"};
+ expectedCompletions = {"coze"};
+ expectedContextLength = 1;
}
SECTION("set mod:leafEnum l")
{
input = "set mod:leafEnum l";
- expected = {"lala", "lol"};
+ expectedCompletions = {"lala", "lol"};
+ expectedContextLength = 1;
}
SECTION("set mod:contA/leafInCont ")
{
input = "set mod:contA/leafInCont ";
- expected = {"abc", "def"};
+ expectedCompletions = {"abc", "def"};
+ expectedContextLength = 0;
}
SECTION("set mod:list[number=42]/leafInList ")
{
input = "set mod:list[number=42]/leafInList ";
- expected = {"ano", "anoda", "ne", "katoda"};
+ expectedCompletions = {"ano", "anoda", "ne", "katoda"};
+ expectedContextLength = 0;
}
- REQUIRE(parser.completeCommand(input, errorStream) == expected);
+ REQUIRE(parser.completeCommand(input, errorStream) == (Completions{expectedCompletions, expectedContextLength}));
}
diff --git a/tests/path_completion.cpp b/tests/path_completion.cpp
index 77dae51..f84ae4f 100644
--- a/tests/path_completion.cpp
+++ b/tests/path_completion.cpp
@@ -6,21 +6,11 @@
*
*/
-#include <experimental/iterator>
#include "trompeloeil_doctest.h"
#include "parser.hpp"
+#include "pretty_printers.hpp"
#include "static_schema.hpp"
-namespace std {
-std::ostream& operator<<(std::ostream& s, const std::set<std::string> set)
-{
- s << std::endl << "{";
- std::copy(set.begin(), set.end(), std::experimental::make_ostream_joiner(s, ", "));
- s << "}" << std::endl;
- return s;
-}
-}
-
TEST_CASE("path_completion")
{
auto schema = std::make_shared<StaticSchema>();
@@ -49,86 +39,105 @@
Parser parser(schema);
std::string input;
std::ostringstream errorStream;
- std::set<std::string> expected;
+
+ std::set<std::string> expectedCompletions;
+ // GCC complains here with -Wmaybe-uninitialized if I don't assign
+ // something here. I suspect it's because of nested SECTIONs. -1 is an
+ // invalid value (as in, I'll never expect expectedContextLength to be -1),
+ // so let's go with that.
+ int expectedContextLength = -1;
SECTION("node name completion")
{
SECTION("ls ")
{
input = "ls ";
- expected = {"example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list[", "example:ovoce[", "example:ovocezelenina[", "example:twoKeyList[", "second:amelie/"};
+ expectedCompletions = {"example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list[", "example:ovoce[", "example:ovocezelenina[", "example:twoKeyList[", "second:amelie/"};
+ expectedContextLength = 0;
}
SECTION("ls e")
{
input = "ls e";
- expected = {"example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list[", "example:ovoce[", "example:ovocezelenina[", "example:twoKeyList["};
+ expectedCompletions = {"example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list[", "example:ovoce[", "example:ovocezelenina[", "example:twoKeyList["};
+ expectedContextLength = 1;
}
SECTION("ls example:ano")
{
input = "ls example:ano";
- expected = {"example:ano/", "example:anoda/"};
+ expectedCompletions = {"example:ano/", "example:anoda/"};
+ expectedContextLength = 11;
}
SECTION("ls example:ano/example:a")
{
input = "ls example:ano/example:a";
- expected = {"example:a2/"};
+ expectedCompletions = {"example:a2/"};
+ expectedContextLength = 9;
}
SECTION("ls x")
{
input = "ls x";
- expected = {};
+ expectedCompletions = {};
+ expectedContextLength = 1;
}
SECTION("ls /")
{
input = "ls /";
- expected = {"example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list[", "example:ovoce[", "example:ovocezelenina[", "example:twoKeyList[", "second:amelie/"};
+ expectedCompletions = {"example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list[", "example:ovoce[", "example:ovocezelenina[", "example:twoKeyList[", "second:amelie/"};
+ expectedContextLength = 0;
}
SECTION("ls /e")
{
input = "ls /e";
- expected = {"example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list[", "example:ovoce[", "example:ovocezelenina[", "example:twoKeyList["};
+ expectedCompletions = {"example:ano/", "example:anoda/", "example:bota/", "example:leafInt ", "example:list[", "example:ovoce[", "example:ovocezelenina[", "example:twoKeyList["};
+ expectedContextLength = 1;
}
SECTION("ls example:bota")
{
input = "ls example:bota";
- expected = {"example:bota/"};
+ expectedCompletions = {"example:bota/"};
+ expectedContextLength = 12;
}
SECTION("ls /example:bota")
{
input = "ls /example:bota";
- expected = {"example:bota/"};
+ expectedCompletions = {"example:bota/"};
+ expectedContextLength = 12;
}
SECTION("ls /s")
{
input = "ls /s";
- expected = {"second:amelie/"};
+ expectedCompletions = {"second:amelie/"};
+ expectedContextLength = 1;
}
SECTION("ls /example:list[number=3]/")
{
input = "ls /example:list[number=3]/";
- expected = {"example:contInList/", "example:number "};
+ expectedCompletions = {"example:contInList/", "example:number "};
+ expectedContextLength = 0;
}
SECTION("ls /example:list[number=3]/c")
{
input = "ls /example:list[number=3]/e";
- expected = {"example:contInList/", "example:number "};
+ expectedCompletions = {"example:contInList/", "example:number "};
+ expectedContextLength = 1;
}
SECTION("ls /example:list[number=3]/a")
{
input = "ls /example:list[number=3]/a";
- expected = {};
+ expectedCompletions = {};
+ expectedContextLength = 1;
}
}
@@ -137,105 +146,122 @@
SECTION("cd example:lis")
{
input = "cd example:lis";
- expected = {"example:list["};
+ expectedCompletions = {"example:list["};
+ expectedContextLength = 11;
}
SECTION("set example:list")
{
input = "set example:list";
- expected = {"example:list["};
+ expectedCompletions = {"example:list["};
+ expectedContextLength = 12;
}
SECTION("cd example:list")
{
input = "cd example:list";
- expected = {"example:list["};
+ expectedCompletions = {"example:list["};
+ expectedContextLength = 12;
}
SECTION("cd example:list[")
{
input = "cd example:list[";
- expected = {"number="};
+ expectedCompletions = {"number="};
+ expectedContextLength = 0;
}
SECTION("cd example:list[numb")
{
input = "cd example:list[numb";
- expected = {"number="};
+ expectedCompletions = {"number="};
+ expectedContextLength = 4;
}
SECTION("cd example:list[number")
{
input = "cd example:list[number";
- expected = {"number="};
+ expectedCompletions = {"number="};
+ expectedContextLength = 6;
}
SECTION("cd example:list[number=12")
{
input = "cd example:list[number=12";
- expected = {"]/"};
+ expectedCompletions = {"]/"};
+ expectedContextLength = 0;
}
SECTION("cd example:list[number=12]")
{
input = "cd example:list[number=12]";
- expected = {"]/"};
+ expectedCompletions = {"]/"};
+ expectedContextLength = 1;
}
SECTION("cd example:twoKeyList[")
{
input = "cd example:twoKeyList[";
- expected = {"name=", "number="};
+ expectedCompletions = {"name=", "number="};
+ expectedContextLength = 0;
}
SECTION("cd example:twoKeyList[name=\"AHOJ\"")
{
input = "cd example:twoKeyList[name=\"AHOJ\"";
- expected = {"]["};
+ expectedCompletions = {"]["};
+ expectedContextLength = 0;
}
SECTION("cd example:twoKeyList[name=\"AHOJ\"]")
{
input = "cd example:twoKeyList[name=\"AHOJ\"]";
- expected = {"]["};
+ expectedCompletions = {"]["};
+ expectedContextLength = 1;
}
SECTION("cd example:twoKeyList[name=\"AHOJ\"][")
{
input = "cd example:twoKeyList[name=\"AHOJ\"][";
- expected = {"number="};
+ expectedCompletions = {"number="};
+ expectedContextLength = 0;
}
SECTION("cd example:twoKeyList[number=42][")
{
input = "cd example:twoKeyList[number=42][";
- expected = {"name="};
+ expectedCompletions = {"name="};
+ expectedContextLength = 0;
}
SECTION("cd example:twoKeyList[name=\"AHOJ\"][number=123")
{
input = "cd example:twoKeyList[name=\"AHOJ\"][number=123";
- expected = {"]/"};
+ expectedCompletions = {"]/"};
+ expectedContextLength = 0;
}
SECTION("cd example:twoKeyList[name=\"AHOJ\"][number=123]")
{
input = "cd example:twoKeyList[name=\"AHOJ\"][number=123]";
- expected = {"]/"};
+ expectedCompletions = {"]/"};
+ expectedContextLength = 1;
}
SECTION("cd example:ovoce")
{
input = "cd example:ovoce";
- expected = {"example:ovoce[", "example:ovocezelenina["};
+ expectedCompletions = {"example:ovoce[", "example:ovocezelenina["};
+ expectedContextLength = 13;
}
}
SECTION("clear completions when no longer inputting path")
{
input = "set example:leafInt ";
- expected = {};
+ expectedCompletions = {};
+ expectedContextLength = 0;
}
- REQUIRE(parser.completeCommand(input, errorStream) == expected);
+ REQUIRE(parser.completeCommand(input, errorStream) == (Completions{expectedCompletions, expectedContextLength}));
}
diff --git a/tests/pretty_printers.hpp b/tests/pretty_printers.hpp
new file mode 100644
index 0000000..42be33e
--- /dev/null
+++ b/tests/pretty_printers.hpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2020 CESNET, https://photonics.cesnet.cz/
+ *
+ * Written by Václav Kubernát <kubernat@cesnet.cz>
+ *
+*/
+
+#include <experimental/iterator>
+#include "parser.hpp"
+namespace std {
+std::ostream& operator<<(std::ostream& s, const Completions& completion)
+{
+ s << std::endl << "Completions {" << std::endl << " m_completions: ";
+ std::transform(completion.m_completions.begin(), completion.m_completions.end(),
+ std::experimental::make_ostream_joiner(s, ", "),
+ [] (auto it) { return '"' + it + '"'; });
+ s << std::endl << " m_contextLength: " << completion.m_contextLength << std::endl;
+ s << "}" << std::endl;
+ return s;
+}
+}