allow moving up a node with cd
Change-Id: Id1419fddda4aa2d2c16b5775a43c8df58db98c73
diff --git a/src/CTree.cpp b/src/CTree.cpp
index 5d0cf7e..69afb58 100644
--- a/src/CTree.cpp
+++ b/src/CTree.cpp
@@ -13,6 +13,10 @@
InvalidNodeException::~InvalidNodeException() = default;
struct nodeToString : public boost::static_visitor<std::string> {
+ std::string operator()(const nodeup_&) const
+ {
+ return "..";
+ }
template <class T>
std::string operator()(const T& node) const
{
@@ -94,7 +98,6 @@
m_nodes.emplace(name, std::unordered_map<std::string, NodeType>());
}
-
void CTree::changeNode(const path_& name)
{
if (name.m_nodes.empty()) {
@@ -102,7 +105,13 @@
return;
}
for (const auto& it : name.m_nodes) {
- m_curDir = joinPaths(m_curDir, boost::apply_visitor(nodeToString(), it));
+ const std::string node = boost::apply_visitor(nodeToString(), it);
+ if (node == "..") {
+ m_curDir = stripLastNodeFromPath(m_curDir);
+ } else {
+ m_curDir = joinPaths(m_curDir, boost::apply_visitor(nodeToString(), it));
+ }
+
}
}
std::string CTree::currentNode() const
diff --git a/src/ast.hpp b/src/ast.hpp
index 8e71476..0c257d0 100644
--- a/src/ast.hpp
+++ b/src/ast.hpp
@@ -37,6 +37,14 @@
struct parser_context_tag;
+
+struct nodeup_ {
+ bool operator==(const nodeup_&) const
+ {
+ return true;
+ }
+};
+
struct container_ {
container_() = default;
container_(const std::string& name);
@@ -64,7 +72,7 @@
struct path_ {
bool operator==(const path_& b) const;
- std::vector<boost::variant<container_, listElement_>> m_nodes;
+ std::vector<boost::variant<container_, listElement_, nodeup_>> m_nodes;
};
diff --git a/src/ast_handlers.hpp b/src/ast_handlers.hpp
index 746116e..9ab4738 100644
--- a/src/ast_handlers.hpp
+++ b/src/ast_handlers.hpp
@@ -11,7 +11,6 @@
#include "CTree.hpp"
#include "parser_context.hpp"
-
struct keyValue_class {
template <typename T, typename Iterator, typename Context>
void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
@@ -99,6 +98,22 @@
}
};
+
+struct nodeup_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);
+
+ if (!parserContext.m_curPath.empty()) {
+ parserContext.m_curPath = stripLastNodeFromPath(parserContext.m_curPath);
+ } else {
+ _pass(context) = false;
+ }
+
+ }
+};
+
struct container_class {
template <typename T, typename Iterator, typename Context>
void on_success(Iterator const&, Iterator const&, T& ast, Context const& context)
diff --git a/src/grammars.hpp b/src/grammars.hpp
index c6f3ab5..ef6b60f 100644
--- a/src/grammars.hpp
+++ b/src/grammars.hpp
@@ -11,11 +11,13 @@
#include "ast.hpp"
#include "ast_handlers.hpp"
+
x3::rule<keyValue_class, keyValue_> const keyValue = "keyValue";
x3::rule<identifier_class, std::string> const identifier = "identifier";
x3::rule<listPrefix_class, std::string> const listPrefix = "listPrefix";
x3::rule<listSuffix_class, std::vector<keyValue_>> const listSuffix = "listSuffix";
x3::rule<listElement_class, listElement_> const listElement = "listElement";
+x3::rule<nodeup_class, nodeup_> const nodeup = "nodeup";
x3::rule<container_class, container_> const container = "container";
x3::rule<path_class, path_> const path = "path";
x3::rule<cd_class, cd_> const cd = "cd";
@@ -39,20 +41,24 @@
auto const listElement_def =
listPrefix > listSuffix;
+auto const nodeup_def =
+ lit("..") > x3::attr(nodeup_());
+
auto const container_def =
identifier;
auto const path_def =
- (container | listElement) % '/';
+ (container | listElement | nodeup) % '/';
auto const cd_def =
- lit("cd") > x3::omit[x3::no_skip[space]] > path >> x3::eoi;
+ lit("cd") > x3::omit[x3::no_skip[space]] > path >> x3::eoi;
BOOST_SPIRIT_DEFINE(keyValue)
BOOST_SPIRIT_DEFINE(identifier)
BOOST_SPIRIT_DEFINE(listPrefix)
BOOST_SPIRIT_DEFINE(listSuffix)
BOOST_SPIRIT_DEFINE(listElement)
+BOOST_SPIRIT_DEFINE(nodeup)
BOOST_SPIRIT_DEFINE(container)
BOOST_SPIRIT_DEFINE(path)
BOOST_SPIRIT_DEFINE(cd)
diff --git a/src/utils.cpp b/src/utils.cpp
index 38bfe7d..77466c4 100644
--- a/src/utils.cpp
+++ b/src/utils.cpp
@@ -14,3 +14,14 @@
else
return prefix + '/' + suffix;
}
+
+std::string stripLastNodeFromPath(const std::string& path)
+{
+ std::string res = path;
+ auto pos = res.find_last_of('/');
+ if (pos == res.npos)
+ res.clear();
+ else
+ res.erase(pos);
+ return res;
+}
diff --git a/src/utils.hpp b/src/utils.hpp
index 54c455a..4f10102 100644
--- a/src/utils.hpp
+++ b/src/utils.hpp
@@ -8,3 +8,4 @@
#include <string>
std::string joinPaths(const std::string& prefix, const std::string& suffix);
+std::string stripLastNodeFromPath(const std::string& path);
diff --git a/tests/cd.cpp b/tests/cd.cpp
index d6079fb..8ab4c40 100644
--- a/tests/cd.cpp
+++ b/tests/cd.cpp
@@ -101,6 +101,33 @@
}
}
+ SECTION("moving up")
+ {
+ SECTION("a/..")
+ {
+ input = "cd a/..";
+ expected.m_path.m_nodes.push_back(container_("a"));
+ expected.m_path.m_nodes.push_back(nodeup_());
+ }
+
+ SECTION("a/../a")
+ {
+ input = "cd a/../a";
+ expected.m_path.m_nodes.push_back(container_("a"));
+ expected.m_path.m_nodes.push_back(nodeup_());
+ expected.m_path.m_nodes.push_back(container_("a"));
+ }
+
+ SECTION("a/../a/a2")
+ {
+ input = "cd a/../a/a2";
+ expected.m_path.m_nodes.push_back(container_("a"));
+ expected.m_path.m_nodes.push_back(nodeup_());
+ expected.m_path.m_nodes.push_back(container_("a"));
+ expected.m_path.m_nodes.push_back(container_("a2"));
+ }
+ }
+
cd_ command = parser.parseCommand(input, errorStream);
REQUIRE(command == expected);
}