Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
140 changes: 140 additions & 0 deletions components/finsh/ansi.h
Original file line number Diff line number Diff line change
@@ -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 */
50 changes: 18 additions & 32 deletions components/finsh/shell.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
#include <rthw.h>
#include <string.h>
#include <stdio.h>

#include "ansi.h"
#ifdef RT_USING_FINSH

#include "shell.h"
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -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 */
{
Expand All @@ -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],
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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);
Expand All @@ -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
{
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 */
{
Expand All @@ -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; i<line_position; \b) */
if (shell->line_position > shell->line_curpos + 1)
rt_kprintf(ANSI_FMT_CUB, shell->line_position - shell->line_curpos - 1);
}
shell->line_curpos++;
}
Expand Down
Loading