diff --git a/components/finsh/ansi.h b/components/finsh/ansi.h new file mode 100644 index 00000000000..c9f8d027610 --- /dev/null +++ b/components/finsh/ansi.h @@ -0,0 +1,140 @@ +/** + * @file ansi.h + * @brief VT100/xterm ANSI escape macros for serial terminal (e.g. Xshell). + * + * Usage: + * uart_puts(ANSI_CLR_LINE); + * uart_puts("log: "); + * uart_puts(msg); + * uart_puts(ANSI_CRLF); + * redraw_prompt(); + * + * Compile-time: uart_puts(ANSI_CLR_LINE); + * Runtime: rt_kprintf(ANSI_FMT_CUB, n); + */ + +#ifndef ANSI_H +#define ANSI_H + +/* -------------------------------------------------------------------------- */ +/* Core */ +/* -------------------------------------------------------------------------- */ + +#define ANSI_ESC "\x1b" +#define ANSI_CSI "\x1b[" + +#define ANSI_CRLF "\r\n" +#define ANSI_CR "\r" +#define ANSI_LF "\n" + +/* -------------------------------------------------------------------------- */ +/* Erase */ +/* -------------------------------------------------------------------------- */ + +/** Clear from cursor to end of line */ +#define ANSI_EL ANSI_CSI "0K" +/** Clear from line start to cursor */ +#define ANSI_EL_START ANSI_CSI "1K" +/** Clear entire current line */ +#define ANSI_EL_LINE ANSI_CSI "2K" + +/** Clear screen, cursor home (1,1) */ +#define ANSI_CLS ANSI_CSI "2J" +/** Clear screen + scrollback (xterm) */ +#define ANSI_CLS_ALL ANSI_CSI "3J" + +/** Carriage return + erase whole line (most used) */ +#define ANSI_CLR_LINE "\r" ANSI_EL_LINE + +/* -------------------------------------------------------------------------- */ +/* Cursor move — parameterized (n must be decimal literal or macro) */ +/* -------------------------------------------------------------------------- */ + +#define ANSI_CUU(n) ANSI_CSI #n "A" /* cursor up */ +#define ANSI_CUD(n) ANSI_CSI #n "B" /* cursor down */ +#define ANSI_CUF(n) ANSI_CSI #n "C" /* cursor forward (right) */ +#define ANSI_CUB(n) ANSI_CSI #n "D" /* cursor back (left) */ +#define ANSI_CHA(n) ANSI_CSI #n "G" /* cursor column, 1-based */ +#define ANSI_CUP(row, col) ANSI_CSI #row ";" #col "H" + +#define ANSI_CUU1 ANSI_CSI "1A" +#define ANSI_CUD1 ANSI_CSI "1B" +#define ANSI_CUF1 ANSI_CSI "1C" +#define ANSI_CUB1 ANSI_CSI "1D" + +/* -------------------------------------------------------------------------- */ +/* Cursor move — runtime (rt_kprintf / printf / snprintf, n >= 1) */ +/* -------------------------------------------------------------------------- */ + +#define ANSI_FMT_CUU ANSI_ESC "[%dA" +#define ANSI_FMT_CUD ANSI_ESC "[%dB" +#define ANSI_FMT_CUF ANSI_ESC "[%dC" +#define ANSI_FMT_CUB ANSI_ESC "[%dD" +#define ANSI_FMT_CHA ANSI_ESC "[%dG" /* column 1-based */ +#define ANSI_FMT_CUP ANSI_ESC "[%d;%dH" /* row, col; both 1-based */ + +/** Move to column n (1 = first column) — compile-time literal only */ +#define ANSI_COL(n) ANSI_CHA(n) + +/** + * Jump to end of current line without tracking column count. + * Terminals clamp column to line width (works on Xshell VT100/xterm). + */ +#define ANSI_EOL ANSI_CSI "999C" +#define ANSI_EOL_G ANSI_CSI "999G" + +/* Save / restore cursor (optional; not all terminals support) */ +#define ANSI_SAVE_CURSOR ANSI_CSI "s" +#define ANSI_RESTORE_CURSOR ANSI_CSI "u" + +/* -------------------------------------------------------------------------- */ +/* SGR — text attributes */ +/* -------------------------------------------------------------------------- */ + +#define ANSI_RESET ANSI_CSI "0m" +#define ANSI_BOLD ANSI_CSI "1m" +#define ANSI_DIM ANSI_CSI "2m" +#define ANSI_UNDERLINE ANSI_CSI "4m" +#define ANSI_REVERSE ANSI_CSI "7m" + +#define ANSI_FG_BLACK ANSI_CSI "30m" +#define ANSI_FG_RED ANSI_CSI "31m" +#define ANSI_FG_GREEN ANSI_CSI "32m" +#define ANSI_FG_YELLOW ANSI_CSI "33m" +#define ANSI_FG_BLUE ANSI_CSI "34m" +#define ANSI_FG_MAGENTA ANSI_CSI "35m" +#define ANSI_FG_CYAN ANSI_CSI "36m" +#define ANSI_FG_WHITE ANSI_CSI "37m" + +#define ANSI_BG_BLACK ANSI_CSI "40m" +#define ANSI_BG_RED ANSI_CSI "41m" +#define ANSI_BG_GREEN ANSI_CSI "42m" +#define ANSI_BG_YELLOW ANSI_CSI "43m" +#define ANSI_BG_BLUE ANSI_CSI "44m" +#define ANSI_BG_MAGENTA ANSI_CSI "45m" +#define ANSI_BG_CYAN ANSI_CSI "46m" +#define ANSI_BG_WHITE ANSI_CSI "47m" + +/* -------------------------------------------------------------------------- */ +/* Shell UI helpers (two-line layout: log above, prompt below) */ +/* -------------------------------------------------------------------------- */ + +/** Erase bottom interactive line (prompt + input); input kept in RAM. */ +#define ANSI_PROMPT_CLEAR ANSI_CLR_LINE + +/** + * After a log line exists above: go up one line and move to its end. + * Then uart_puts() incremental log bytes, then ANSI_UI_NEWLINE + redraw prompt. + */ +#define ANSI_LOG_APPEND_POS ANSI_CUU1 ANSI_EOL + +/** Separate log row from prompt row (structural newline, not log content). */ +#define ANSI_UI_NEWLINE ANSI_CRLF + +/** + * Overwrite current line in place (progress / status on one line). + * uart_puts(ANSI_LINE_OVERWRITE); uart_puts("progress 50%"); + */ +#define ANSI_LINE_OVERWRITE ANSI_CLR_LINE + +#endif /* ANSI_H */ diff --git a/components/finsh/shell.c b/components/finsh/shell.c index bfdf48cd9fe..49a2d15b9fb 100644 --- a/components/finsh/shell.c +++ b/components/finsh/shell.c @@ -21,7 +21,7 @@ #include #include #include - +#include "ansi.h" #ifdef RT_USING_FINSH #include "shell.h" @@ -409,7 +409,7 @@ static rt_bool_t shell_handle_history(struct finsh_shell *shell) rt_kprintf("\r"); #else - rt_kprintf("\033[2K\r"); + rt_kprintf(ANSI_CLR_LINE); #endif rt_kprintf("%s%s", FINSH_PROMPT, shell->line); return RT_FALSE; @@ -693,7 +693,7 @@ static void finsh_thread_entry(void *parameter) int new_pos = find_prev_word_start(shell->line, shell->line_curpos); if (new_pos != shell->line_curpos) { - rt_kprintf("\033[%dD", shell->line_curpos - new_pos); + rt_kprintf(ANSI_FMT_CUB, shell->line_curpos - new_pos); shell->line_curpos = new_pos; } continue; @@ -703,7 +703,7 @@ static void finsh_thread_entry(void *parameter) int new_pos = find_next_word_end(shell->line, shell->line_curpos, shell->line_position); if (new_pos != shell->line_curpos) { - rt_kprintf("\033[%dC", new_pos - shell->line_curpos); + rt_kprintf(ANSI_FMT_CUF, new_pos - shell->line_curpos); shell->line_curpos = new_pos; } continue; @@ -738,11 +738,8 @@ static void finsh_thread_entry(void *parameter) if (key_code == 0x31) /* home key */ { /* move cursor to beginning of line */ - while (shell->line_curpos > 0) - { - rt_kprintf("\b"); - shell->line_curpos--; - } + rt_kprintf(ANSI_FMT_CUB, shell->line_curpos); + shell->line_curpos = 0; } else if (key_code == 0x32) /* insert key */ { @@ -755,7 +752,6 @@ static void finsh_thread_entry(void *parameter) if (finsh_shell_check_line(shell) && (shell->line_curpos < shell->line_position)) { - int i; shell->line_position--; rt_memmove(&shell->line[shell->line_curpos], &shell->line[shell->line_curpos + 1], @@ -766,18 +762,14 @@ static void finsh_thread_entry(void *parameter) rt_kprintf("%s ", &shell->line[shell->line_curpos]); /* move cursor back to original position */ - for (i = shell->line_curpos; i <= shell->line_position; i++) - rt_kprintf("\b"); + rt_kprintf(ANSI_FMT_CUB, shell->line_position - shell->line_curpos + 1); } } else if (key_code == 0x34) /* end key */ { /* move cursor to end of line */ - while (shell->line_curpos < shell->line_position) - { - rt_kprintf("%c", shell->line[shell->line_curpos]); - shell->line_curpos++; - } + rt_kprintf(ANSI_FMT_CUF, shell->line_position-shell->line_curpos); + shell->line_curpos = shell->line_position; } continue; } @@ -792,15 +784,13 @@ static void finsh_thread_entry(void *parameter) /* handle tab key */ else if (ch == '\t') { - int i; /* move the cursor to the beginning of line */ - for (i = 0; i < shell->line_curpos; i++) - rt_kprintf("\b"); + rt_kprintf(ANSI_FMT_CUB, shell->line_curpos); /* auto complete */ shell_auto_complete(&shell->line[0]); /* re-calculate position */ - finsh_shell_update_line_length(shell); + shell->line_curpos = shell->line_position = (rt_uint16_t)rt_strlen(shell->line); continue; } @@ -816,8 +806,6 @@ static void finsh_thread_entry(void *parameter) if (shell->line_position > shell->line_curpos) { - int i; - rt_memmove(&shell->line[shell->line_curpos], &shell->line[shell->line_curpos + 1], shell->line_position - shell->line_curpos); @@ -826,8 +814,7 @@ static void finsh_thread_entry(void *parameter) rt_kprintf("\b%s \b", &shell->line[shell->line_curpos]); /* move the cursor to the origin position */ - for (i = shell->line_curpos; i <= shell->line_position; i++) - rt_kprintf("\b"); + rt_kprintf(ANSI_FMT_CUB, shell->line_position - shell->line_curpos + 1); } else { @@ -860,15 +847,15 @@ static void finsh_thread_entry(void *parameter) shell->line_curpos = start; /* Redraw the affected line section */ - rt_kprintf("\033[%dD", del_count); + rt_kprintf(ANSI_FMT_CUB, del_count); /* Rewrite the remaining content */ rt_kprintf("%.*s", shell->line_position - start, &shell->line[start]); /* Clear trailing artifacts */ - rt_kprintf("\033[K"); + rt_kprintf(ANSI_EL_LINE); if (shell->line_position > start) { /* Reset cursor */ - rt_kprintf("\033[%dD", shell->line_position - start); + rt_kprintf(ANSI_FMT_CUB, shell->line_position - start); } continue; @@ -899,7 +886,6 @@ static void finsh_thread_entry(void *parameter) /* normal character */ if (shell->line_curpos < shell->line_position) { - int i; #if defined(FINSH_USING_FUNC_EXT) if (shell->overwrite_mode) /* overwrite mode */ { @@ -922,9 +908,9 @@ static void finsh_thread_entry(void *parameter) if (shell->echo_mode) { rt_kprintf("%s", &shell->line[shell->line_curpos]); - /* move cursor back to correct position */ - for (i = shell->line_curpos + 1; i < shell->line_position; i++) - rt_kprintf("\b"); + /* move cursor back to correct position (was: for i=curpos+1; iline_position > shell->line_curpos + 1) + rt_kprintf(ANSI_FMT_CUB, shell->line_position - shell->line_curpos - 1); } shell->line_curpos++; }