Compare commits
No commits in common. "40d98cdbb6bd5aa66897325ab04d3ede51b86ce0" and "c09929d2f732054ef0f5060371c13d2728cebdd5" have entirely different histories.
40d98cdbb6
...
c09929d2f7
@ -7,10 +7,6 @@ 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)
|
||||||
|
@ -1,51 +0,0 @@
|
|||||||
#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{}};
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
#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();
|
|
||||||
}
|
|
23
src/Page.cpp
23
src/Page.cpp
@ -19,44 +19,45 @@
|
|||||||
#include "libxml/xpath.h"
|
#include "libxml/xpath.h"
|
||||||
|
|
||||||
|
|
||||||
bool is_number(const std::string_view s) {
|
bool is_number(std::string_view s){
|
||||||
return std::ranges::all_of(s, [](const unsigned char c) {
|
return std::all_of(s.begin(), s.end(), [](unsigned char c ){
|
||||||
return std::isdigit(c);
|
return std::isdigit(c);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void italize_numbers(std::string &content, size_t leave_chars = 0) {
|
void italize_numbers(std::string &content, size_t leave_chars = 0) {
|
||||||
size_t end = content.size();
|
size_t end = content.size();
|
||||||
|
|
||||||
// Process backwards, word by word
|
// Process backwards, word by word
|
||||||
for (;;) {
|
for (;;) {
|
||||||
const size_t space = content.rfind(' ', end - 1);
|
size_t space = content.rfind(' ', end - 1);
|
||||||
const size_t begin = (space == std::string::npos) ? 0 : space + 1;
|
size_t begin = (space == std::string::npos) ? 0 : space + 1;
|
||||||
const size_t word_length = end - begin;
|
size_t word_length = end - begin;
|
||||||
|
|
||||||
if (is_number(content.substr(begin, word_length))) {
|
if (is_number(content.substr(begin, word_length))) {
|
||||||
content.insert(end, ansi::CLEAR);
|
content.insert(end, ansi::CLEAR);
|
||||||
content.insert(begin, ansi::ITALIC);
|
content.insert(begin, ansi::ITALIC);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (space == std::string::npos)
|
if (space == std::string::npos)
|
||||||
break;
|
break;
|
||||||
if (leave_chars >= space)
|
if (leave_chars >= space)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
end = space;
|
end = space;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void pretty_format_page(std::string &content) {
|
void pretty_format_page(std::string &content) {
|
||||||
content.insert(0, ansi::BOLD);
|
content.insert(0, ansi::BOLD);
|
||||||
const size_t line_end = content.find("\n");
|
size_t line_end = content.find("\n");
|
||||||
content.insert(line_end, ansi::CLEAR);
|
content.insert(line_end, ansi::CLEAR);
|
||||||
|
|
||||||
italize_numbers(content, line_end + ansi::CLEAR.size());
|
italize_numbers(content, line_end + ansi::CLEAR.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Page::Page(const uint_fast8_t number): m_number(number), m_subpage(fetchSubpage()) {
|
Page::Page(const uint_fast8_t number): m_number(number), m_subpage(fetchSubpage()) {
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,7 +75,7 @@ Page &Page::operator-=(int) {
|
|||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Page::str_pretty() const {
|
std::string Page::str() const {
|
||||||
std::string ret;
|
std::string ret;
|
||||||
|
|
||||||
std::istringstream stream(m_subpage);
|
std::istringstream stream(m_subpage);
|
||||||
|
@ -18,7 +18,7 @@ static constexpr uint_fast8_t MAX_WHITESPACE = 2;
|
|||||||
class Page
|
class Page
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
uint_fast8_t m_number;
|
uint_fast8_t m_number{};
|
||||||
std::string m_subpage;
|
std::string m_subpage;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -32,7 +32,7 @@ public:
|
|||||||
|
|
||||||
Page &operator-=(int);
|
Page &operator-=(int);
|
||||||
|
|
||||||
[[nodiscard]] std::string str_pretty() const;
|
std::string str() const;
|
||||||
|
|
||||||
bool refresh();
|
bool refresh();
|
||||||
|
|
||||||
@ -40,4 +40,6 @@ private:
|
|||||||
[[nodiscard]] std::string url() const;
|
[[nodiscard]] std::string url() const;
|
||||||
|
|
||||||
[[nodiscard]] std::string fetchSubpage() const;
|
[[nodiscard]] std::string fetchSubpage() const;
|
||||||
|
|
||||||
|
[[nodiscard]] bool contentEquals(const std::vector<std::string> &subpagesOther) const;
|
||||||
};
|
};
|
||||||
|
81
src/Tui.cpp
81
src/Tui.cpp
@ -1,81 +0,0 @@
|
|||||||
#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
13
src/Tui.h
@ -1,13 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
#include "Page.hpp"
|
|
||||||
|
|
||||||
|
|
||||||
class Tui {
|
|
||||||
public:
|
|
||||||
Tui(Page page);
|
|
||||||
|
|
||||||
void run();
|
|
||||||
|
|
||||||
private:
|
|
||||||
Page m_page;
|
|
||||||
};
|
|
@ -1,7 +1,8 @@
|
|||||||
|
#include <iostream>
|
||||||
|
|
||||||
#include "Page.hpp"
|
#include "Page.hpp"
|
||||||
#include "Tui.h"
|
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
Tui tui = Page();
|
const auto page = Page();
|
||||||
tui.run();
|
std::cout << page.str() << std::endl;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user