Browse Source

add history and auto complete feature in finsh.

git-svn-id: https://rt-thread.googlecode.com/svn/trunk@54 bbd45198-f89e-11dd-88c7-29a3b14d5316
bernard.xiong 15 years ago
parent
commit
3da0559f23
2 changed files with 274 additions and 12 deletions
  1. 106 0
      finsh/cmd.c
  2. 168 12
      finsh/shell.c

+ 106 - 0
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)

+ 168 - 12
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]);