help: move bilingual help text into module

This commit is contained in:
m1ngsama 2026-05-23 19:41:38 +08:00
parent 8009887be9
commit 4fb531771b
9 changed files with 251 additions and 171 deletions

1
.gitignore vendored
View file

@ -14,3 +14,4 @@ tests/unit/test_chat_room
tests/unit/test_history_view
tests/unit/test_i18n
tests/unit/test_system_message
tests/unit/test_help_text

View file

@ -27,6 +27,8 @@
`:mute-joins` filtering compatible with both Chinese and English logs.
- The interactive welcome screen now follows the selected UI language,
including the narrow-terminal fallback.
- Full-screen help and COMMAND-mode help now live in a dedicated `help_text`
module, keeping large bilingual help copy out of TUI and command flow code.
### Changed
- NORMAL mode now opens at the latest visible messages instead of the oldest

10
include/help_text.h Normal file
View file

@ -0,0 +1,10 @@
#ifndef HELP_TEXT_H
#define HELP_TEXT_H
#include "common.h"
const char *help_text_full(help_lang_t lang);
void help_text_append_commands(char *output, size_t buf_size, size_t *pos,
help_lang_t lang);
#endif /* HELP_TEXT_H */

View file

@ -33,6 +33,4 @@ void tui_clear_screen(struct client *client);
void tui_render_welcome(struct client *client);
/* Get help text based on language */
const char* tui_get_help_text(help_lang_t lang);
#endif /* TUI_H */

View file

@ -8,6 +8,7 @@
#include "chat_room.h"
#include "client.h"
#include "common.h"
#include "help_text.h"
#include "i18n.h"
#include "message.h"
#include "support.h"
@ -105,58 +106,6 @@ static const char *suggest_command(const char *cmd) {
return best_distance <= 2 ? best : NULL;
}
static void append_command_help(char *output, size_t buf_size, size_t *pos,
help_lang_t lang) {
if (lang == LANG_ZH) {
buffer_appendf(output, buf_size, pos,
"========================================\n"
" 可用命令\n"
"========================================\n"
"list, users, who - 显示在线用户\n"
"nick/name <name> - 修改昵称\n"
"msg/w <user> <text> - 私聊用户\n"
"inbox - 查看私聊历史\n"
"last [N] - 查看最近 N 条消息\n"
"search <keyword> - 搜索消息历史\n"
"mute-joins - 切换加入/离开提示\n"
"support - 显示快速支持指南\n"
"lang [en|zh] - 查看或切换界面语言\n"
"help, commands - 显示此帮助\n"
"clear, cls - 清空命令输出\n"
"q, quit, exit - 断开连接\n"
"上/下方向键 - 命令历史\n"
"========================================\n"
"INSERT 模式:\n"
" /me <action> - 发送动作消息\n"
" @username - 提及用户并响铃提示\n"
"========================================\n");
return;
}
buffer_appendf(output, buf_size, pos,
"========================================\n"
" Available Commands\n"
"========================================\n"
"list, users, who - Show online users\n"
"nick/name <name> - Change nickname\n"
"msg/w <user> <text> - Whisper to user (private)\n"
"inbox - Show whisper history\n"
"last [N] - Show last N messages\n"
"search <keyword> - Search message history\n"
"mute-joins - Toggle join/leave notices\n"
"support - Show quick support guide\n"
"lang [en|zh] - Show or switch UI language\n"
"help, commands - Show this help\n"
"clear, cls - Clear command output\n"
"q, quit, exit - Disconnect\n"
"Up/Down arrows - Command history\n"
"========================================\n"
"In INSERT mode:\n"
" /me <action> - Send action message\n"
" @username - Mention (bell notify)\n"
"========================================\n");
}
void commands_dispatch(client_t *client) {
char cmd_buf[256];
strncpy(cmd_buf, client->command_input, sizeof(cmd_buf) - 1);
@ -220,7 +169,8 @@ void commands_dispatch(client_t *client) {
pthread_rwlock_unlock(&g_room->lock);
} else if (strcmp(cmd, "help") == 0 || strcmp(cmd, "commands") == 0) {
append_command_help(output, sizeof(output), &pos, client->help_lang);
help_text_append_commands(output, sizeof(output), &pos,
client->help_lang);
} else if (strcmp(cmd, "support") == 0 || strcmp(cmd, "guide") == 0) {
support_append_interactive_panel(output, sizeof(output), &pos,

167
src/help_text.c Normal file
View file

@ -0,0 +1,167 @@
#include "help_text.h"
void help_text_append_commands(char *output, size_t buf_size, size_t *pos,
help_lang_t lang) {
if (lang == LANG_ZH) {
buffer_appendf(output, buf_size, pos,
"========================================\n"
" 可用命令\n"
"========================================\n"
"list, users, who - 显示在线用户\n"
"nick/name <name> - 修改昵称\n"
"msg/w <user> <text> - 私聊用户\n"
"inbox - 查看私聊历史\n"
"last [N] - 查看最近 N 条消息\n"
"search <keyword> - 搜索消息历史\n"
"mute-joins - 切换加入/离开提示\n"
"support - 显示快速支持指南\n"
"lang [en|zh] - 查看或切换界面语言\n"
"help, commands - 显示此帮助\n"
"clear, cls - 清空命令输出\n"
"q, quit, exit - 断开连接\n"
"上/下方向键 - 命令历史\n"
"========================================\n"
"INSERT 模式:\n"
" /me <action> - 发送动作消息\n"
" @username - 提及用户并响铃提示\n"
"========================================\n");
return;
}
buffer_appendf(output, buf_size, pos,
"========================================\n"
" Available Commands\n"
"========================================\n"
"list, users, who - Show online users\n"
"nick/name <name> - Change nickname\n"
"msg/w <user> <text> - Whisper to user (private)\n"
"inbox - Show whisper history\n"
"last [N] - Show last N messages\n"
"search <keyword> - Search message history\n"
"mute-joins - Toggle join/leave notices\n"
"support - Show quick support guide\n"
"lang [en|zh] - Show or switch UI language\n"
"help, commands - Show this help\n"
"clear, cls - Clear command output\n"
"q, quit, exit - Disconnect\n"
"Up/Down arrows - Command history\n"
"========================================\n"
"In INSERT mode:\n"
" /me <action> - Send action message\n"
" @username - Mention (bell notify)\n"
"========================================\n");
}
const char *help_text_full(help_lang_t lang) {
if (lang == LANG_EN) {
return "TERMINAL CHAT ROOM - HELP\n"
"\n"
"OPERATING MODES:\n"
" INSERT - Type and send messages (default)\n"
" NORMAL - Browse message history\n"
" COMMAND - Execute commands\n"
"\n"
"INSERT MODE KEYS:\n"
" ESC - Enter NORMAL mode\n"
" Enter - Send message\n"
" Backspace - Delete character\n"
" Ctrl+W - Delete last word\n"
" Ctrl+U - Delete line\n"
" Ctrl+C - Enter NORMAL mode\n"
"\n"
"NORMAL MODE KEYS:\n"
" Opens at latest messages\n"
" Follows latest until you scroll up\n"
" i - Return to INSERT mode\n"
" : - Enter COMMAND mode\n"
" j/k - Scroll down/up one line\n"
" Ctrl+D/U - Scroll half page down/up\n"
" Ctrl+F/B - Scroll full page down/up\n"
" PgDn/PgUp - Scroll full page down/up\n"
" End/Home - Jump to bottom/top\n"
" g/G - Jump to top/bottom\n"
" ? - Show this help\n"
" Ctrl+C - Exit chat\n"
"\n"
"AVAILABLE COMMANDS:\n"
" :list, :users - Show online users\n"
" :nick <name> - Change nickname\n"
" :msg <user> <text> - Whisper to user\n"
" :w <user> <text> - Short alias for :msg\n"
" :last [N] - Show last N messages (max 50)\n"
" :search <keyword> - Search message history\n"
" :mute-joins - Toggle join/leave notices\n"
" :support - Show quick support guide\n"
" :lang <en|zh> - Switch UI language\n"
" :help - Show available commands\n"
" :clear - Clear command output\n"
" :q, :quit, :exit - Disconnect\n"
"\n"
"SPECIAL MESSAGES:\n"
" /me <action> - Send action (e.g. /me waves)\n"
" @username - Mention user (bell + highlight)\n"
"\n"
"HELP SCREEN KEYS:\n"
" q, ESC - Close help\n"
" j/k - Scroll down/up\n"
" Ctrl+D/U - Scroll half page down/up\n"
" Ctrl+F/B - Scroll full page down/up\n"
" g/G - Jump to top/bottom\n"
" e/z - Switch English/Chinese\n";
}
return "终端聊天室 - 帮助\n"
"\n"
"操作模式:\n"
" INSERT - 输入和发送消息(默认)\n"
" NORMAL - 浏览消息历史\n"
" COMMAND - 执行命令\n"
"\n"
"INSERT 模式按键:\n"
" ESC - 进入 NORMAL 模式\n"
" Enter - 发送消息\n"
" Backspace - 删除字符\n"
" Ctrl+W - 删除上个单词\n"
" Ctrl+U - 删除整行\n"
" Ctrl+C - 进入 NORMAL 模式\n"
"\n"
"NORMAL 模式按键:\n"
" 默认停在最新消息\n"
" 未向上翻阅时自动跟随最新消息\n"
" i - 返回 INSERT 模式\n"
" : - 进入 COMMAND 模式\n"
" j/k - 向下/上滚动一行\n"
" Ctrl+D/U - 向下/上滚动半页\n"
" Ctrl+F/B - 向下/上滚动整页\n"
" PgDn/PgUp - 向下/上滚动整页\n"
" End/Home - 跳到底部/顶部\n"
" g/G - 跳到顶部/底部\n"
" ? - 显示此帮助\n"
" Ctrl+C - 退出聊天\n"
"\n"
"可用命令:\n"
" :list, :users - 显示在线用户\n"
" :nick <名字> - 更改昵称\n"
" :msg <用户> <文本> - 私聊\n"
" :w <用户> <文本> - :msg 的简写\n"
" :last [N] - 显示最后 N 条消息(最多50)\n"
" :search <关键词> - 搜索消息历史\n"
" :mute-joins - 切换加入/离开提示\n"
" :support - 显示快速支持指南\n"
" :lang <en|zh> - 切换界面语言\n"
" :help - 显示可用命令\n"
" :clear - 清空命令输出\n"
" :q, :quit, :exit - 断开连接\n"
"\n"
"特殊消息:\n"
" /me <动作> - 发送动作 (如 /me 挥手)\n"
" @用户名 - 提及用户 (响铃+高亮)\n"
"\n"
"帮助界面按键:\n"
" q, ESC - 关闭帮助\n"
" j/k - 向下/上滚动\n"
" Ctrl+D/U - 向下/上滚动半页\n"
" Ctrl+F/B - 向下/上滚动整页\n"
" g/G - 跳到顶部/底部\n"
" e/z - 切换英文/中文\n";
}

117
src/tui.c
View file

@ -2,6 +2,7 @@
#include "client.h"
#include "ssh_server.h"
#include "chat_room.h"
#include "help_text.h"
#include "history_view.h"
#include "i18n.h"
#include "system_message.h"
@ -748,120 +749,6 @@ void tui_render_motd(client_t *client) {
client_send(client, buffer, pos);
}
const char* tui_get_help_text(help_lang_t lang) {
if (lang == LANG_EN) {
return "TERMINAL CHAT ROOM - HELP\n"
"\n"
"OPERATING MODES:\n"
" INSERT - Type and send messages (default)\n"
" NORMAL - Browse message history\n"
" COMMAND - Execute commands\n"
"\n"
"INSERT MODE KEYS:\n"
" ESC - Enter NORMAL mode\n"
" Enter - Send message\n"
" Backspace - Delete character\n"
" Ctrl+W - Delete last word\n"
" Ctrl+U - Delete line\n"
" Ctrl+C - Enter NORMAL mode\n"
"\n"
"NORMAL MODE KEYS:\n"
" Opens at latest messages\n"
" Follows latest until you scroll up\n"
" i - Return to INSERT mode\n"
" : - Enter COMMAND mode\n"
" j/k - Scroll down/up one line\n"
" Ctrl+D/U - Scroll half page down/up\n"
" Ctrl+F/B - Scroll full page down/up\n"
" PgDn/PgUp - Scroll full page down/up\n"
" End/Home - Jump to bottom/top\n"
" g/G - Jump to top/bottom\n"
" ? - Show this help\n"
" Ctrl+C - Exit chat\n"
"\n"
"AVAILABLE COMMANDS:\n"
" :list, :users - Show online users\n"
" :nick <name> - Change nickname\n"
" :msg <user> <text> - Whisper to user\n"
" :w <user> <text> - Short alias for :msg\n"
" :last [N] - Show last N messages (max 50)\n"
" :search <keyword> - Search message history\n"
" :mute-joins - Toggle join/leave notices\n"
" :support - Show quick support guide\n"
" :lang <en|zh> - Switch UI language\n"
" :help - Show available commands\n"
" :clear - Clear command output\n"
" :q, :quit, :exit - Disconnect\n"
"\n"
"SPECIAL MESSAGES:\n"
" /me <action> - Send action (e.g. /me waves)\n"
" @username - Mention user (bell + highlight)\n"
"\n"
"HELP SCREEN KEYS:\n"
" q, ESC - Close help\n"
" j/k - Scroll down/up\n"
" Ctrl+D/U - Scroll half page down/up\n"
" Ctrl+F/B - Scroll full page down/up\n"
" g/G - Jump to top/bottom\n"
" e/z - Switch English/Chinese\n";
} else {
return "终端聊天室 - 帮助\n"
"\n"
"操作模式:\n"
" INSERT - 输入和发送消息(默认)\n"
" NORMAL - 浏览消息历史\n"
" COMMAND - 执行命令\n"
"\n"
"INSERT 模式按键:\n"
" ESC - 进入 NORMAL 模式\n"
" Enter - 发送消息\n"
" Backspace - 删除字符\n"
" Ctrl+W - 删除上个单词\n"
" Ctrl+U - 删除整行\n"
" Ctrl+C - 进入 NORMAL 模式\n"
"\n"
"NORMAL 模式按键:\n"
" 默认停在最新消息\n"
" 未向上翻阅时自动跟随最新消息\n"
" i - 返回 INSERT 模式\n"
" : - 进入 COMMAND 模式\n"
" j/k - 向下/上滚动一行\n"
" Ctrl+D/U - 向下/上滚动半页\n"
" Ctrl+F/B - 向下/上滚动整页\n"
" PgDn/PgUp - 向下/上滚动整页\n"
" End/Home - 跳到底部/顶部\n"
" g/G - 跳到顶部/底部\n"
" ? - 显示此帮助\n"
" Ctrl+C - 退出聊天\n"
"\n"
"可用命令:\n"
" :list, :users - 显示在线用户\n"
" :nick <名字> - 更改昵称\n"
" :msg <用户> <文本> - 私聊\n"
" :w <用户> <文本> - :msg 的简写\n"
" :last [N] - 显示最后 N 条消息(最多50)\n"
" :search <关键词> - 搜索消息历史\n"
" :mute-joins - 切换加入/离开提示\n"
" :support - 显示快速支持指南\n"
" :lang <en|zh> - 切换界面语言\n"
" :help - 显示可用命令\n"
" :clear - 清空命令输出\n"
" :q, :quit, :exit - 断开连接\n"
"\n"
"特殊消息:\n"
" /me <动作> - 发送动作 (如 /me 挥手)\n"
" @用户名 - 提及用户 (响铃+高亮)\n"
"\n"
"帮助界面按键:\n"
" q, ESC - 关闭帮助\n"
" j/k - 向下/上滚动\n"
" Ctrl+D/U - 向下/上滚动半页\n"
" Ctrl+F/B - 向下/上滚动整页\n"
" g/G - 跳到顶部/底部\n"
" e/z - 切换英文/中文\n";
}
}
/* Render the help screen */
void tui_render_help(client_t *client) {
if (!client || !client->connected) return;
@ -891,7 +778,7 @@ void tui_render_help(client_t *client) {
buffer_appendf(buffer, sizeof(buffer), &pos, ANSI_RESET "\r\n");
/* Help content */
const char *help_text = tui_get_help_text(client->help_lang);
const char *help_text = help_text_full(client->help_lang);
char help_copy[8192];
strncpy(help_copy, help_text, sizeof(help_copy) - 1);
help_copy[sizeof(help_copy) - 1] = '\0';

View file

@ -17,8 +17,9 @@ CHAT_ROOM_SRC = ../../src/chat_room.c
HISTORY_VIEW_SRC = ../../src/history_view.c
I18N_SRC = ../../src/i18n.c
SYSTEM_MESSAGE_SRC = ../../src/system_message.c
HELP_TEXT_SRC = ../../src/help_text.c
TESTS = test_utf8 test_message test_chat_room test_history_view test_i18n test_system_message
TESTS = test_utf8 test_message test_chat_room test_history_view test_i18n test_system_message test_help_text
.PHONY: all clean run
@ -42,6 +43,9 @@ test_i18n: test_i18n.c $(I18N_SRC)
test_system_message: test_system_message.c $(SYSTEM_MESSAGE_SRC) $(I18N_SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
test_help_text: test_help_text.c $(HELP_TEXT_SRC) $(COMMON_SRC)
$(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS)
run: all
@echo "=== Running UTF-8 Tests ==="
./test_utf8
@ -60,6 +64,9 @@ run: all
@echo ""
@echo "=== Running System Message Tests ==="
./test_system_message
@echo ""
@echo "=== Running Help Text Tests ==="
./test_help_text
clean:
rm -f $(TESTS) *.o test_messages.log

View file

@ -0,0 +1,58 @@
/* Unit tests for help text ownership and language selection */
#include "../../include/help_text.h"
#include <assert.h>
#include <stdio.h>
#include <string.h>
#define TEST(name) static void test_##name()
#define RUN_TEST(name) do { \
printf("Running %s... ", #name); \
test_##name(); \
printf("\n"); \
tests_passed++; \
} while(0)
static int tests_passed = 0;
TEST(full_help_matches_language) {
const char *en = help_text_full(LANG_EN);
const char *zh = help_text_full(LANG_ZH);
assert(strstr(en, "TERMINAL CHAT ROOM - HELP") != NULL);
assert(strstr(en, "AVAILABLE COMMANDS") != NULL);
assert(strstr(en, "Switch English/Chinese") != NULL);
assert(strstr(zh, "终端聊天室 - 帮助") != NULL);
assert(strstr(zh, "可用命令") != NULL);
assert(strstr(zh, "切换英文/中文") != NULL);
}
TEST(command_help_matches_language) {
char out[2048];
size_t pos;
out[0] = '\0';
pos = 0;
help_text_append_commands(out, sizeof(out), &pos, LANG_EN);
assert(strstr(out, "Available Commands") != NULL);
assert(strstr(out, "Show online users") != NULL);
assert(pos == strlen(out));
out[0] = '\0';
pos = 0;
help_text_append_commands(out, sizeof(out), &pos, LANG_ZH);
assert(strstr(out, "可用命令") != NULL);
assert(strstr(out, "显示在线用户") != NULL);
assert(pos == strlen(out));
}
int main(void) {
printf("Running help text unit tests...\n\n");
RUN_TEST(full_help_matches_language);
RUN_TEST(command_help_matches_language);
printf("\n✓ All %d tests passed!\n", tests_passed);
return 0;
}