mirror of
https://oauth2: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@github.com/m1ngsama/TNT.git
synced 2026-06-26 05:34:39 +08:00
tui: guide first-time users
This commit is contained in:
parent
69ddcd2d95
commit
36dbe8d549
5 changed files with 126 additions and 13 deletions
|
|
@ -26,6 +26,10 @@
|
|||
counting escape sequences as visible width or cutting color codes.
|
||||
- Host-key generation now uses the non-deprecated libssh PKI API on libssh
|
||||
0.12+ while keeping compatibility with older libssh releases.
|
||||
- INSERT mode now shows a lightweight first-use hint for sending, browsing,
|
||||
and `:support`.
|
||||
- `:support` is now task-oriented around common user goals, and mistyped
|
||||
commands suggest the nearest known command when possible.
|
||||
|
||||
## 2026-05-18 - Interactive input polish
|
||||
|
||||
|
|
|
|||
|
|
@ -44,6 +44,64 @@ static void append_highlighted(char *output, size_t buf_size, size_t *pos,
|
|||
}
|
||||
}
|
||||
|
||||
static int min3(int a, int b, int c) {
|
||||
int m = a < b ? a : b;
|
||||
return m < c ? m : c;
|
||||
}
|
||||
|
||||
static int command_edit_distance(const char *a, const char *b) {
|
||||
size_t la = strlen(a);
|
||||
size_t lb = strlen(b);
|
||||
int prev[32];
|
||||
int curr[32];
|
||||
|
||||
if (la >= 32 || lb >= 32) {
|
||||
return 99;
|
||||
}
|
||||
|
||||
for (size_t j = 0; j <= lb; j++) {
|
||||
prev[j] = (int)j;
|
||||
}
|
||||
|
||||
for (size_t i = 1; i <= la; i++) {
|
||||
curr[0] = (int)i;
|
||||
for (size_t j = 1; j <= lb; j++) {
|
||||
int cost = a[i - 1] == b[j - 1] ? 0 : 1;
|
||||
curr[j] = min3(prev[j] + 1, curr[j - 1] + 1,
|
||||
prev[j - 1] + cost);
|
||||
}
|
||||
for (size_t j = 0; j <= lb; j++) {
|
||||
prev[j] = curr[j];
|
||||
}
|
||||
}
|
||||
|
||||
return prev[lb];
|
||||
}
|
||||
|
||||
static const char *suggest_command(const char *cmd) {
|
||||
static const char *commands[] = {
|
||||
"list", "users", "who", "nick", "name", "msg", "w", "inbox",
|
||||
"last", "search", "mute-joins", "mute", "support", "guide",
|
||||
"help", "commands", "clear", "cls", "q", "quit", "exit"
|
||||
};
|
||||
const char *best = NULL;
|
||||
int best_distance = 99;
|
||||
|
||||
if (!cmd || !*cmd) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(commands) / sizeof(commands[0]); i++) {
|
||||
int distance = command_edit_distance(cmd, commands[i]);
|
||||
if (distance < best_distance) {
|
||||
best_distance = distance;
|
||||
best = commands[i];
|
||||
}
|
||||
}
|
||||
|
||||
return best_distance <= 2 ? best : NULL;
|
||||
}
|
||||
|
||||
void commands_dispatch(client_t *client) {
|
||||
char cmd_buf[256];
|
||||
strncpy(cmd_buf, client->command_input, sizeof(cmd_buf) - 1);
|
||||
|
|
@ -368,9 +426,15 @@ void commands_dispatch(client_t *client) {
|
|||
return;
|
||||
|
||||
} else {
|
||||
const char *suggestion = suggest_command(cmd);
|
||||
buffer_appendf(output, sizeof(output), &pos,
|
||||
"Unknown command: %s\n"
|
||||
"Type 'help' for available commands\n", cmd);
|
||||
"Unknown command: %s\n", cmd);
|
||||
if (suggestion) {
|
||||
buffer_appendf(output, sizeof(output), &pos,
|
||||
"Did you mean :%s?\n", suggestion);
|
||||
}
|
||||
buffer_appendf(output, sizeof(output), &pos,
|
||||
"Type :support for guidance or :help for commands\n");
|
||||
}
|
||||
|
||||
cmd_done:
|
||||
|
|
|
|||
|
|
@ -7,23 +7,25 @@ void support_append_interactive_panel(char *buffer, size_t buf_size,
|
|||
buffer_appendf(buffer, buf_size, pos,
|
||||
"\033[1;36m支持 · support\033[0m\n"
|
||||
"\n"
|
||||
"\033[1;37m快速开始\033[0m\n"
|
||||
"\033[1;37m第一次进来\033[0m\n"
|
||||
" INSERT 输入消息,Enter 发送,ESC 进入 NORMAL\n"
|
||||
" NORMAL 浏览消息,G 回到最新,i 继续输入\n"
|
||||
" COMMAND 按 : 输入命令,q/ESC 关闭当前面板\n"
|
||||
"\n"
|
||||
"\033[1;37m常用动作\033[0m\n"
|
||||
" :users 查看在线用户\n"
|
||||
" :last 20 查看最近 20 条历史\n"
|
||||
" :search <keyword> 搜索聊天记录\n"
|
||||
" :msg <user> <text> 私聊\n"
|
||||
" :inbox 查看私聊收件箱\n"
|
||||
" :mute-joins 静音加入/离开提示\n"
|
||||
"\033[1;37m我想...\033[0m\n"
|
||||
" 看谁在线 :users\n"
|
||||
" 看最近历史 :last 20\n"
|
||||
" 搜索聊天记录 :search <keyword>\n"
|
||||
" 回到最新消息 G 或 End\n"
|
||||
" 私聊某个人 :msg <user> <text>\n"
|
||||
" 查看私聊收件箱 :inbox\n"
|
||||
" 静音进出提示 :mute-joins\n"
|
||||
"\n"
|
||||
"\033[1;37m遇到问题\033[0m\n"
|
||||
" 看不到新消息: 在 NORMAL 按 G 或 End 回到最新\n"
|
||||
" 粘贴多行文本: 直接粘贴,TNT 会等 Enter 后一次发送\n"
|
||||
" 输入太长: 状态行接近限制时会提示,超出会响铃\n"
|
||||
" 命令不记得: 输入 :help 看列表,输入 :support 回到这里\n"
|
||||
" 连接断开: 可能是空闲超时、连接数限制或网络重连\n"
|
||||
"\n"
|
||||
"\033[2;37m更多: ? 打开完整按键帮助,:help 查看命令列表\033[0m\n");
|
||||
|
|
|
|||
|
|
@ -7,7 +7,18 @@ void tui_status_append(char *buffer, size_t buf_size, size_t *pos,
|
|||
if (!buffer || !pos || !client) return;
|
||||
|
||||
if (client->mode == MODE_INSERT) {
|
||||
buffer_appendf(buffer, buf_size, pos, "\033[2;37m›\033[0m \033[K");
|
||||
if (client->width >= 58) {
|
||||
buffer_appendf(buffer, buf_size, pos,
|
||||
"\033[2;37m›\033[0m "
|
||||
"\033[2;37mEnter send · Esc browse · :support\033[0m"
|
||||
"\033[K");
|
||||
} else if (client->width >= 36) {
|
||||
buffer_appendf(buffer, buf_size, pos,
|
||||
"\033[2;37m›\033[0m "
|
||||
"\033[2;37mEnter · Esc · :support\033[0m\033[K");
|
||||
} else {
|
||||
buffer_appendf(buffer, buf_size, pos, "\033[2;37m›\033[0m \033[K");
|
||||
}
|
||||
} else if (client->mode == MODE_NORMAL) {
|
||||
int total = msg_count;
|
||||
int range_start = total == 0 ? 0 : start + 1;
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ set timeout 10
|
|||
spawn ssh $SSH_OPTS anonymous@127.0.0.1
|
||||
sleep 1
|
||||
send -- "tester\r"
|
||||
expect "›"
|
||||
expect ":support"
|
||||
send -- "\033\[200~"
|
||||
send -- "line1\nline2\nline3"
|
||||
send -- "\033\[201~"
|
||||
|
|
@ -139,7 +139,7 @@ set timeout 10
|
|||
spawn ssh $SSH_OPTS anonymous@127.0.0.1
|
||||
sleep 1
|
||||
send -- "supporter\r"
|
||||
expect "›"
|
||||
expect ":support"
|
||||
send -- "\033"
|
||||
expect "NORMAL"
|
||||
send -- ":"
|
||||
|
|
@ -165,6 +165,38 @@ else
|
|||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
|
||||
UNKNOWN_SCRIPT="$STATE_DIR/unknown-command.expect"
|
||||
cat >"$UNKNOWN_SCRIPT" <<EOF
|
||||
set timeout 10
|
||||
spawn ssh $SSH_OPTS anonymous@127.0.0.1
|
||||
sleep 1
|
||||
send -- "mistype\r"
|
||||
expect ":support"
|
||||
send -- "\033"
|
||||
expect "NORMAL"
|
||||
send -- ":"
|
||||
expect ":"
|
||||
send -- "suport\r"
|
||||
expect "Did you mean :support"
|
||||
expect "Press any key"
|
||||
send -- "q"
|
||||
sleep 0.2
|
||||
send -- "\003"
|
||||
sleep 0.2
|
||||
send -- "\003"
|
||||
expect eof
|
||||
EOF
|
||||
|
||||
if expect "$UNKNOWN_SCRIPT" >"$STATE_DIR/unknown-command.log" 2>&1; then
|
||||
echo "✓ mistyped command suggests nearest command"
|
||||
PASS=$((PASS + 1))
|
||||
else
|
||||
echo "x mistyped command suggestion failed"
|
||||
sed -n '1,160p' "$STATE_DIR/unknown-command.log"
|
||||
sed -n '1,120p' "$STATE_DIR/server.log"
|
||||
FAIL=$((FAIL + 1))
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "PASSED: $PASS"
|
||||
echo "FAILED: $FAIL"
|
||||
|
|
|
|||
Loading…
Reference in a new issue