Skip to content

Commit

Permalink
close #235 - view the command history and execute a command with bang +
Browse files Browse the repository at this point in the history
id
  • Loading branch information
daniele77 committed Oct 22, 2024
2 parents 2363f79 + 4e5ce75 commit e785137
Show file tree
Hide file tree
Showing 5 changed files with 132 additions and 9 deletions.
15 changes: 12 additions & 3 deletions include/cli/cli.h
Original file line number Diff line number Diff line change
Expand Up @@ -358,6 +358,13 @@ namespace cli

void ShowHistory() const { history.Show(out); }

void ExecFromHistory(unsigned index)
{
history.ForgetLatest();
const auto cmd = history.At(index);
Feed(cmd);
}

std::string PreviousCmd(const std::string& line)
{
return history.Previous(line);
Expand Down Expand Up @@ -890,13 +897,16 @@ namespace cli
[this](std::ostream&){ Exit(); },
"Quit the session"
);
#ifdef CLI_HISTORY_CMD
globalScopeMenu->Insert(
"history",
[this](std::ostream&){ ShowHistory(); },
"Show the history"
);
#endif
globalScopeMenu->Insert(
"!", {"history entry index"},
[this](std::ostream&, unsigned cmdIndex){ ExecFromHistory(cmdIndex); },
"Exec a command by index in the history"
);
}

inline void CliSession::Feed(const std::string& cmd)
Expand All @@ -909,7 +919,6 @@ namespace cli

try
{

// global cmds check
bool found = globalScopeMenu->ScanCmds(strs, *this);

Expand Down
45 changes: 41 additions & 4 deletions include/cli/detail/history.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,9 +111,13 @@ class History
// Show the whole history on the given ostream
void Show(std::ostream& out) const
{
const auto size = buffer.size();
out << '\n';
for (auto& item: buffer)
out << item << '\n';
for (std::size_t i = 0; i < size; ++i)
{
const auto j = size-1-i;
out << IndexToId(j) << '\t' << buffer[j] << '\n';
}
out << '\n' << std::flush;
}

Expand Down Expand Up @@ -142,21 +146,54 @@ class History
return result;
}

std::string At(std::size_t id) const
{
std::size_t index = IdToIndex(id);
assert(index < buffer.size());
return buffer[index];
}

void ForgetLatest()
{
assert(!buffer.empty());
buffer.pop_front();
}

private:

// oldest has index = size-1 and id = idOfOldest
// newest has index = 0 and id = idOfOldest + size-1
std::size_t IndexToId(std::size_t index) const
{
if (index > idOfOldest+buffer.size()-1)
throw std::out_of_range("Index not found in history");
return idOfOldest + buffer.size() - 1 - index;
}

std::size_t IdToIndex(std::size_t id) const
{
if (id < idOfOldest || id > idOfOldest+buffer.size()-1)
throw std::out_of_range("Index not found in history");
return idOfOldest + buffer.size() - 1 - id;
}

void Insert(const std::string& item)
{
buffer.push_front(item);
buffer.emplace_front(item);
if (buffer.size() > maxSize)
{
buffer.pop_back();
++idOfOldest;
}
}

const std::size_t maxSize;
std::deque<std::string> buffer;
std::deque<std::string> buffer; // buffer[0] is the newest element
std::size_t current = 0;
std::size_t commands = 0; // number of commands issued
enum class Mode { inserting, browsing };
Mode mode = Mode::inserting;
std::size_t idOfOldest = 0; // the id of the oldest element kept in the history
};

} // namespace detail
Expand Down
11 changes: 10 additions & 1 deletion include/cli/detail/split.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ class Text
state = State::escape;
splitResult.emplace_back("");
}
else if (c == '!')
{
splitResult.emplace_back(1, c);
}
else
{
state = State::word;
Expand All @@ -114,6 +118,11 @@ class Text
{
state = State::space;
}
else if (c == '!')
{
splitResult.emplace_back(1, c);
state = State::space;
}
else if (c == '"' || c == '\'')
{
NewSentence(c);
Expand All @@ -122,7 +131,7 @@ class Text
{
prev_state = state;
state = State::escape;
}
}
else
{
assert(!splitResult.empty());
Expand Down
35 changes: 34 additions & 1 deletion test/test_history.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ BOOST_AUTO_TEST_CASE(Insertion)
history.NewCommand("item3");
history.NewCommand("item4");

BOOST_CHECK_EQUAL(history.At(0), "item1");
BOOST_CHECK_EQUAL(history.At(1), "item2");
BOOST_CHECK_EQUAL(history.At(2), "item3");
BOOST_CHECK_EQUAL(history.At(3), "item4");

BOOST_CHECK_EQUAL(history.Previous(""), "item4");
BOOST_CHECK_EQUAL(history.Previous("item4"), "item3");
BOOST_CHECK_EQUAL(history.Previous("foo"), "item2");
Expand All @@ -90,6 +95,12 @@ BOOST_AUTO_TEST_CASE(Insertion)

history.NewCommand("item5");

BOOST_CHECK_EQUAL(history.At(0), "item1");
BOOST_CHECK_EQUAL(history.At(1), "item2");
BOOST_CHECK_EQUAL(history.At(2), "foo");
BOOST_CHECK_EQUAL(history.At(3), "item4");
BOOST_CHECK_EQUAL(history.At(4), "item5");

BOOST_CHECK_EQUAL(history.Previous(""), "item5");
BOOST_CHECK_EQUAL(history.Previous("item5"), "item4");
BOOST_CHECK_EQUAL(history.Next(), "item5");
Expand Down Expand Up @@ -150,6 +161,10 @@ BOOST_AUTO_TEST_CASE(Copies)
const std::vector<std::string> v = { "item1", "item2", "item3" };
history.LoadCommands(v);

BOOST_CHECK_EQUAL(history.At(0), "item1");
BOOST_CHECK_EQUAL(history.At(1), "item2");
BOOST_CHECK_EQUAL(history.At(2), "item3");

BOOST_CHECK_EQUAL(history.Previous(""), "item3");
BOOST_CHECK_EQUAL(history.Previous("item3"), "item2");
BOOST_CHECK_EQUAL(history.Previous("item2"), "item1");
Expand All @@ -158,6 +173,12 @@ BOOST_AUTO_TEST_CASE(Copies)
history.NewCommand("itemA");
history.NewCommand("itemB");

BOOST_CHECK_EQUAL(history.At(0), "item1");
BOOST_CHECK_EQUAL(history.At(1), "item2");
BOOST_CHECK_EQUAL(history.At(2), "item3");
BOOST_CHECK_EQUAL(history.At(3), "itemA");
BOOST_CHECK_EQUAL(history.At(4), "itemB");

BOOST_CHECK_EQUAL(history.Previous(""), "itemB");
BOOST_CHECK_EQUAL(history.Previous("itemB"), "itemA");
BOOST_CHECK_EQUAL(history.Previous("itemA"), "item3");
Expand All @@ -175,13 +196,21 @@ BOOST_AUTO_TEST_CASE(Copies)
const std::vector<std::string> v1 = { "item1", "item2", "item3" };
history1.LoadCommands(v1);

BOOST_CHECK_EQUAL(history1.At(0), "item1");
BOOST_CHECK_EQUAL(history1.At(1), "item2");
BOOST_CHECK_EQUAL(history1.At(2), "item3");

BOOST_CHECK_EQUAL(history1.Previous(""), "item3");
BOOST_CHECK_EQUAL(history1.Previous("item3"), "item2");
BOOST_CHECK_EQUAL(history1.Previous("item2"), "item2");

history1.NewCommand("itemA");
history1.NewCommand("itemB");

BOOST_CHECK_EQUAL(history1.At(2), "item3");
BOOST_CHECK_EQUAL(history1.At(3), "itemA");
BOOST_CHECK_EQUAL(history1.At(4), "itemB");

BOOST_CHECK_EQUAL(history1.Previous(""), "itemB");
BOOST_CHECK_EQUAL(history1.Previous("itemB"), "itemA");
BOOST_CHECK_EQUAL(history1.Previous("itemA"), "itemA");
Expand All @@ -199,9 +228,13 @@ BOOST_AUTO_TEST_CASE(Copies)
history2.NewCommand("itemD");
history2.NewCommand("itemE");

BOOST_CHECK_EQUAL(history2.At(2), "itemC");
BOOST_CHECK_EQUAL(history2.At(3), "itemD");
BOOST_CHECK_EQUAL(history2.At(4), "itemE");

auto cmds2 = history2.GetCommands();
const std::vector<std::string> expected2 = { "itemC", "itemD", "itemE" };
BOOST_CHECK_EQUAL_COLLECTIONS(cmds2.begin(), cmds2.end(), expected2.begin(), expected2.end());
}

BOOST_AUTO_TEST_SUITE_END()
BOOST_AUTO_TEST_SUITE_END()
35 changes: 35 additions & 0 deletions test/test_split.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -241,4 +241,39 @@ BOOST_AUTO_TEST_CASE(EscapedCases)
BOOST_CHECK_EQUAL(strs[0], R"(foo\"bar)");
}

BOOST_AUTO_TEST_CASE(Symbols)
{
VS strs;

split(strs, "!foo"); // two words!
BOOST_CHECK_EQUAL(strs.size(), 2);
BOOST_CHECK_EQUAL(strs[0], "!");
BOOST_CHECK_EQUAL(strs[1], "foo");

split(strs, " ! foo "); // two words
BOOST_CHECK_EQUAL(strs.size(), 2);
BOOST_CHECK_EQUAL(strs[0], "!");
BOOST_CHECK_EQUAL(strs[1], "foo");

split(strs, "!42!69!"); // 5 words
BOOST_CHECK_EQUAL(strs.size(), 5);
BOOST_CHECK_EQUAL(strs[0], "!");
BOOST_CHECK_EQUAL(strs[1], "42");
BOOST_CHECK_EQUAL(strs[2], "!");
BOOST_CHECK_EQUAL(strs[3], "69");
BOOST_CHECK_EQUAL(strs[4], "!");

split(strs, " 38!42!69! 72 ! 33"); // 9 words
BOOST_CHECK_EQUAL(strs.size(), 9);
BOOST_CHECK_EQUAL(strs[0], "38");
BOOST_CHECK_EQUAL(strs[1], "!");
BOOST_CHECK_EQUAL(strs[2], "42");
BOOST_CHECK_EQUAL(strs[3], "!");
BOOST_CHECK_EQUAL(strs[4], "69");
BOOST_CHECK_EQUAL(strs[5], "!");
BOOST_CHECK_EQUAL(strs[6], "72");
BOOST_CHECK_EQUAL(strs[7], "!");
BOOST_CHECK_EQUAL(strs[8], "33");
}

BOOST_AUTO_TEST_SUITE_END()

0 comments on commit e785137

Please sign in to comment.