This commit is contained in:
lyon 2024-12-02 21:05:57 +08:00
commit e1013eb1d6
7 changed files with 205 additions and 40 deletions

View File

@ -11,40 +11,9 @@
"program": "${workspaceFolder}/build/test/pikascript_test",
// "program": "${workspaceFolder}/build/boot/demo06-pikamain/pikascript_demo06-pikamain",
"args": [
// "--gtest_filter=vm.keyword_2"
// "--gtest_filter=compiler.find_break_point"
// "--gtest_filter=pikaMain.REPL_pdb_set_break"
// "--gtest_filter=vm.subsrc_import",
// "--gtest_filter=vm.run_file_subsrc"
// "--gtest_filter=vm.run_file"
// "--gtest_filter=stddata.encode_decode"
// "--gtest_filter=packtool.packfiles_txt"
// "--gtest_filter=cmodule.class_attr_obj"
// "--gtest_filter=except.try_import_except"
// "--gtest_filter=vm.test_cmodule_import_as"
// "--gtest_filter=vm.subsrc_import"
// "--gtest_filter=event.event_thread3"
// "--gtest_filter=parser.semicolon*"
// "--gtest_filter=time*"
// "--gtest_filter=flashdb.tsdb1"
// "--gtest_filter=flashdb.base"
// "--gtest_filter=jrpc.server"
// "--gtest_filter=jrpc.client"
// "--gtest_filter=jrpc.BlockingRequestBetweenTwoJRPC"
// "--gtest_filter=jrpc.cmd"
// "--gtest_filter=jrpc.exec_get_val"
// "--gtest_filter=jrpc.exec_get_val"
// "--gtest_filter=thread.issue1"
// "--gtest_filter=except.isinstance"
// "--gtest_filter=builtin.isinstance"
// "--gtest_filter=bytes.bytes_split"
// "--gtest_filter=except.dict"
// "--gtest_filter=except.*"
// "--gtest_filter=except.try1"
// "--gtest_filter=except.for_loop"
// "--gtest_filter=builtin.init_raise"
// "--gtest_filter=builtin.strformat"
// "--gtest_filter=except.typeerr"
// "--gtest_filter=module.REPL_big_script"
// "--gtest_filter=parser.input_issue1"
"--gtest_filter=except.raise_type"
],
"stopAtEntry": false,
"cwd": "${workspaceFolder}",

View File

@ -504,9 +504,9 @@ char f_getchar(void) {
if (n > 0) {
return c;
}
pika_platform_printf("f_getchar error\r\n");
pika_assert(0);
return -1;
// pika_platform_printf("f_getchar error\r\n");
// pika_assert(0);
return EOF;
}
void pikaScriptShell_withGetchar(PikaObj* self, sh_getchar getchar_fn);
}
@ -603,7 +603,7 @@ TEST(module, REPL_big_script) {
fclose((FILE*)f_getchar_fp);
/* collect */
/* assert */
EXPECT_STREQ(log_buff[0],
EXPECT_STREQ(log_buff[3],
"\r\nError: line buff overflow, please use bigger "
"'PIKA_LINE_BUFF_SIZE'\r\n");
/* deinit */

View File

@ -2753,6 +2753,27 @@ TEST(pikaMain, REPL_backspace) {
EXPECT_EQ(pikaMemNow(), 0);
}
#if PIKA_TAB_ENABLE
TEST(pikaMain, REPL_tab_completion) {
char lines[] = {'p', 'r', 0x09, '(', '\"',
't', 'e', 's', 't', '\"', ')', '\r', '\n', 0x00};
/* init */
g_PikaMemInfo.heapUsedMax = 0;
PikaObj* pikaMain = newRootObj("pikaMain", New_PikaMain);
/* run */
__platform_printf("BEGIN\r\n");
for (size_t i = 0; i < strGetSize(lines); i++) {
obj_runChar(pikaMain, lines[i]);
}
/* collect */
/* assert */
EXPECT_STREQ(log_buff[1], "test\r\n");
/* deinit */
obj_deinit(pikaMain);
EXPECT_EQ(pikaMemNow(), 0);
}
#endif
TEST(pikaMain, REPL_backspace_issue_1) {
char* lines = "print('test'\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b\b'a'\r\n";
/* init */

View File

@ -1395,6 +1395,121 @@ typedef enum {
__FILTER_SUCCESS_DROP_ALL_PEEKED
} FilterReturn;
typedef struct {
int count;
char **completions;
} CompletionList;
typedef struct {
char lineBuff[PIKA_LINE_BUFF_SIZE];
size_t line_position;
size_t line_curpos;
char prefix[32];
} Shell;
const char *dictionary[] = {
"import", "PikaStdLib", "from", "high", "low", "Pin", "value", "def",
"PikaStdDevice", "setPin", "enable", "print", "sleep_ms", "read",
"setMode", "setCallBack", "setPull", "as", "MemChecker", "max", "min",
"float", "int", "str", "list", "dict", "tuple", "if", "else",
"elif", "for", "while", "break", "continue", "return", "try", "except",
"finally", "with", "open", "write", "append", "close", "True", "False",
"None", "self", "class", "init", "len", "range", "input", "output",
"config", "setup", "loop", "GPIO", "UART", "I2C", "SPI", "ADC", "PWM",
"digitalRead", "digitalWrite", "analogRead", "analogWrite", "time", "datetime",
"random", "OS", "sys", "math", "json", "readFile", "writeFile",
""
};
int dictSize = sizeof(dictionary) / sizeof(dictionary[0]);
static CompletionList filtered_complete = {0, NULL};
void shCompletePrint(CompletionList *completeList, const char *prefix) {
for (int i = 0; i < completeList->count; i++) {
printf("%s ", completeList->completions[i]);
}
}
void getFilteredCompletions(const char* prefix, const char** dictionary, int dictSize, CompletionList *result) {
printf("\n");
if (result->completions != NULL) {
for (int i = 0; i < result->count; i++) {
free(result->completions[i]);
}
free(result->completions);
result->completions = NULL;
}
result->count = 0;
result->completions = (char**)malloc(dictSize * sizeof(char*));
if (result->completions == NULL) {
printf("Memory allocation failed\n");
return;
}
for (int i = 0; i < dictSize; i++) {
if (strncmp(dictionary[i], prefix, strlen(prefix)) == 0) {
result->completions[result->count] = strdup(dictionary[i]);
if (result->completions[result->count] == NULL) {
printf("Memory allocation failed for completion\n");
continue;
}
result->count++;
}
}
if (result->count == 0) {
printf("Warning: No matches found for '%s'\n", prefix);
}
}
/*free CompletionList*/
void freeCompletionList(CompletionList *list) {
for (int i = 0; i < list->count; ++i) {
free(list->completions[i]);
}
free(list->completions);
list->completions = NULL;
list->count = 0;
}
void handleTabCompletion(ShellConfig* shell, char* prefix) {
#if PIKA_TAB_ENABLE
if (shell->line_position > 0) {
if (prefix == NULL) {
printf("Memory allocation failed for prefix\n");
return;
}
// printf("\n================[fetch : %s ]=====================\n", prefix);
getFilteredCompletions(prefix, dictionary, dictSize, &filtered_complete);
if (filtered_complete.count == 1) {
char* last_space = strrchr(shell->lineBuff, ' ');
size_t start_pos = 0;
if (last_space != NULL) {
/*保留空格以前的内容*/
start_pos = last_space - shell->lineBuff + 1;
}
memset(shell->lineBuff + start_pos, 0, sizeof(shell->lineBuff) - start_pos);
strncpy(shell->lineBuff + start_pos, filtered_complete.completions[0], sizeof(shell->lineBuff) - start_pos - 1);
shell->lineBuff[sizeof(shell->lineBuff) - 1] = '\0';
shell->line_position = strlen(shell->lineBuff);
shell->line_curpos = shell->line_position;
printf(">>> %s", shell->lineBuff);
} else {
shCompletePrint(&filtered_complete, prefix);
printf("\n>>> %s", shell->lineBuff);
}
free(prefix);
}
#endif
freeCompletionList(&filtered_complete);
}
pika_bool _filter_msg_hi_pika_handler(FilterItem* msg,
PikaObj* self,
ShellConfig* shell) {
@ -1668,6 +1783,14 @@ enum shellCTRL _inner_do_obj_runChar(PikaObj* self,
ShellConfig* shell) {
char* input_line = NULL;
enum shellCTRL ctrl = SHELL_CTRL_CONTINUE;
static uint64_t tick_start_block_input = 0;
if (tick_start_block_input != 0) {
if (pika_platform_get_tick() - tick_start_block_input < 5000) {
return SHELL_CTRL_CONTINUE;
} else {
tick_start_block_input = 0;
}
}
if (inputChar == 0x7F) {
inputChar = '\b';
}
@ -1682,6 +1805,33 @@ enum shellCTRL _inner_do_obj_runChar(PikaObj* self,
ctrl = SHELL_CTRL_CONTINUE;
goto __exit;
}
if (inputChar == 0x09) {
#if PIKA_TAB_ENABLE
if (shell->line_position > 0) {
// printf("Current cursor position: %zu, Line position: %zu\n", shell->line_curpos, shell->line_position);
char* shell_content = NULL;
char* last_space = strrchr(shell->lineBuff, ' ');
if (last_space == NULL) {
shell_content = strndup(shell->lineBuff, shell->line_position);
} else {
shell_content = strdup(last_space + 1);
}
if (shell_content == NULL) {
printf("Memory allocation failed for shell_content\n");
// return;
}
handleTabCompletion(shell, shell_content);
ctrl = SHELL_CTRL_CONTINUE;
// __clearBuff(shell);
goto __exit;
}
#endif
ctrl = SHELL_CTRL_CONTINUE;
goto __exit;
}
if (inputChar == 0x1b) {
shell->stat = PIKA_SHELL_STATE_WAIT_SPEC_KEY;
ctrl = SHELL_CTRL_CONTINUE;
@ -1762,7 +1912,12 @@ enum shellCTRL _inner_do_obj_runChar(PikaObj* self,
pika_platform_printf(
"\r\nError: line buff overflow, please use bigger "
"'PIKA_LINE_BUFF_SIZE'\r\n");
ctrl = SHELL_CTRL_EXIT;
ctrl = SHELL_CTRL_CONTINUE;
pika_platform_printf(
"Input is blocked for 5 seconds to protect the "
"kernel...\r\n");
tick_start_block_input = pika_platform_get_tick();
pika_platform_printf(">>> ");
__clearBuff(shell);
goto __exit;
}
@ -1981,6 +2136,12 @@ void _do_pikaScriptShell(PikaObj* self, ShellConfig* cfg) {
while (1) {
inputChar[1] = inputChar[0];
inputChar[0] = _await_getchar(cfg->fn_getchar);
#ifdef __linux
if (inputChar[0] == EOF) {
pika_platform_printf("\r\n");
return;
}
#endif
#if !PIKA_NANO_ENABLE
/* run python script */
if (inputChar[0] == '!' && inputChar[1] == '#') {

View File

@ -498,6 +498,10 @@ char* shHistory_getPrev(ShellHistory* self);
char* shHistory_getNext(ShellHistory* self);
#endif
#if PIKA_TAB_ENABLE
void handleTabCompletion(ShellConfig* shell, char* prefix);
#endif
void _do_pikaScriptShell(PikaObj* self, ShellConfig* cfg);
void _temp__do_pikaScriptShell(PikaObj* self, ShellConfig* cfg);

View File

@ -2720,7 +2720,9 @@ static char* Suger_semicolon(Args* outbuffs, char* sLine) {
sStmtItem = strsAppend(&buffs, sStmtItem, "\n");
sStmtAfter = strsAppend(&buffs, sStmtAfter, sStmtItem);
}
sStmtAfter[strGetSize(sStmtAfter) - 1] = '\0';
if (sStmtAfter[0] != '\0') {
sStmtAfter[strGetSize(sStmtAfter) - 1] = '\0';
}
sStmtAfter = strsCopy(outbuffs, sStmtAfter);
strsDeinit(&buffs);
return sStmtAfter;

View File

@ -93,6 +93,10 @@ extern "C" {
#define PIKA_SHELL_HISTORY_ENABLE 0
#endif
#ifndef PIKA_TAB_ENABLE
#define PIKA_TAB_ENABLE 0
#endif
#endif
/* default optimize */
@ -495,6 +499,10 @@ extern "C" {
#define PIKA_SHELL_HISTORY_ENABLE 1
#endif
#ifndef PIKA_TAB_ENABLE
#define PIKA_TAB_ENABLE 1
#endif
#ifndef PIKA_SHELL_HISTORY_NUM
#define PIKA_SHELL_HISTORY_NUM 5
#endif