mirror of
https://github.com/m1ngsama/TUT.git
synced 2026-02-08 09:04:04 +00:00
Major architectural refactoring from ncurses to FTXUI framework with professional engineering structure. Project Structure: - src/core/: Browser engine, URL parser, HTTP client - src/ui/: FTXUI components (main window, address bar, content view, panels) - src/renderer/: HTML renderer, text formatter, style parser - src/utils/: Logger, config manager, theme manager - tests/unit/: Unit tests for core components - tests/integration/: Integration tests - assets/: Default configs, themes, keybindings New Features: - btop-style four-panel layout with rounded borders - TOML-based configuration system - Multiple color themes (default, nord, gruvbox, solarized) - Comprehensive logging system - Modular architecture with clear separation of concerns Build System: - Updated CMakeLists.txt for modular build - Prefer system packages (Homebrew) over FetchContent - Google Test integration for testing - Version info generation via cmake/version.hpp.in Configuration: - Default config.toml with browser settings - Four built-in themes - Default keybindings configuration - Config stored in ~/.config/tut/ Removed: - Legacy v1 source files (ncurses-based) - Old render/ directory - Duplicate and obsolete test files - Old documentation files Binary: ~827KB (well under 5MB goal) Dependencies: FTXUI, cpp-httplib, toml11, gumbo-parser, OpenSSL
152 lines
4 KiB
C++
152 lines
4 KiB
C++
/**
|
|
* @file text_formatter.cpp
|
|
* @brief 文本格式化实现
|
|
*/
|
|
|
|
#include "renderer/text_formatter.hpp"
|
|
#include <algorithm>
|
|
#include <sstream>
|
|
|
|
namespace tut {
|
|
|
|
std::vector<std::string> TextFormatter::wrapText(const std::string& text, int width) {
|
|
std::vector<std::string> lines;
|
|
if (width <= 0 || text.empty()) {
|
|
return lines;
|
|
}
|
|
|
|
std::istringstream iss(text);
|
|
std::string word;
|
|
std::string current_line;
|
|
|
|
while (iss >> word) {
|
|
if (current_line.empty()) {
|
|
current_line = word;
|
|
} else if (static_cast<int>(current_line.length() + 1 + word.length()) <= width) {
|
|
current_line += " " + word;
|
|
} else {
|
|
lines.push_back(current_line);
|
|
current_line = word;
|
|
}
|
|
}
|
|
|
|
if (!current_line.empty()) {
|
|
lines.push_back(current_line);
|
|
}
|
|
|
|
return lines;
|
|
}
|
|
|
|
std::string TextFormatter::alignLeft(const std::string& text, int width) {
|
|
if (static_cast<int>(text.length()) >= width) {
|
|
return text;
|
|
}
|
|
return text + std::string(width - text.length(), ' ');
|
|
}
|
|
|
|
std::string TextFormatter::alignRight(const std::string& text, int width) {
|
|
if (static_cast<int>(text.length()) >= width) {
|
|
return text;
|
|
}
|
|
return std::string(width - text.length(), ' ') + text;
|
|
}
|
|
|
|
std::string TextFormatter::alignCenter(const std::string& text, int width) {
|
|
if (static_cast<int>(text.length()) >= width) {
|
|
return text;
|
|
}
|
|
int padding = width - static_cast<int>(text.length());
|
|
int left_padding = padding / 2;
|
|
int right_padding = padding - left_padding;
|
|
return std::string(left_padding, ' ') + text + std::string(right_padding, ' ');
|
|
}
|
|
|
|
std::string TextFormatter::truncate(const std::string& text, size_t max_length,
|
|
const std::string& suffix) {
|
|
if (text.length() <= max_length) {
|
|
return text;
|
|
}
|
|
if (max_length <= suffix.length()) {
|
|
return suffix.substr(0, max_length);
|
|
}
|
|
return text.substr(0, max_length - suffix.length()) + suffix;
|
|
}
|
|
|
|
std::string TextFormatter::trim(const std::string& text) {
|
|
size_t start = text.find_first_not_of(" \t\n\r\f\v");
|
|
if (start == std::string::npos) {
|
|
return "";
|
|
}
|
|
size_t end = text.find_last_not_of(" \t\n\r\f\v");
|
|
return text.substr(start, end - start + 1);
|
|
}
|
|
|
|
int TextFormatter::displayWidth(const std::string& text) {
|
|
int width = 0;
|
|
for (size_t i = 0; i < text.length(); ) {
|
|
unsigned char c = text[i];
|
|
if ((c & 0x80) == 0) {
|
|
// ASCII
|
|
width += 1;
|
|
i += 1;
|
|
} else if ((c & 0xE0) == 0xC0) {
|
|
// 2-byte UTF-8
|
|
width += 1;
|
|
i += 2;
|
|
} else if ((c & 0xF0) == 0xE0) {
|
|
// 3-byte UTF-8 (CJK 字符通常是这种)
|
|
width += 2; // 假设是宽字符
|
|
i += 3;
|
|
} else if ((c & 0xF8) == 0xF0) {
|
|
// 4-byte UTF-8
|
|
width += 2;
|
|
i += 4;
|
|
} else {
|
|
width += 1;
|
|
i += 1;
|
|
}
|
|
}
|
|
return width;
|
|
}
|
|
|
|
std::string TextFormatter::expandTabs(const std::string& text, int tab_size) {
|
|
std::string result;
|
|
int column = 0;
|
|
|
|
for (char c : text) {
|
|
if (c == '\t') {
|
|
int spaces = tab_size - (column % tab_size);
|
|
result.append(spaces, ' ');
|
|
column += spaces;
|
|
} else if (c == '\n') {
|
|
result += c;
|
|
column = 0;
|
|
} else {
|
|
result += c;
|
|
column++;
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
std::string TextFormatter::normalizeWhitespace(const std::string& text) {
|
|
std::string result;
|
|
bool last_was_space = false;
|
|
|
|
for (char c : text) {
|
|
if (std::isspace(static_cast<unsigned char>(c))) {
|
|
if (!last_was_space) {
|
|
result += ' ';
|
|
last_was_space = true;
|
|
}
|
|
} else {
|
|
result += c;
|
|
last_was_space = false;
|
|
}
|
|
}
|
|
|
|
return trim(result);
|
|
}
|
|
|
|
} // namespace tut
|