summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorwangqinglin <[email protected]>2023-09-27 12:34:05 +0800
committerGitHub <[email protected]>2023-09-27 12:34:05 +0800
commit2d630e38d75c0f83a819083261e2e025b4bcf29d (patch)
tree164244d99a6507046a4202713566f5c7212dbb47
parentd8a2084c057d6116b81a93d334e00f3ba1df67bf (diff)
【msh】新增msh自动补全子选项特性 (#8086)
-rw-r--r--components/finsh/Kconfig4
-rw-r--r--components/finsh/cmd.c93
-rw-r--r--components/finsh/finsh.h148
-rw-r--r--components/finsh/msh.c158
-rw-r--r--components/finsh/msh.h4
-rw-r--r--components/finsh/shell.c4
6 files changed, 363 insertions, 48 deletions
diff --git a/components/finsh/Kconfig b/components/finsh/Kconfig
index 2d9d768e23..119d968163 100644
--- a/components/finsh/Kconfig
+++ b/components/finsh/Kconfig
@@ -76,4 +76,8 @@ if RT_USING_MSH
int "The number of arguments for a shell command"
default 10
+ config FINSH_USING_OPTION_COMPLETION
+ bool "command option completion enable"
+ default y
+
endif
diff --git a/components/finsh/cmd.c b/components/finsh/cmd.c
index c3b0760f6a..4dc21f404f 100644
--- a/components/finsh/cmd.c
+++ b/components/finsh/cmd.c
@@ -39,6 +39,7 @@
#ifdef RT_USING_FINSH
#include <finsh.h>
+#define LIST_DFS_OPT_ID 0x100
#define LIST_FIND_OBJ_NR 8
static long clear(void)
@@ -903,6 +904,7 @@ long list_device(void)
}
#endif /* RT_USING_DEVICE */
+#ifndef FINSH_USING_OPTION_COMPLETION
int cmd_list(int argc, char **argv)
{
if(argc == 2)
@@ -1013,6 +1015,95 @@ _usage:
return 0;
}
-MSH_CMD_EXPORT_ALIAS(cmd_list, list, list objects);
+
+#else
+CMD_OPTIONS_STATEMENT(cmd_list)
+int cmd_list(int argc, char **argv)
+{
+ if (argc == 2)
+ {
+ switch (MSH_OPT_ID_GET(cmd_list))
+ {
+ case RT_Object_Class_Thread: list_thread(); break;
+ case RT_Object_Class_Timer: list_timer(); break;
+#ifdef RT_USING_SEMAPHORE
+ case RT_Object_Class_Semaphore: list_sem(); break;
+#endif /* RT_USING_SEMAPHORE */
+#ifdef RT_USING_EVENT
+ case RT_Object_Class_Event: list_event(); break;
+#endif /* RT_USING_EVENT */
+#ifdef RT_USING_MUTEX
+ case RT_Object_Class_Mutex: list_mutex(); break;
+#endif /* RT_USING_MUTEX */
+#ifdef RT_USING_MAILBOX
+ case RT_Object_Class_MailBox: list_mailbox(); break;
+#endif /* RT_USING_MAILBOX */
+#ifdef RT_USING_MESSAGEQUEUE
+ case RT_Object_Class_MessageQueue: list_msgqueue(); break;
+#endif /* RT_USING_MESSAGEQUEUE */
+#ifdef RT_USING_MEMHEAP
+ case RT_Object_Class_MemHeap: list_memheap(); break;
+#endif /* RT_USING_MEMHEAP */
+#ifdef RT_USING_MEMPOOL
+ case RT_Object_Class_MemPool: list_mempool(); break;
+#endif /* RT_USING_MEMPOOL */
+#ifdef RT_USING_DEVICE
+ case RT_Object_Class_Device: list_device(); break;
+#endif /* RT_USING_DEVICE */
+#ifdef RT_USING_DFS
+ case LIST_DFS_OPT_ID:
+ {
+ extern int list_fd(void);
+ list_fd();
+ break;
+ }
+#endif /* RT_USING_DFS */
+ default:
+ goto _usage;
+ break;
+ };
+
+ return 0;
+ }
+
+_usage:
+ rt_kprintf("Usage: list [options]\n");
+ rt_kprintf("[options]:\n");
+ MSH_OPT_DUMP(cmd_list);
+ return 0;
+}
+CMD_OPTIONS_NODE_START(cmd_list)
+CMD_OPTIONS_NODE(RT_Object_Class_Thread, thread, list threads)
+CMD_OPTIONS_NODE(RT_Object_Class_Timer, timer, list timers)
+#ifdef RT_USING_SEMAPHORE
+CMD_OPTIONS_NODE(RT_Object_Class_Semaphore, sem, list semaphores)
+#endif /* RT_USING_SEMAPHORE */
+#ifdef RT_USING_EVENT
+CMD_OPTIONS_NODE(RT_Object_Class_Event, event, list events)
+#endif /* RT_USING_EVENT */
+#ifdef RT_USING_MUTEX
+CMD_OPTIONS_NODE(RT_Object_Class_Mutex, mutex, list mutexs)
+#endif /* RT_USING_MUTEX */
+#ifdef RT_USING_MAILBOX
+CMD_OPTIONS_NODE(RT_Object_Class_MailBox, mailbox, list mailboxs)
+#endif /* RT_USING_MAILBOX */
+#ifdef RT_USING_MESSAGEQUEUE
+CMD_OPTIONS_NODE(RT_Object_Class_MessageQueue, msgqueue, list message queues)
+#endif /* RT_USING_MESSAGEQUEUE */
+#ifdef RT_USING_MEMHEAP
+CMD_OPTIONS_NODE(RT_Object_Class_MemHeap, memheap, list memory heaps)
+#endif /* RT_USING_MEMHEAP */
+#ifdef RT_USING_MEMPOOL
+CMD_OPTIONS_NODE(RT_Object_Class_MemPool, mempool, list memory pools)
+#endif /* RT_USING_MEMPOOL */
+#ifdef RT_USING_DEVICE
+CMD_OPTIONS_NODE(RT_Object_Class_Device, device, list devices)
+#endif /* RT_USING_DEVICE */
+#ifdef RT_USING_DFS
+CMD_OPTIONS_NODE(LIST_DFS_OPT_ID, fd, list file descriptors)
+#endif /* RT_USING_DFS */
+CMD_OPTIONS_NODE_END
+#endif /* FINSH_USING_OPTION_COMPLETION */
+MSH_CMD_EXPORT_ALIAS(cmd_list, list, list objects, optenable);
#endif /* RT_USING_FINSH */
diff --git a/components/finsh/finsh.h b/components/finsh/finsh.h
index cf13b761d5..d6bf53abcb 100644
--- a/components/finsh/finsh.h
+++ b/components/finsh/finsh.h
@@ -16,21 +16,35 @@
#pragma section("FSymTab$f",read)
#endif /* _MSC_VER */
+#ifdef FINSH_USING_OPTION_COMPLETION
+#define FINSH_COND(opt) opt,
+#else
+#define FINSH_COND(opt)
+#endif
+
+#ifdef FINSH_USING_DESCRIPTION
+#define FINSH_DESC(cmd, desc) __fsym_##cmd##_desc,
+#else
+#define FINSH_DESC(cmd, desc)
+#endif
+
typedef long (*syscall_func)(void);
#ifdef FINSH_USING_SYMTAB
+
#ifdef __TI_COMPILER_VERSION__
#define __TI_FINSH_EXPORT_FUNCTION(f) PRAGMA(DATA_SECTION(f,"FSymTab"))
#endif /* __TI_COMPILER_VERSION__ */
-#ifdef FINSH_USING_DESCRIPTION
+
#ifdef _MSC_VER
-#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
+#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc, opt) \
const char __fsym_##cmd##_name[] = #cmd; \
const char __fsym_##cmd##_desc[] = #desc; \
__declspec(allocate("FSymTab$f")) \
const struct finsh_syscall __fsym_##cmd = \
{ \
__fsym_##cmd##_name, \
- __fsym_##cmd##_desc, \
+ FINSH_DESC(cmd, desc) \
+ FINSH_COND(opt) \
(syscall_func)&name \
};
#pragma comment(linker, "/merge:FSymTab=mytext")
@@ -41,62 +55,54 @@ typedef long (*syscall_func)(void);
#else
#define RT_NOBLOCKED
#endif
-#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
- __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \
- const char __fsym_##cmd##_name[] = #cmd; \
- const char __fsym_##cmd##_desc[] = #desc; \
- rt_used RT_NOBLOCKED const struct finsh_syscall __fsym_##cmd = \
+#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc, opt) \
+ __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \
+ const char __fsym_##cmd##_name[] = #cmd; \
+ const char __fsym_##cmd##_desc[] = #desc; \
+ rt_used RT_NOBLOCKED const struct finsh_syscall __fsym_##cmd = \
{ \
__fsym_##cmd##_name, \
- __fsym_##cmd##_desc, \
+ FINSH_DESC(cmd, desc) \
+ FINSH_COND(opt) \
(syscall_func)&name \
};
+
#else
-#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
+#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc, opt) \
const char __fsym_##cmd##_name[] rt_section(".rodata.name") = #cmd; \
const char __fsym_##cmd##_desc[] rt_section(".rodata.name") = #desc; \
rt_used const struct finsh_syscall __fsym_##cmd rt_section("FSymTab")= \
{ \
__fsym_##cmd##_name, \
- __fsym_##cmd##_desc, \
+ FINSH_DESC(cmd, desc) \
+ FINSH_COND(opt) \
(syscall_func)&name \
};
-#endif
-#else
-#ifdef _MSC_VER
-#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
- const char __fsym_##cmd##_name[] = #cmd; \
- __declspec(allocate("FSymTab$f")) \
- const struct finsh_syscall __fsym_##cmd = \
- { \
- __fsym_##cmd##_name, \
- (syscall_func)&name \
- };
-#pragma comment(linker, "/merge:FSymTab=mytext")
+#endif /* _MSC_VER */
+#endif /* end of FINSH_USING_SYMTAB */
-#elif defined(__TI_COMPILER_VERSION__)
-#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
- __TI_FINSH_EXPORT_FUNCTION(__fsym_##cmd); \
- const char __fsym_##cmd##_name[] = #cmd; \
- const struct finsh_syscall __fsym_##cmd = \
- { \
- __fsym_##cmd##_name, \
- (syscall_func)&name \
- };
-#else
-#define MSH_FUNCTION_EXPORT_CMD(name, cmd, desc) \
- const char __fsym_##cmd##_name[] = #cmd; \
- rt_used const struct finsh_syscall __fsym_##cmd rt_section("FSymTab")= \
- { \
- __fsym_##cmd##_name, \
- (syscall_func)&name \
- };
+#define __MSH_GET_MACRO(_1, _2, _3, _FUN, ...) _FUN
+#define __MSH_GET_EXPORT_MACRO(_1, _2, _3, _4, _FUN, ...) _FUN
-#endif
-#endif /* end of FINSH_USING_DESCRIPTION */
-#endif /* end of FINSH_USING_SYMTAB */
+#define _MSH_FUNCTION_CMD2(a0, a1) \
+ MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, 0)
+
+#define _MSH_FUNCTION_CMD3_OPT(a0, a1, a2) \
+ MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, a0##_msh_options)
+
+#define _MSH_FUNCTION_CMD3_NO_OPT(a0, a1, a2) \
+ MSH_FUNCTION_EXPORT_CMD(a0, a0, a1, 0)
+
+#define _MSH_FUNCTION_EXPORT_CMD3(a0, a1, a2) \
+ MSH_FUNCTION_EXPORT_CMD(a0, a1, a2, 0)
+
+#define _MSH_FUNCTION_EXPORT_CMD4_OPT(a0, a1, a2, a3) \
+ MSH_FUNCTION_EXPORT_CMD(a0, a1, a2, a0##_msh_options)
+
+#define _MSH_FUNCTION_EXPORT_CMD4_NO_OPT(a0, a1, a2, a3) \
+ MSH_FUNCTION_EXPORT_CMD(a0, a1, a2, 0)
/**
* @ingroup finsh
@@ -126,9 +132,18 @@ typedef long (*syscall_func)(void);
*
* @param command is the name of the command.
* @param desc is the description of the command, which will show in help list.
+ * @param opt This is an option, enter any content to enable option completion
*/
-#define MSH_CMD_EXPORT(command, desc) \
- MSH_FUNCTION_EXPORT_CMD(command, command, desc)
+/* MSH_CMD_EXPORT(command, desc) or MSH_CMD_EXPORT(command, desc, opt) */
+#ifdef FINSH_USING_OPTION_COMPLETION
+#define MSH_CMD_EXPORT(...) \
+ __MSH_GET_MACRO(__VA_ARGS__, _MSH_FUNCTION_CMD3_OPT, \
+ _MSH_FUNCTION_CMD2)(__VA_ARGS__)
+#else
+#define MSH_CMD_EXPORT(...) \
+ __MSH_GET_MACRO(__VA_ARGS__, _MSH_FUNCTION_CMD3_NO_OPT, \
+ _MSH_FUNCTION_CMD2)(__VA_ARGS__)
+#endif /* FINSH_USING_OPTION_COMPLETION */
/**
* @ingroup msh
@@ -138,9 +153,19 @@ typedef long (*syscall_func)(void);
* @param command is the name of the command.
* @param alias is the alias of the command.
* @param desc is the description of the command, which will show in help list.
+ * @param opt This is an option, enter any content to enable option completion
*/
-#define MSH_CMD_EXPORT_ALIAS(command, alias, desc) \
- MSH_FUNCTION_EXPORT_CMD(command, alias, desc)
+/* #define MSH_CMD_EXPORT_ALIAS(command, alias, desc) or
+ #define MSH_CMD_EXPORT_ALIAS(command, alias, desc, opt) */
+#ifdef FINSH_USING_OPTION_COMPLETION
+#define MSH_CMD_EXPORT_ALIAS(...) \
+ __MSH_GET_EXPORT_MACRO(__VA_ARGS__, _MSH_FUNCTION_EXPORT_CMD4_OPT, \
+ _MSH_FUNCTION_EXPORT_CMD3)(__VA_ARGS__)
+#else
+#define MSH_CMD_EXPORT_ALIAS(...) \
+ __MSH_GET_EXPORT_MACRO(__VA_ARGS__, _MSH_FUNCTION_EXPORT_CMD4_NO_OPT, \
+ _MSH_FUNCTION_EXPORT_CMD3)(__VA_ARGS__)
+#endif /* FINSH_USING_OPTION_COMPLETION */
/* system call table */
struct finsh_syscall
@@ -149,6 +174,10 @@ struct finsh_syscall
#if defined(FINSH_USING_DESCRIPTION) && defined(FINSH_USING_SYMTAB)
const char *desc; /* description of system call */
#endif
+
+#ifdef FINSH_USING_OPTION_COMPLETION
+ struct msh_cmd_opt *opt;
+#endif
syscall_func func; /* the function address of system call */
};
@@ -159,6 +188,31 @@ struct finsh_syscall_item
struct finsh_syscall syscall; /* syscall */
};
+#ifdef FINSH_USING_OPTION_COMPLETION
+typedef struct msh_cmd_opt
+{
+ rt_uint32_t id;
+ const char *name;
+ const char *des;
+} msh_cmd_opt_t;
+
+#define CMD_OPTIONS_STATEMENT(command) static struct msh_cmd_opt command##_msh_options[];
+#define CMD_OPTIONS_NODE_START(command) static struct msh_cmd_opt command##_msh_options[] = {
+#define CMD_OPTIONS_NODE(_id, _name, _des) {.id = _id, .name = #_name, .des = #_des},
+#define CMD_OPTIONS_NODE_END {0},};
+
+void msh_opt_list_dump(void *options);
+int msh_cmd_opt_id_get(int argc, char *argv[], void *options);
+#define MSH_OPT_ID_GET(fun) msh_cmd_opt_id_get(argc, argv, (void*) fun##_msh_options)
+#define MSH_OPT_DUMP(fun) msh_opt_list_dump((void*) fun##_msh_options)
+
+#else
+#define CMD_OPTIONS_STATEMENT(command)
+#define CMD_OPTIONS_NODE_START(command)
+#define CMD_OPTIONS_NODE(_id, _name, _des)
+#define CMD_OPTIONS_NODE_END
+#endif
+
extern struct finsh_syscall_item *global_syscall_list;
extern struct finsh_syscall *_syscall_table_begin, *_syscall_table_end;
diff --git a/components/finsh/msh.c b/components/finsh/msh.c
index 85fe04b8a7..9c5513f8b9 100644
--- a/components/finsh/msh.c
+++ b/components/finsh/msh.c
@@ -789,4 +789,162 @@ void msh_auto_complete(char *prefix)
return ;
}
+
+#ifdef FINSH_USING_OPTION_COMPLETION
+static msh_cmd_opt_t *msh_get_cmd_opt(char *opt_str)
+{
+ struct finsh_syscall *index;
+ msh_cmd_opt_t *opt = RT_NULL;
+ char *ptr;
+ int len;
+
+ if ((ptr = strchr(opt_str, ' ')))
+ {
+ len = ptr - opt_str;
+ }
+ else
+ {
+ len = strlen(opt_str);
+ }
+
+ for (index = _syscall_table_begin;
+ index < _syscall_table_end;
+ FINSH_NEXT_SYSCALL(index))
+ {
+ if (strncmp(index->name, opt_str, len) == 0 && index->name[len] == '\0')
+ {
+ opt = index->opt;
+ break;
+ }
+ }
+
+ return opt;
+}
+
+static int msh_get_argc(char *prefix, char **last_argv)
+{
+ int argc = 0;
+ char *ch = prefix;
+
+ while (*ch)
+ {
+ if ((*ch == ' ') && *(ch + 1) && (*(ch + 1) != ' '))
+ {
+ *last_argv = ch + 1;
+ argc++;
+ }
+ ch++;
+ }
+
+ return argc;
+}
+
+static void msh_opt_complete(char *opts_str, struct msh_cmd_opt *cmd_opt)
+{
+ struct msh_cmd_opt *opt = cmd_opt;
+ const char *name_ptr = RT_NULL;
+ int min_length = 0, length, opts_str_len;
+
+ opts_str_len = strlen(opts_str);
+
+ for (opt = cmd_opt; opt->id; opt++)
+ {
+ if (!strncmp(opt->name, opts_str, opts_str_len))
+ {
+ if (min_length == 0)
+ {
+ /* set name_ptr */
+ name_ptr = opt->name;
+ /* set initial length */
+ min_length = strlen(name_ptr);
+ }
+
+ length = str_common(name_ptr, opt->name);
+ if (length < min_length)
+ {
+ min_length = length;
+ }
+
+ rt_kprintf("%s\n", opt->name);
+ }
+ }
+ rt_kprintf("\n");
+
+ if (name_ptr != NULL)
+ {
+ strncpy(opts_str, name_ptr, min_length);
+ }
+}
+
+static void msh_opt_help(msh_cmd_opt_t *cmd_opt)
+{
+ msh_cmd_opt_t *opt = cmd_opt;
+
+ for (; opt->id; opt++)
+ {
+ rt_kprintf("%-16s - %s\n", opt->name, opt->des);
+ }
+ rt_kprintf("\n");
+}
+
+void msh_opt_auto_complete(char *prefix)
+{
+ int argc;
+ char *opt_str = RT_NULL;
+ msh_cmd_opt_t *opt = RT_NULL;
+
+ if ((argc = msh_get_argc(prefix, &opt_str)))
+ {
+ opt = msh_get_cmd_opt(prefix);
+ }
+ else if (!msh_get_cmd(prefix, strlen(prefix)) && (' ' == prefix[strlen(prefix) - 1]))
+ {
+ opt = msh_get_cmd_opt(prefix);
+ }
+
+ if (opt && opt->id)
+ {
+ switch (argc)
+ {
+ case 0:
+ msh_opt_help(opt);
+ break;
+
+ case 1:
+ msh_opt_complete(opt_str, opt);
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+int msh_cmd_opt_id_get(int argc, char *argv[], void *options)
+{
+ msh_cmd_opt_t *opt = (msh_cmd_opt_t *) options;
+ int opt_id;
+
+ for (opt_id = 0; (argc >= 2) && opt && opt->id; opt++)
+ {
+ if (!strcmp(opt->name, argv[1]))
+ {
+ opt_id = opt->id;
+ break;
+ }
+ }
+
+ return opt_id;
+}
+
+void msh_opt_list_dump(void *options)
+{
+ msh_cmd_opt_t *opt = (msh_cmd_opt_t *) options;
+
+ for (; opt && opt->id; opt++)
+ {
+ rt_kprintf(" %-16s - %s\n", opt->name, opt->des);
+ }
+}
+#endif /* FINSH_USING_OPTION_COMPLETION */
#endif /* RT_USING_FINSH */
diff --git a/components/finsh/msh.h b/components/finsh/msh.h
index b9b037586e..28652aef66 100644
--- a/components/finsh/msh.h
+++ b/components/finsh/msh.h
@@ -19,4 +19,8 @@ void msh_auto_complete(char *prefix);
int msh_exec_module(const char *cmd_line, int size);
int msh_exec_script(const char *cmd_line, int size);
+#ifdef FINSH_USING_OPTION_COMPLETION
+void msh_opt_auto_complete(char *prefix);
+
+#endif /* FINSH_USING_OPTION_COMPLETION */
#endif
diff --git a/components/finsh/shell.c b/components/finsh/shell.c
index b55eb32316..db5f286285 100644
--- a/components/finsh/shell.c
+++ b/components/finsh/shell.c
@@ -381,6 +381,10 @@ static void shell_auto_complete(char *prefix)
rt_kprintf("\n");
msh_auto_complete(prefix);
+#ifdef FINSH_USING_OPTION_COMPLETION
+ msh_opt_auto_complete(prefix);
+#endif
+
rt_kprintf("%s%s", FINSH_PROMPT, prefix);
}