mirror of
https://github.com/m1ngsama/TUT.git
synced 2025-12-24 10:51:46 +00:00
refactor: Improve code quality and Unix philosophy
- Remove redundant comments for cleaner code - Simplify error messages and status display - Improve code consistency across modules - Fix GitHub Actions workflow binary names - Enhance .gitignore for common editor files - Align help text formatting - Remove unnecessary verbose comments
This commit is contained in:
parent
ab2d1932e4
commit
ef80f9ab82
6 changed files with 36 additions and 81 deletions
14
.github/workflows/release.yml
vendored
14
.github/workflows/release.yml
vendored
|
|
@ -47,13 +47,13 @@ jobs:
|
|||
|
||||
- name: Rename binary with platform suffix
|
||||
run: |
|
||||
mv build/nbtca_tui build/nbtca_tui-${{ matrix.name }}
|
||||
mv build/tut build/tut-${{ matrix.name }}
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: nbtca_tui-${{ matrix.name }}
|
||||
path: build/nbtca_tui-${{ matrix.name }}
|
||||
name: tut-${{ matrix.name }}
|
||||
path: build/tut-${{ matrix.name }}
|
||||
|
||||
release:
|
||||
needs: build
|
||||
|
|
@ -85,13 +85,13 @@ jobs:
|
|||
Automated release for commit ${{ github.sha }}
|
||||
|
||||
## Download
|
||||
- **macOS**: `nbtca_tui-macos`
|
||||
- **Linux**: `nbtca_tui-linux`
|
||||
- **macOS**: `tut-macos`
|
||||
- **Linux**: `tut-linux`
|
||||
|
||||
## Build from source
|
||||
See the [README](https://github.com/${{ github.repository }}/blob/main/README.md) for build instructions.
|
||||
files: |
|
||||
artifacts/nbtca_tui-macos/nbtca_tui-macos
|
||||
artifacts/nbtca_tui-linux/nbtca_tui-linux
|
||||
artifacts/tut-macos/tut-macos
|
||||
artifacts/tut-linux/tut-linux
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
|
|
|||
5
.gitignore
vendored
5
.gitignore
vendored
|
|
@ -2,3 +2,8 @@ build/
|
|||
*.o
|
||||
tut
|
||||
.DS_Store
|
||||
*.swp
|
||||
*.swo
|
||||
*~
|
||||
.vscode/
|
||||
.idea/
|
||||
|
|
|
|||
|
|
@ -52,9 +52,9 @@ public:
|
|||
auto response = http_client.fetch(url);
|
||||
|
||||
if (!response.is_success()) {
|
||||
status_message = "Error: " + (response.error_message.empty() ?
|
||||
status_message = response.error_message.empty() ?
|
||||
"HTTP " + std::to_string(response.status_code) :
|
||||
response.error_message);
|
||||
response.error_message;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -65,14 +65,13 @@ public:
|
|||
current_link = -1;
|
||||
search_results.clear();
|
||||
|
||||
// 更新历史
|
||||
if (history_pos >= 0 && history_pos < static_cast<int>(history.size()) - 1) {
|
||||
history.erase(history.begin() + history_pos + 1, history.end());
|
||||
}
|
||||
history.push_back(url);
|
||||
history_pos = history.size() - 1;
|
||||
|
||||
status_message = "Loaded: " + (current_doc.title.empty() ? url : current_doc.title);
|
||||
status_message = current_doc.title.empty() ? url : current_doc.title;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
@ -80,7 +79,6 @@ public:
|
|||
attron(COLOR_PAIR(COLOR_STATUS_BAR));
|
||||
mvprintw(screen_height - 1, 0, "%s", std::string(screen_width, ' ').c_str());
|
||||
|
||||
// 显示模式和缓冲
|
||||
std::string mode_str;
|
||||
InputMode mode = input_handler.get_mode();
|
||||
switch (mode) {
|
||||
|
|
@ -88,29 +86,24 @@ public:
|
|||
mode_str = "NORMAL";
|
||||
break;
|
||||
case InputMode::COMMAND:
|
||||
mode_str = input_handler.get_buffer();
|
||||
break;
|
||||
case InputMode::SEARCH:
|
||||
mode_str = input_handler.get_buffer();
|
||||
break;
|
||||
default:
|
||||
mode_str = "???";
|
||||
mode_str = "";
|
||||
break;
|
||||
}
|
||||
|
||||
// 左侧:模式或命令
|
||||
mvprintw(screen_height - 1, 0, " %s", mode_str.c_str());
|
||||
|
||||
// 中间:状态消息
|
||||
if (!status_message.empty() && mode == InputMode::NORMAL) {
|
||||
int msg_x = (screen_width - status_message.length()) / 2;
|
||||
if (msg_x < mode_str.length() + 2) {
|
||||
if (msg_x < static_cast<int>(mode_str.length()) + 2) {
|
||||
msg_x = mode_str.length() + 2;
|
||||
}
|
||||
mvprintw(screen_height - 1, msg_x, "%s", status_message.c_str());
|
||||
}
|
||||
|
||||
// 右侧:位置信息
|
||||
int total_lines = rendered_lines.size();
|
||||
int visible_lines = screen_height - 2;
|
||||
int percentage = 0;
|
||||
|
|
@ -147,7 +140,6 @@ public:
|
|||
int line_idx = scroll_pos + i;
|
||||
const auto& line = rendered_lines[line_idx];
|
||||
|
||||
// 高亮当前链接
|
||||
if (line.is_link && line.link_index == current_link) {
|
||||
attron(COLOR_PAIR(COLOR_LINK_ACTIVE));
|
||||
} else {
|
||||
|
|
@ -157,15 +149,12 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
// 搜索高亮
|
||||
std::string display_text = line.text;
|
||||
if (!search_term.empty() &&
|
||||
std::find(search_results.begin(), search_results.end(), line_idx) != search_results.end()) {
|
||||
// 简单高亮:整行反色(实际应该只高亮匹配部分)
|
||||
attron(A_REVERSE);
|
||||
}
|
||||
|
||||
mvprintw(i, 0, "%s", display_text.c_str());
|
||||
mvprintw(i, 0, "%s", line.text.c_str());
|
||||
|
||||
if (!search_term.empty() &&
|
||||
std::find(search_results.begin(), search_results.end(), line_idx) != search_results.end()) {
|
||||
|
|
@ -225,7 +214,6 @@ public:
|
|||
case Action::NEXT_LINK:
|
||||
if (!current_doc.links.empty()) {
|
||||
current_link = (current_link + 1) % current_doc.links.size();
|
||||
// 滚动到链接位置
|
||||
scroll_to_link(current_link);
|
||||
}
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -23,22 +23,18 @@ public:
|
|||
result.has_count = false;
|
||||
result.count = 1;
|
||||
|
||||
// 处理数字前缀
|
||||
if (std::isdigit(ch) && (ch != '0' || !count_buffer.empty())) {
|
||||
count_buffer += static_cast<char>(ch);
|
||||
return result;
|
||||
}
|
||||
|
||||
// 解析count
|
||||
if (!count_buffer.empty()) {
|
||||
result.has_count = true;
|
||||
result.count = std::stoi(count_buffer);
|
||||
count_buffer.clear();
|
||||
}
|
||||
|
||||
// 处理vim风格的命令
|
||||
switch (ch) {
|
||||
// 移动
|
||||
case 'j':
|
||||
case KEY_DOWN:
|
||||
result.action = Action::SCROLL_DOWN;
|
||||
|
|
@ -55,18 +51,14 @@ public:
|
|||
case KEY_RIGHT:
|
||||
result.action = Action::GO_FORWARD;
|
||||
break;
|
||||
|
||||
// 翻页
|
||||
case 4: // Ctrl-D
|
||||
case 4:
|
||||
case ' ':
|
||||
result.action = Action::SCROLL_PAGE_DOWN;
|
||||
break;
|
||||
case 21: // Ctrl-U
|
||||
case 21:
|
||||
case 'b':
|
||||
result.action = Action::SCROLL_PAGE_UP;
|
||||
break;
|
||||
|
||||
// 跳转
|
||||
case 'g':
|
||||
buffer += 'g';
|
||||
if (buffer == "gg") {
|
||||
|
|
@ -82,8 +74,6 @@ public:
|
|||
result.action = Action::GOTO_BOTTOM;
|
||||
}
|
||||
break;
|
||||
|
||||
// 搜索
|
||||
case '/':
|
||||
mode = InputMode::SEARCH;
|
||||
buffer = "/";
|
||||
|
|
@ -94,27 +84,21 @@ public:
|
|||
case 'N':
|
||||
result.action = Action::SEARCH_PREV;
|
||||
break;
|
||||
|
||||
// 链接导航
|
||||
case '\t': // Tab
|
||||
case '\t':
|
||||
result.action = Action::NEXT_LINK;
|
||||
break;
|
||||
case KEY_BTAB: // Shift-Tab (可能不是所有终端都支持)
|
||||
case KEY_BTAB:
|
||||
case 'T':
|
||||
result.action = Action::PREV_LINK;
|
||||
break;
|
||||
case '\n': // Enter
|
||||
case '\n':
|
||||
case '\r':
|
||||
result.action = Action::FOLLOW_LINK;
|
||||
break;
|
||||
|
||||
// 命令模式
|
||||
case ':':
|
||||
mode = InputMode::COMMAND;
|
||||
buffer = ":";
|
||||
break;
|
||||
|
||||
// 其他操作
|
||||
case 'r':
|
||||
result.action = Action::REFRESH;
|
||||
break;
|
||||
|
|
@ -124,7 +108,6 @@ public:
|
|||
case '?':
|
||||
result.action = Action::HELP;
|
||||
break;
|
||||
|
||||
default:
|
||||
buffer.clear();
|
||||
break;
|
||||
|
|
@ -138,8 +121,7 @@ public:
|
|||
result.action = Action::NONE;
|
||||
|
||||
if (ch == '\n' || ch == '\r') {
|
||||
// 执行命令
|
||||
std::string command = buffer.substr(1); // 去掉':'
|
||||
std::string command = buffer.substr(1);
|
||||
|
||||
if (command == "q" || command == "quit") {
|
||||
result.action = Action::QUIT;
|
||||
|
|
@ -148,14 +130,12 @@ public:
|
|||
} else if (command == "r" || command == "refresh") {
|
||||
result.action = Action::REFRESH;
|
||||
} else if (command.rfind("o ", 0) == 0 || command.rfind("open ", 0) == 0) {
|
||||
// :o URL 或 :open URL
|
||||
size_t space_pos = command.find(' ');
|
||||
if (space_pos != std::string::npos) {
|
||||
result.action = Action::OPEN_URL;
|
||||
result.text = command.substr(space_pos + 1);
|
||||
}
|
||||
} else if (!command.empty() && std::isdigit(command[0])) {
|
||||
// 跳转到行号
|
||||
try {
|
||||
result.action = Action::GOTO_LINE;
|
||||
result.number = std::stoi(command);
|
||||
|
|
@ -166,7 +146,7 @@ public:
|
|||
|
||||
mode = InputMode::NORMAL;
|
||||
buffer.clear();
|
||||
} else if (ch == 27) { // ESC
|
||||
} else if (ch == 27) {
|
||||
mode = InputMode::NORMAL;
|
||||
buffer.clear();
|
||||
} else if (ch == KEY_BACKSPACE || ch == 127 || ch == 8) {
|
||||
|
|
@ -188,14 +168,13 @@ public:
|
|||
result.action = Action::NONE;
|
||||
|
||||
if (ch == '\n' || ch == '\r') {
|
||||
// 执行搜索
|
||||
if (buffer.length() > 1) {
|
||||
result.action = Action::SEARCH_FORWARD;
|
||||
result.text = buffer.substr(1); // 去掉'/'
|
||||
result.text = buffer.substr(1);
|
||||
}
|
||||
mode = InputMode::NORMAL;
|
||||
buffer.clear();
|
||||
} else if (ch == 27) { // ESC
|
||||
} else if (ch == 27) {
|
||||
mode = InputMode::NORMAL;
|
||||
buffer.clear();
|
||||
} else if (ch == KEY_BACKSPACE || ch == 127 || ch == 8) {
|
||||
|
|
|
|||
|
|
@ -24,7 +24,6 @@ void print_usage(const char* prog_name) {
|
|||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
// 解析命令行参数
|
||||
std::string initial_url;
|
||||
|
||||
if (argc > 1) {
|
||||
|
|
|
|||
|
|
@ -7,7 +7,6 @@ class TextRenderer::Impl {
|
|||
public:
|
||||
RenderConfig config;
|
||||
|
||||
// 自动换行处理
|
||||
std::vector<std::string> wrap_text(const std::string& text, int width) {
|
||||
std::vector<std::string> lines;
|
||||
if (text.empty()) {
|
||||
|
|
@ -19,20 +18,17 @@ public:
|
|||
std::string current_line;
|
||||
|
||||
while (words_stream >> word) {
|
||||
// 处理单个词超长的情况
|
||||
if (word.length() > static_cast<size_t>(width)) {
|
||||
if (!current_line.empty()) {
|
||||
lines.push_back(current_line);
|
||||
current_line.clear();
|
||||
}
|
||||
// 强制分割长词
|
||||
for (size_t i = 0; i < word.length(); i += width) {
|
||||
lines.push_back(word.substr(i, width));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
// 正常换行逻辑
|
||||
if (current_line.empty()) {
|
||||
current_line = word;
|
||||
} else if (current_line.length() + 1 + word.length() <= static_cast<size_t>(width)) {
|
||||
|
|
@ -54,7 +50,6 @@ public:
|
|||
return lines;
|
||||
}
|
||||
|
||||
// 添加缩进
|
||||
std::string add_indent(const std::string& text, int indent) {
|
||||
return std::string(indent, ' ') + text;
|
||||
}
|
||||
|
|
@ -69,20 +64,17 @@ TextRenderer::~TextRenderer() = default;
|
|||
std::vector<RenderedLine> TextRenderer::render(const ParsedDocument& doc, int screen_width) {
|
||||
std::vector<RenderedLine> lines;
|
||||
|
||||
// 计算实际内容宽度
|
||||
int content_width = std::min(pImpl->config.max_width, screen_width - 4);
|
||||
if (content_width < 40) {
|
||||
content_width = screen_width - 4;
|
||||
}
|
||||
|
||||
// 计算左边距(如果居中)
|
||||
int margin = 0;
|
||||
if (pImpl->config.center_content && content_width < screen_width) {
|
||||
margin = (screen_width - content_width) / 2;
|
||||
}
|
||||
pImpl->config.margin_left = margin;
|
||||
|
||||
// 渲染标题
|
||||
if (!doc.title.empty()) {
|
||||
RenderedLine title_line;
|
||||
title_line.text = std::string(margin, ' ') + doc.title;
|
||||
|
|
@ -92,7 +84,6 @@ std::vector<RenderedLine> TextRenderer::render(const ParsedDocument& doc, int sc
|
|||
title_line.link_index = -1;
|
||||
lines.push_back(title_line);
|
||||
|
||||
// 标题下划线
|
||||
RenderedLine underline;
|
||||
underline.text = std::string(margin, ' ') + std::string(std::min((int)doc.title.length(), content_width), '=');
|
||||
underline.color_pair = COLOR_HEADING1;
|
||||
|
|
@ -101,7 +92,6 @@ std::vector<RenderedLine> TextRenderer::render(const ParsedDocument& doc, int sc
|
|||
underline.link_index = -1;
|
||||
lines.push_back(underline);
|
||||
|
||||
// 空行
|
||||
RenderedLine empty;
|
||||
empty.text = "";
|
||||
empty.color_pair = COLOR_NORMAL;
|
||||
|
|
@ -111,7 +101,6 @@ std::vector<RenderedLine> TextRenderer::render(const ParsedDocument& doc, int sc
|
|||
lines.push_back(empty);
|
||||
}
|
||||
|
||||
// 渲染URL
|
||||
if (!doc.url.empty()) {
|
||||
RenderedLine url_line;
|
||||
url_line.text = std::string(margin, ' ') + "URL: " + doc.url;
|
||||
|
|
@ -130,7 +119,6 @@ std::vector<RenderedLine> TextRenderer::render(const ParsedDocument& doc, int sc
|
|||
lines.push_back(empty);
|
||||
}
|
||||
|
||||
// 渲染内容元素
|
||||
for (const auto& elem : doc.elements) {
|
||||
int color = COLOR_NORMAL;
|
||||
bool bold = false;
|
||||
|
|
@ -179,7 +167,6 @@ std::vector<RenderedLine> TextRenderer::render(const ParsedDocument& doc, int sc
|
|||
break;
|
||||
}
|
||||
|
||||
// 换行处理
|
||||
auto wrapped_lines = pImpl->wrap_text(elem.text, content_width - prefix.length());
|
||||
for (size_t i = 0; i < wrapped_lines.size(); ++i) {
|
||||
RenderedLine line;
|
||||
|
|
@ -195,7 +182,6 @@ std::vector<RenderedLine> TextRenderer::render(const ParsedDocument& doc, int sc
|
|||
lines.push_back(line);
|
||||
}
|
||||
|
||||
// 段落间距
|
||||
if (elem.type == ElementType::PARAGRAPH ||
|
||||
elem.type == ElementType::HEADING1 ||
|
||||
elem.type == ElementType::HEADING2 ||
|
||||
|
|
@ -212,7 +198,6 @@ std::vector<RenderedLine> TextRenderer::render(const ParsedDocument& doc, int sc
|
|||
}
|
||||
}
|
||||
|
||||
// 渲染链接列表
|
||||
if (!doc.links.empty() && pImpl->config.show_link_indicators) {
|
||||
RenderedLine separator;
|
||||
std::string sepline(content_width, '-');
|
||||
|
|
@ -254,7 +239,6 @@ std::vector<RenderedLine> TextRenderer::render(const ParsedDocument& doc, int sc
|
|||
lines.push_back(link_line);
|
||||
}
|
||||
|
||||
// URL on next line
|
||||
auto url_wrapped = pImpl->wrap_text(link.url, content_width - 6);
|
||||
for (const auto& url_line_text : url_wrapped) {
|
||||
RenderedLine url_line;
|
||||
|
|
|
|||
Loading…
Reference in a new issue