Skip to content

[update] <components>:finsh/shell.c 增加新功能 #10394

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Aug 6, 2025
Merged
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
6 changes: 6 additions & 0 deletions components/finsh/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ if RT_USING_MSH
default 5
endif

config FINSH_USING_WORD_OPERATION
bool "Enable word-based cursor operations"
default n
help
Enable Ctrl+Backspace to delete words and Ctrl+Arrow to move cursor by word

config FINSH_USING_SYMTAB
bool "Using symbol table for commands"
default y
Expand Down
105 changes: 104 additions & 1 deletion components/finsh/shell.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2006-2021, RT-Thread Development Team
* Copyright (c) 2006-2025, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
Expand Down Expand Up @@ -457,6 +457,37 @@ static void shell_push_history(struct finsh_shell *shell)
}
#endif

#if defined(FINSH_USING_WORD_OPERATION)
static int find_prev_word_start(const char *line, int curpos)
{
if (curpos <= 0) return 0;

/* Skip whitespace */
while (--curpos > 0 && (line[curpos] == ' ' || line[curpos] == '\t'));
Copy link
Preview

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The loop uses pre-decrement --curpos in the condition, which could cause the function to skip checking the character at the initial position. This may lead to incorrect word boundary detection.

Suggested change
while (--curpos > 0 && (line[curpos] == ' ' || line[curpos] == '\t'));
while (curpos > 0 && (line[curpos] == ' ' || line[curpos] == '\t'))
curpos--;

Copilot uses AI. Check for mistakes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

如果当前curpos 为空格 跳过就跳过了
如果不是空格 预减也不影响


/* Find word start */
while (curpos > 0 && !(line[curpos] == ' ' || line[curpos] == '\t'))
curpos--;

return (curpos <= 0) ? 0 : curpos + 1;
}

static int find_next_word_end(const char *line, int curpos, int max)
{
if (curpos >= max) return max;

/* Skip to next word */
while (curpos < max && (line[curpos] == ' ' || line[curpos] == '\t'))
curpos++;

/* Find word end */
while (curpos < max && !(line[curpos] == ' ' || line[curpos] == '\t'))
curpos++;

return curpos;
}
#endif /* defined(FINSH_USING_WORD_OPERATION) */

#ifdef RT_USING_HOOK
static void (*_finsh_thread_entry_hook)(void);

Expand Down Expand Up @@ -609,6 +640,42 @@ static void finsh_thread_entry(void *parameter)

continue;
}
#if defined(FINSH_USING_WORD_OPERATION)
/* Add Ctrl+Left/Right handling */
else if (ch == '1')
{
/* Read modifier sequence [1;5D/C] */
int next_ch = finsh_getchar();
if (next_ch == ';')
{
next_ch = finsh_getchar();
if (next_ch == '5')
{
next_ch = finsh_getchar();
if (next_ch == 'D') /* Ctrl+Left */
{
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);
shell->line_curpos = new_pos;
}
continue;
}
else if (next_ch == 'C') /* Ctrl+Right */
{
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);
shell->line_curpos = new_pos;
}
continue;
}
}
}
}
#endif /*defined(FINSH_USING_WORD_OPERATION) */
}

/* received null or error */
Expand Down Expand Up @@ -661,7 +728,43 @@ static void finsh_thread_entry(void *parameter)

continue;
}
#if defined(FINSH_USING_WORD_OPERATION)
/* Add Ctrl+Backspace handling */
else if (ch == 0x17) /* Ctrl+Backspace (typically ^W) */
Comment on lines +732 to +733
Copy link
Preview

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment suggests this is typically Ctrl+Backspace, but 0x17 is actually Ctrl+W. Ctrl+Backspace typically sends different escape sequences depending on the terminal. This could confuse users about which key combination actually triggers this functionality.

Suggested change
/* Add Ctrl+Backspace handling */
else if (ch == 0x17) /* Ctrl+Backspace (typically ^W) */
/* Add Ctrl+W (delete previous word) handling */
else if (ch == 0x17) /* Ctrl+W (delete previous word) */

Copilot uses AI. Check for mistakes.

{
if (shell->line_curpos == 0) continue;

int start = find_prev_word_start(shell->line, shell->line_curpos);
int del_count = shell->line_curpos - start;
int new_len = shell->line_position - del_count;

/* Delete characters and properly add RT_NULL termination */
rt_memmove(&shell->line[start],
&shell->line[start + del_count],
new_len - start + 1);
Copy link
Preview

Copilot AI Aug 5, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The calculation new_len - start + 1 for the memmove length appears incorrect. It should be shell->line_position - start - del_count to move the remaining characters after the deleted word.

Suggested change
new_len - start + 1);
shell->line_position - start - del_count);

Copilot uses AI. Check for mistakes.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

image


/* Clear residual data */
rt_memset(&shell->line[new_len], 0, shell->line_position - new_len);

/* Update positions */
shell->line_position = new_len;
shell->line_curpos = start;

/* Redraw the affected line section */
rt_kprintf("\033[%dD", del_count);
/* Rewrite the remaining content */
rt_kprintf("%.*s", shell->line_position - start, &shell->line[start]);
/* Clear trailing artifacts */
rt_kprintf("\033[K");
if (shell->line_position > start)
{
/* Reset cursor */
rt_kprintf("\033[%dD", shell->line_position - start);
}

continue;
}
#endif /*defined(FINSH_USING_WORD_OPERATION) */
/* handle end of line, break */
if (ch == '\r' || ch == '\n')
{
Expand Down