diff --git a/.gitignore b/.gitignore index f44737c..3b250d9 100644 --- a/.gitignore +++ b/.gitignore @@ -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 diff --git a/docs/CHANGELOG.md b/docs/CHANGELOG.md index 0ee3622..3a8bf03 100644 --- a/docs/CHANGELOG.md +++ b/docs/CHANGELOG.md @@ -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 diff --git a/include/help_text.h b/include/help_text.h new file mode 100644 index 0000000..232b854 --- /dev/null +++ b/include/help_text.h @@ -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 */ diff --git a/include/tui.h b/include/tui.h index b656971..c6ddf74 100644 --- a/include/tui.h +++ b/include/tui.h @@ -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 */ diff --git a/src/commands.c b/src/commands.c index 44eab1e..6da7262 100644 --- a/src/commands.c +++ b/src/commands.c @@ -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 - 修改昵称\n" - "msg/w - 私聊用户\n" - "inbox - 查看私聊历史\n" - "last [N] - 查看最近 N 条消息\n" - "search - 搜索消息历史\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 - 发送动作消息\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 - Change nickname\n" - "msg/w - Whisper to user (private)\n" - "inbox - Show whisper history\n" - "last [N] - Show last N messages\n" - "search - 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 - 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, diff --git a/src/help_text.c b/src/help_text.c new file mode 100644 index 0000000..710ad41 --- /dev/null +++ b/src/help_text.c @@ -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 - 修改昵称\n" + "msg/w - 私聊用户\n" + "inbox - 查看私聊历史\n" + "last [N] - 查看最近 N 条消息\n" + "search - 搜索消息历史\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 - 发送动作消息\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 - Change nickname\n" + "msg/w - Whisper to user (private)\n" + "inbox - Show whisper history\n" + "last [N] - Show last N messages\n" + "search - 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 - 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 - Change nickname\n" + " :msg - Whisper to user\n" + " :w - Short alias for :msg\n" + " :last [N] - Show last N messages (max 50)\n" + " :search - Search message history\n" + " :mute-joins - Toggle join/leave notices\n" + " :support - Show quick support guide\n" + " :lang - Switch UI language\n" + " :help - Show available commands\n" + " :clear - Clear command output\n" + " :q, :quit, :exit - Disconnect\n" + "\n" + "SPECIAL MESSAGES:\n" + " /me - 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 - 切换界面语言\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"; +} diff --git a/src/tui.c b/src/tui.c index 1bab30e..2aaf456 100644 --- a/src/tui.c +++ b/src/tui.c @@ -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 - Change nickname\n" - " :msg - Whisper to user\n" - " :w - Short alias for :msg\n" - " :last [N] - Show last N messages (max 50)\n" - " :search - Search message history\n" - " :mute-joins - Toggle join/leave notices\n" - " :support - Show quick support guide\n" - " :lang - Switch UI language\n" - " :help - Show available commands\n" - " :clear - Clear command output\n" - " :q, :quit, :exit - Disconnect\n" - "\n" - "SPECIAL MESSAGES:\n" - " /me - 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 - 切换界面语言\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'; diff --git a/tests/unit/Makefile b/tests/unit/Makefile index 67d04ca..8d314b2 100644 --- a/tests/unit/Makefile +++ b/tests/unit/Makefile @@ -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 diff --git a/tests/unit/test_help_text.c b/tests/unit/test_help_text.c new file mode 100644 index 0000000..12bfbdc --- /dev/null +++ b/tests/unit/test_help_text.c @@ -0,0 +1,58 @@ +/* Unit tests for help text ownership and language selection */ + +#include "../../include/help_text.h" +#include +#include +#include + +#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; +}