Command done
This commit is contained in:
parent
28613af006
commit
40d98cdbb6
@ -7,6 +7,10 @@ add_executable(${PROJECT_NAME}
|
|||||||
Page.cpp
|
Page.cpp
|
||||||
stringutil.hpp
|
stringutil.hpp
|
||||||
stringutil.cpp
|
stringutil.cpp
|
||||||
|
Tui.cpp
|
||||||
|
Tui.h
|
||||||
|
Command.h
|
||||||
|
Command.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${PROJECT_NAME} PRIVATE LibXml2::LibXml2 cpr::cpr)
|
target_link_libraries(${PROJECT_NAME} PRIVATE LibXml2::LibXml2 cpr::cpr)
|
||||||
|
51
src/Command.cpp
Normal file
51
src/Command.cpp
Normal file
@ -0,0 +1,51 @@
|
|||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Command {
|
||||||
|
Command readCommand() {
|
||||||
|
if (!std::cin)
|
||||||
|
return {Exit{}};
|
||||||
|
std::string line;
|
||||||
|
if (!std::getline(std::cin, line))
|
||||||
|
return {Exit{}};
|
||||||
|
|
||||||
|
// Trim leading and trailing whitespaces
|
||||||
|
constexpr std::string_view TO_TRIM = " \t\n\r";
|
||||||
|
const size_t start = line.find_first_not_of(TO_TRIM);
|
||||||
|
const size_t end = line.find_last_not_of(TO_TRIM);
|
||||||
|
if (start == std::string::npos) return None{};
|
||||||
|
const std::string_view line_trimmed(line.data() + start, end - start + 1);
|
||||||
|
|
||||||
|
using namespace std::string_view_literals;
|
||||||
|
if (line_trimmed == "r"sv || line_trimmed == "refresh"sv)
|
||||||
|
return Refresh{};
|
||||||
|
if (line_trimmed == "n"sv || line_trimmed == ">"sv || line_trimmed == "next"sv)
|
||||||
|
return Next{};
|
||||||
|
if (line_trimmed == "p"sv || line_trimmed == "<"sv || line_trimmed == "previous"sv)
|
||||||
|
return Previous{};
|
||||||
|
if (line_trimmed == "x"sv || line_trimmed == "exit"sv || line_trimmed == "q"sv || line_trimmed == "quit"sv)
|
||||||
|
return Exit{};
|
||||||
|
if (line_trimmed == "help"sv || line_trimmed == "?"sv || line_trimmed == "?"sv)
|
||||||
|
return Help{};
|
||||||
|
|
||||||
|
if (line_trimmed.starts_with("seek") || line.starts_with("s ")) {
|
||||||
|
const size_t space = line_trimmed.find(' ');
|
||||||
|
if (space == std::string::npos)
|
||||||
|
throw NoNumberException();
|
||||||
|
int number = 0;
|
||||||
|
const size_t size = line.size();
|
||||||
|
for (size_t i = space + 1; i < size; ++i) {
|
||||||
|
const char c = line_trimmed[i];
|
||||||
|
if (!std::isdigit(c))
|
||||||
|
throw NoNumberException();
|
||||||
|
number = number * 10 + (c - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
return {Seek{number}};
|
||||||
|
}
|
||||||
|
|
||||||
|
return {None{}};
|
||||||
|
}
|
||||||
|
}
|
41
src/Command.h
Normal file
41
src/Command.h
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <variant>
|
||||||
|
|
||||||
|
|
||||||
|
namespace Command {
|
||||||
|
class NoNumberException final : public std::exception {
|
||||||
|
public:
|
||||||
|
[[nodiscard]] const char *what() const noexcept override {
|
||||||
|
return "Seek option was used without a number";
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct Help {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct None {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Next {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Previous {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Refresh {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Exit {
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Seek {
|
||||||
|
int number;
|
||||||
|
};
|
||||||
|
|
||||||
|
using Command = std::variant<None, Help, Next, Previous, Refresh, Exit, Seek>;
|
||||||
|
|
||||||
|
Command readCommand();
|
||||||
|
}
|
@ -74,7 +74,7 @@ Page &Page::operator-=(int) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Page::str() const {
|
std::string Page::str_pretty() const {
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
std::istringstream stream(m_subpage);
|
std::istringstream stream(m_subpage);
|
||||||
|
@ -32,7 +32,7 @@ public:
|
|||||||
|
|
||||||
Page &operator-=(int);
|
Page &operator-=(int);
|
||||||
|
|
||||||
[[nodiscard]] std::string str() const;
|
[[nodiscard]] std::string str_pretty() const;
|
||||||
|
|
||||||
bool refresh();
|
bool refresh();
|
||||||
|
|
||||||
|
81
src/Tui.cpp
Normal file
81
src/Tui.cpp
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
#include "Tui.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <optional>
|
||||||
|
#include <ostream>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "Command.h"
|
||||||
|
|
||||||
|
Tui::Tui(Page page) : m_page(std::move(page)) {
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::optional<int> get_page_number(const std::string_view line) {
|
||||||
|
const size_t space = line.find_first_of(' ');
|
||||||
|
if (space == std::string::npos)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
int number = 0;
|
||||||
|
const size_t size = line.size();
|
||||||
|
for (size_t i = space; i < size; i++) {
|
||||||
|
const char c = line[i];
|
||||||
|
if (!std::isdigit(c))
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
number = number * 10 + (c - '0');
|
||||||
|
}
|
||||||
|
|
||||||
|
return number;
|
||||||
|
}
|
||||||
|
|
||||||
|
void printHelp() {
|
||||||
|
std::cout
|
||||||
|
<< "Available Commands:\n"
|
||||||
|
<< " r, refresh : Refresh the current view.\n"
|
||||||
|
<< " n, >, next : Move to the next item.\n"
|
||||||
|
<< " p, <, previous : Move to the previous item.\n"
|
||||||
|
<< " x, exit, q, quit : Exit the application.\n"
|
||||||
|
<< " seek <number>, s <number> : Seek to the specified number.\n"
|
||||||
|
<< " help, h, ? : Display this help message."
|
||||||
|
<< std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Tui::run() {
|
||||||
|
std::cout << m_page.str_pretty() << std::endl;
|
||||||
|
for (;;) {
|
||||||
|
std::cout << "Enter a command: ";
|
||||||
|
std::flush(std::cout);
|
||||||
|
const Command::Command command = Command::readCommand();
|
||||||
|
|
||||||
|
bool should_exit = false;
|
||||||
|
auto visitor = [this, &should_exit]<typename T0>(T0 &&arg) {
|
||||||
|
using T = std::decay_t<T0>;
|
||||||
|
|
||||||
|
if constexpr (std::is_same_v<T, Command::None>) {
|
||||||
|
std::cout << "Invalid command!" << std::endl;
|
||||||
|
} else if constexpr (std::is_same_v<T, Command::Next>) {
|
||||||
|
m_page += 1;
|
||||||
|
std::cout << m_page.str_pretty() << std::endl;
|
||||||
|
} else if constexpr (std::is_same_v<T, Command::Previous>) {
|
||||||
|
m_page -= 1;
|
||||||
|
std::cout << m_page.str_pretty() << std::endl;
|
||||||
|
} else if constexpr (std::is_same_v<T, Command::Refresh>) {
|
||||||
|
m_page.refresh();
|
||||||
|
std::cout << m_page.str_pretty() << std::endl;
|
||||||
|
} else if constexpr (std::is_same_v<T, Command::Exit>) {
|
||||||
|
should_exit = true;
|
||||||
|
} else if constexpr (std::is_same_v<T, Command::Help>) {
|
||||||
|
printHelp();
|
||||||
|
} else if constexpr (std::is_same_v<T, Command::Seek>) {
|
||||||
|
const Command::Seek &seek = arg;
|
||||||
|
const int number = seek.number;
|
||||||
|
m_page = Page(number);
|
||||||
|
std::cout << m_page.str_pretty() << std::endl;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
std::visit(visitor, command);
|
||||||
|
if (should_exit)
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
13
src/Tui.h
Normal file
13
src/Tui.h
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "Page.hpp"
|
||||||
|
|
||||||
|
|
||||||
|
class Tui {
|
||||||
|
public:
|
||||||
|
Tui(Page page);
|
||||||
|
|
||||||
|
void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
Page m_page;
|
||||||
|
};
|
@ -1,8 +1,7 @@
|
|||||||
#include <iostream>
|
|
||||||
|
|
||||||
#include "Page.hpp"
|
#include "Page.hpp"
|
||||||
|
#include "Tui.h"
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
const auto page = Page();
|
Tui tui = Page();
|
||||||
std::cout << page.str() << std::endl;
|
tui.run();
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user