From 3da0559f23b7cd01004c451a2ce30ecc8e9b0271 Mon Sep 17 00:00:00 2001 From: "bernard.xiong" Date: Tue, 29 Sep 2009 13:07:29 +0000 Subject: [PATCH] add history and auto complete feature in finsh. git-svn-id: https://rt-thread.googlecode.com/svn/trunk@54 bbd45198-f89e-11dd-88c7-29a3b14d5316 --- finsh/cmd.c | 106 +++++++++++++++++++++++++++++ finsh/shell.c | 180 ++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 274 insertions(+), 12 deletions(-) diff --git a/finsh/cmd.c b/finsh/cmd.c index ef2b02d13..f79039416 100644 --- a/finsh/cmd.c +++ b/finsh/cmd.c @@ -369,6 +369,112 @@ int list() } FINSH_FUNCTION_EXPORT(list, list all symbol in system) +int str_is_prefix(const char* prefix, const char* str) +{ + while ((*prefix) && (*prefix == *str)) + { + prefix ++; + str ++; + } + + if (*prefix == 0) return 0; + return -1; +} + +void list_prefix(char* prefix) +{ + struct finsh_syscall_item* syscall_item; + struct finsh_sysvar_item* sysvar_item; + rt_uint16_t func_cnt, var_cnt; + const char* name_ptr; + + func_cnt = 0; + var_cnt = 0; + { + struct finsh_syscall* index; + for (index = _syscall_table_begin; index < _syscall_table_end; index ++) + { + if (str_is_prefix(prefix, index->name) == 0) + { + if (func_cnt == 0) + rt_kprintf("--function:\n"); + + func_cnt ++; + /* set name_ptr */ + name_ptr = index->name; + +#ifdef FINSH_USING_DESCRIPTION + rt_kprintf("%-16s -- %s\n", index->name, index->desc); +#else + rt_kprintf("%s\n", index->name); +#endif + } + } + } + + /* list syscall list */ + syscall_item = global_syscall_list; + while (syscall_item != NULL) + { + if (str_is_prefix(prefix, syscall_item->syscall.name) == 0) + { + if (func_cnt == 0) + rt_kprintf("--function:\n"); + func_cnt ++; + /* set name_ptr */ + name_ptr = syscall_item->syscall.name; + + rt_kprintf("[l] %s\n", syscall_item->syscall.name); + } + syscall_item = syscall_item->next; + } + + { + struct finsh_sysvar* index; + for (index = _sysvar_table_begin; index < _sysvar_table_end; index ++) + { + if (str_is_prefix(prefix, index->name) == 0) + { + if (var_cnt == 0) + rt_kprintf("--variable:\n"); + + var_cnt ++; + /* set name ptr */ + name_ptr = index->name; + +#ifdef FINSH_USING_DESCRIPTION + rt_kprintf("%-16s -- %s\n", index->name, index->desc); +#else + rt_kprintf("%s\n", index->name); +#endif + } + } + } + + sysvar_item = global_sysvar_list; + while (sysvar_item != NULL) + { + if (str_is_prefix(prefix, sysvar_item->sysvar.name) == 0) + { + if (var_cnt == 0) + rt_kprintf("--variable:\n"); + + var_cnt ++; + /* set name ptr */ + name_ptr = sysvar_item->sysvar.name; + + rt_kprintf("[l] %s\n", sysvar_item->sysvar.name); + } + sysvar_item = sysvar_item->next; + } + + /* only one matched */ + if ((func_cnt + var_cnt) == 1) + { + rt_strncpy(prefix, name_ptr, strlen(name_ptr)); + } +} + #ifdef FINSH_USING_SYMTAB static int dummy = 0; FINSH_VAR_EXPORT(dummy, finsh_type_int, dummy variable for finsh) diff --git a/finsh/shell.c b/finsh/shell.c index 486959480..295079b13 100644 --- a/finsh/shell.c +++ b/finsh/shell.c @@ -20,6 +20,8 @@ #include "finsh.h" +#define FINSH_USING_HISTORY + #if defined(__CC_ARM) /* ARMCC compiler */ #ifdef FINSH_USING_SYMTAB extern int FSymTab$$Base; @@ -41,6 +43,22 @@ struct rt_semaphore uart_sem; #ifdef RT_USING_DEVICE rt_device_t finsh_device; #endif +#ifdef FINSH_USING_HISTORY +enum input_stat +{ + WAIT_NORMAL, + WAIT_SPEC_KEY, + WAIT_FUNC_KEY, +}; +#ifndef FINSH_HISTORY_LINES +#define FINSH_HISTORY_LINES 5 +#endif +#ifndef FINSH_CMD_SIZE +#define FINSH_CMD_SIZE 80 +#endif +char finsh_cmd_history[FINSH_HISTORY_LINES][FINSH_CMD_SIZE]; +rt_uint16_t finsh_history_count = 0; +#endif #if !defined (RT_USING_NEWLIB) && !defined (RT_USING_MINILIBC) void *memccpy(void *dst, const void *src, int c, size_t count) @@ -148,11 +166,28 @@ void finsh_notify() } #endif +void finsh_auto_complete(char* prefix) +{ + extern void list_prefix(char* prefix); + + rt_kprintf("\n"); + list_prefix(prefix); + rt_kprintf("finsh>>%s", prefix); +} + void finsh_thread_entry(void* parameter) { struct finsh_parser parser; char line[256]; int pos ; +#ifdef FINSH_USING_HISTORY + enum input_stat stat; + unsigned short current_history, use_history; +#endif + + stat = WAIT_NORMAL; + current_history = 0; + use_history = 0; finsh_init(&parser); @@ -170,36 +205,157 @@ void finsh_thread_entry(void* parameter) char ch; #ifndef RT_USING_DEVICE - ch = rt_serial_getc(); + ch = rt_serial_getc(); if (ch != 0) #else rt_err_t rx_result; - rx_result = rt_device_read(finsh_device, 0, &ch, 1); + rx_result = rt_device_read(finsh_device, 0, &ch, 1); if (ch != 0 && rx_result == 1) #endif { - line[pos] = ch; +#ifdef FINSH_USING_HISTORY + /* + * handle up and down key + * up key : 0x1b 0x5b 0x41 + * down key: 0x1b 0x5b 0x42 + */ + if (ch == 0x1b) + { + stat = WAIT_SPEC_KEY; + continue; + } + + if ((stat == WAIT_SPEC_KEY) && (ch == 0x5b)) + { + if (ch == 0x5b) + { + stat = WAIT_FUNC_KEY; + continue; + } + stat = WAIT_NORMAL; + } + + if (stat == WAIT_FUNC_KEY) + { + stat = WAIT_NORMAL; + + if (ch == 0x41) /* up key */ + { + /* prev history */ + if (current_history > 0)current_history --; + else + { + current_history = 0; + continue; + } + + /* copy the history command */ + memcpy(line, &finsh_cmd_history[current_history][0], + FINSH_CMD_SIZE); + pos = strlen(line); + use_history = 1; + } + else if (ch == 0x42) /* down key */ + { + /* next history */ + if (current_history < finsh_history_count - 1) + current_history ++; + else + { + current_history = finsh_history_count - 1; + continue; + } + + memcpy(line, &finsh_cmd_history[current_history][0], + FINSH_CMD_SIZE); + pos = strlen(line); + use_history = 1; + } + + if (use_history) + { + rt_kprintf("\033[2K\r"); + rt_kprintf("finsh>>%s", line); + continue; + } + } +#endif + /* + * handle tab key + */ + if (ch == '\t') + { + /* auto complete */ + finsh_auto_complete(&line[0]); + /* re-calculate position */ + pos = strlen(line); + continue; + } + + /* + * handle backspace key + */ + if (ch == 0x7f) + { + if (pos != 0) rt_kprintf("%c", ch); + line[pos--] = 0; + if (pos < 0) pos = 0; + continue; + } + + line[pos] = ch; rt_kprintf("%c", line[pos]); /* if it's the end of line, break */ if (line[pos] == 0xd || line[pos] == 0xa) - { + { /* change to ';' and break */ line[pos] = ';'; break; } - else if (line[pos] == 0x7f) /* backspace */ - { - line[pos] = 0; - pos --; - if (pos < 0) pos = 0; - continue; - } + else use_history = 0; /* not "\n", it's a new command */ pos ++; } } - } + } + + if (pos == 0) + { + rt_kprintf("\n"); + continue; + } + +#ifdef FINSH_USING_HISTORY + if (use_history == 0) + { + /* push history */ + if (finsh_history_count >= FINSH_HISTORY_LINES) + { + /* move history */ + int index; + for (index = 0; index < FINSH_HISTORY_LINES - 1; index ++) + { + memcpy(&finsh_cmd_history[index][0], + &finsh_cmd_history[index + 1][0], FINSH_CMD_SIZE); + } + memset(&finsh_cmd_history[index][0], 0, FINSH_CMD_SIZE); + memcpy(&finsh_cmd_history[index][0], line, pos); + + /* it's the maximum history */ + finsh_history_count = FINSH_HISTORY_LINES; + } + else + { + memset(&finsh_cmd_history[finsh_history_count][0], 0, FINSH_CMD_SIZE); + memcpy(&finsh_cmd_history[finsh_history_count][0], line, pos); + + /* increase count and set current history position */ + finsh_history_count ++; + } + } + current_history = finsh_history_count; +#endif rt_kprintf("\n"); finsh_parser_run(&parser, (unsigned char*)&line[0]); -- GitLab