Refactor app modules and add clang-format

This commit is contained in:
2026-04-24 06:34:30 +03:00
parent 0de7073f00
commit 70c2e77957
12 changed files with 2354 additions and 2011 deletions

180
src/app_commands.cpp Normal file
View File

@@ -0,0 +1,180 @@
#include "app.h"
#include <algorithm>
#include <cctype>
#include <set>
#include <sstream>
#include "util.h"
namespace telegram_tui {
namespace {
bool starts_with_at(const std::string &text, std::size_t index, const char *prefix) {
const std::size_t prefix_size = std::char_traits<char>::length(prefix);
return text.compare(index, prefix_size, prefix) == 0;
}
} // namespace
std::int64_t App::resolve_message_ref(const ChatInfo &chat, std::int64_t ref) const {
if (ref > 0 && ref <= static_cast<std::int64_t>(chat.messages.size())) {
return chat.messages[static_cast<std::size_t>(ref - 1)].id;
}
for (const auto &message : chat.messages) {
if (message.id == ref) {
return message.id;
}
}
return 0;
}
std::tuple<bool, std::int64_t, std::string>
App::parse_single_message_command(const std::string &value, const char *prefix) const {
if (!starts_with_at(value, 0, prefix)) {
return {false, 0, value};
}
const std::size_t prefix_size = std::char_traits<char>::length(prefix);
std::size_t id_start = prefix_size;
while (id_start < value.size() && value[id_start] == ' ') {
++id_start;
}
std::size_t id_end = id_start;
while (id_end < value.size() && std::isdigit(static_cast<unsigned char>(value[id_end]))) {
++id_end;
}
if (id_end == id_start) {
return {true, 0, {}};
}
std::int64_t parsed_value = 0;
try {
parsed_value = std::stoll(value.substr(id_start, id_end - id_start));
} catch (...) {
return {true, 0, {}};
}
while (id_end < value.size() && value[id_end] == ' ') {
++id_end;
}
const auto chat_id = open_chat_id();
if (!chat_id.has_value()) {
return {true, 0, value.substr(id_end)};
}
const auto chat_it = chats_.find(*chat_id);
if (chat_it == chats_.end()) {
return {true, 0, value.substr(id_end)};
}
const ChatInfo &chat = chat_it->second;
return {true, resolve_message_ref(chat, parsed_value), value.substr(id_end)};
}
std::optional<std::vector<std::int64_t>> App::parse_message_list_command(const std::string &value,
const char *prefix) const {
if (!starts_with_at(value, 0, prefix)) {
return std::nullopt;
}
const std::size_t prefix_size = std::char_traits<char>::length(prefix);
std::string remainder = value.substr(prefix_size);
remainder = trim_copy(std::move(remainder));
if (remainder.empty()) {
return std::vector<std::int64_t>{};
}
const auto chat_id = open_chat_id();
if (!chat_id.has_value()) {
return std::vector<std::int64_t>{};
}
const auto chat_it = chats_.find(*chat_id);
if (chat_it == chats_.end()) {
return std::vector<std::int64_t>{};
}
const ChatInfo &chat = chat_it->second;
for (char &ch : remainder) {
if (ch == ',') {
ch = ' ';
}
}
std::set<std::int64_t> unique_message_ids;
std::stringstream stream(remainder);
std::string token;
while (stream >> token) {
const auto dash = token.find('-');
if (dash != std::string::npos) {
const std::string start_text = token.substr(0, dash);
const std::string end_text = token.substr(dash + 1);
if (!is_decimal_number(start_text) || !is_decimal_number(end_text)) {
return std::vector<std::int64_t>{};
}
std::int64_t start_value = 0;
std::int64_t end_value = 0;
try {
start_value = std::stoll(start_text);
end_value = std::stoll(end_text);
} catch (...) {
return std::vector<std::int64_t>{};
}
if (start_value > end_value) {
std::swap(start_value, end_value);
}
for (std::int64_t ref = start_value; ref <= end_value; ++ref) {
const std::int64_t message_id = resolve_message_ref(chat, ref);
if (message_id == 0) {
return std::vector<std::int64_t>{};
}
unique_message_ids.insert(message_id);
}
continue;
}
if (!is_decimal_number(token)) {
return std::vector<std::int64_t>{};
}
std::int64_t parsed_value = 0;
try {
parsed_value = std::stoll(token);
} catch (...) {
return std::vector<std::int64_t>{};
}
const std::int64_t message_id = resolve_message_ref(chat, parsed_value);
if (message_id == 0) {
return std::vector<std::int64_t>{};
}
unique_message_ids.insert(message_id);
}
return std::vector<std::int64_t>(unique_message_ids.begin(), unique_message_ids.end());
}
App::ComposeCommand App::parse_compose_command(const std::string &value) const {
if (const auto message_ids = parse_message_list_command(value, ">f ");
message_ids.has_value()) {
return ComposeCommand{ComposeCommandKind::Forward, 0, *message_ids, {}};
}
if (const auto message_ids = parse_message_list_command(value, ">d ");
message_ids.has_value()) {
return ComposeCommand{ComposeCommandKind::Delete, 0, *message_ids, {}};
}
if (const auto [matched, message_id, text] = parse_single_message_command(value, ">e ");
matched) {
return ComposeCommand{ComposeCommandKind::Edit, message_id, {}, text};
}
if (const auto [matched, message_id, text] = parse_single_message_command(value, ">r ");
matched) {
return ComposeCommand{ComposeCommandKind::Reply, message_id, {}, text};
}
return ComposeCommand{};
}
} // namespace telegram_tui