mirror of
https://github.com/tio/tio.git
synced 2026-05-01 14:57:59 +02:00
Add tty_inkey(),tty_simple() and tty_subcmd_readln()
Add following functions to handle input from a thread that uses standard input. tty_inkey() waits for a key to be pressed for a specified amount of time, and then returns the pressed string. tty_simple_readln() reads user input until Enter is pressed. It supports Backspace key. tty_subcmd_readln() reads user input until Enter is pressed. It supports line editing (cursor keys, Backspace) and command history. The script REPL history buffer is now a dedicated history buffer instead of the subcommand history buffer. REPL prompt changes from ">>" to "->". Reduced the history buffer size from 1000 lines to 500 lines.
This commit is contained in:
parent
9703c25503
commit
c8df45ceff
4 changed files with 92 additions and 32 deletions
|
|
@ -191,13 +191,13 @@ Example:
|
||||||
[10:17:30.215] Enter file name or "!" Lua commands or "@" interpreter directive:
|
[10:17:30.215] Enter file name or "!" Lua commands or "@" interpreter directive:
|
||||||
>> @repl
|
>> @repl
|
||||||
[10:17:31.956] Enter Lua REPL mode (@exit to exit)
|
[10:17:31.956] Enter Lua REPL mode (@exit to exit)
|
||||||
>> p=1
|
-> p=1
|
||||||
>> for i=1,10 do\
|
-> for i=1,10 do\
|
||||||
>> p = p * i\
|
-> p = p * i\
|
||||||
>> end
|
-> end
|
||||||
>> print(p, "\r")
|
-> print(p, "\r")
|
||||||
3628800
|
3628800
|
||||||
>> @exit
|
-> @exit
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define RL_HISTORY_MAX 1000
|
#define RL_HISTORY_MAX 500
|
||||||
#define RL_PROMPT_LENGTH_MAX 16
|
#define RL_PROMPT_LENGTH_MAX 16
|
||||||
|
|
||||||
typedef struct readline_s readline_t;
|
typedef struct readline_s readline_t;
|
||||||
|
|
|
||||||
107
src/tty.c
107
src/tty.c
|
|
@ -151,6 +151,7 @@ typedef enum
|
||||||
} sub_command_t;
|
} sub_command_t;
|
||||||
|
|
||||||
#define MLINE_MAX 4096
|
#define MLINE_MAX 4096
|
||||||
|
#define INKEY_CHARS_MAX 16
|
||||||
|
|
||||||
// clang-format off
|
// clang-format off
|
||||||
const char random_array[] =
|
const char random_array[] =
|
||||||
|
|
@ -190,10 +191,12 @@ static char *tty_buffer_write_ptr = tty_buffer;
|
||||||
static pthread_t thread;
|
static pthread_t thread;
|
||||||
static int pipefd[2];
|
static int pipefd[2];
|
||||||
static pthread_mutex_t mutex_input_ready = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t mutex_input_ready = PTHREAD_MUTEX_INITIALIZER;
|
||||||
static char line[PATH_MAX], mline[MLINE_MAX];
|
char line[PATH_MAX], mline[MLINE_MAX];
|
||||||
|
char inkey_chars[INKEY_CHARS_MAX];
|
||||||
static size_t listing_device_name_length_max = 0;
|
static size_t listing_device_name_length_max = 0;
|
||||||
static readline_t *readline_ctx = NULL;
|
static readline_t *readline_ctx = NULL;
|
||||||
static readline_t *subcmd_readline_ctx = NULL;
|
static readline_t *subcmd_readline_ctx = NULL;
|
||||||
|
static readline_t *script_repl_readline_ctx = NULL;
|
||||||
|
|
||||||
static void optional_local_echo(char c)
|
static void optional_local_echo(char c)
|
||||||
{
|
{
|
||||||
|
|
@ -327,10 +330,6 @@ int tty_tcsetattr(int fd)
|
||||||
/* touch DTR only, don't touch RTS */
|
/* touch DTR only, don't touch RTS */
|
||||||
int tiocm_dtr = TIOCM_DTR;
|
int tiocm_dtr = TIOCM_DTR;
|
||||||
int action = (line_state & TIOCM_DTR) ? TIOCMBIS /* DTR=LOW */ : TIOCMBIC /* DTR=HIGH */ ;
|
int action = (line_state & TIOCM_DTR) ? TIOCMBIS /* DTR=LOW */ : TIOCMBIC /* DTR=HIGH */ ;
|
||||||
|
|
||||||
tio_debug_printf("hard flow : tiocm_dtr=%c, action=%c",
|
|
||||||
(line_state & TIOCM_DTR) ? '1' : '0', (line_state & TIOCM_DTR) ? 'C' : 'S');
|
|
||||||
|
|
||||||
if (ioctl(fd, action, &tiocm_dtr) < 0)
|
if (ioctl(fd, action, &tiocm_dtr) < 0)
|
||||||
{
|
{
|
||||||
tio_warning_printf("Could not set line state (%s)", strerror(errno));
|
tio_warning_printf("Could not set line state (%s)", strerror(errno));
|
||||||
|
|
@ -341,10 +340,6 @@ int tty_tcsetattr(int fd)
|
||||||
{
|
{
|
||||||
/* not hardware flow control */
|
/* not hardware flow control */
|
||||||
/* restore DTR and RTS at the same time */
|
/* restore DTR and RTS at the same time */
|
||||||
|
|
||||||
tio_debug_printf("non-hard flow : line_state=0x%x, TIOCM_DTR=0x%x, TIOCM_RTS=0x%x",
|
|
||||||
line_state, TIOCM_DTR, TIOCM_RTS);
|
|
||||||
|
|
||||||
if (ioctl(fd, TIOCMSET, &line_state) < 0)
|
if (ioctl(fd, TIOCMSET, &line_state) < 0)
|
||||||
{
|
{
|
||||||
tio_warning_printf("Could not set line state (%s)", strerror(errno));
|
tio_warning_printf("Could not set line state (%s)", strerror(errno));
|
||||||
|
|
@ -828,12 +823,63 @@ static void tty_line_poke(int fd, int mask, tty_line_mode_t mode, unsigned int d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int tio_subcmd_readln(const char *title_prompt)
|
int tty_inkey(int mseconds)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
memset(inkey_chars, 0, INKEY_CHARS_MAX);
|
||||||
|
|
||||||
|
if ((ret = read_poll(pipefd[0], &inkey_chars[0], 1, (int)mseconds)) <= 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
if ((ret = read_poll(pipefd[0], &inkey_chars[1], INKEY_CHARS_MAX - 2, 0)) < 0)
|
||||||
|
{
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
return ret + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int tty_simple_readln(const char *prompt)
|
||||||
|
{
|
||||||
|
char *p = line;
|
||||||
|
|
||||||
|
/* print prompt */
|
||||||
|
if (prompt && (prompt[0] != '\0')) {
|
||||||
|
tio_printf_raw("%s", prompt);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read line, accept BS and DEL as rubout characters */
|
||||||
|
for (p = line ; p < &line[PATH_MAX-1]; )
|
||||||
|
{
|
||||||
|
if (read(pipefd[0], p, 1) > 0)
|
||||||
|
{
|
||||||
|
if (*p == 0x08 || *p == 0x7f)
|
||||||
|
{
|
||||||
|
if (p > line)
|
||||||
|
{
|
||||||
|
write(STDOUT_FILENO, "\b \b", 3);
|
||||||
|
p--;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
write(STDOUT_FILENO, p, 1);
|
||||||
|
if (*p == '\r') break;
|
||||||
|
p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
write(STDOUT_FILENO, "\n", 1);
|
||||||
|
*p = 0;
|
||||||
|
|
||||||
|
return (p - line);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tty_readln(readline_t *ctx, const char *title_prompt)
|
||||||
{
|
{
|
||||||
if (title_prompt && (title_prompt[0] != '\0')) {
|
if (title_prompt && (title_prompt[0] != '\0')) {
|
||||||
tio_printf_raw("%s\r\n", title_prompt);
|
tio_printf_raw("%s\r\n", title_prompt);
|
||||||
}
|
}
|
||||||
readline_prompt_for_input(subcmd_readline_ctx);
|
readline_prompt_for_input(ctx);
|
||||||
|
|
||||||
/* Read line with line edit and history. */
|
/* Read line with line edit and history. */
|
||||||
char c;
|
char c;
|
||||||
|
|
@ -841,16 +887,26 @@ static int tio_subcmd_readln(const char *title_prompt)
|
||||||
{
|
{
|
||||||
if (read(pipefd[0], &c, 1) > 0)
|
if (read(pipefd[0], &c, 1) > 0)
|
||||||
{
|
{
|
||||||
readline_input(subcmd_readline_ctx, c);
|
readline_input(ctx, c);
|
||||||
if (c == '\r') break;
|
if (c == '\r') break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
strncpy(line, readline_get(subcmd_readline_ctx), PATH_MAX - 1);
|
strncpy(line, readline_get(ctx), PATH_MAX - 1);
|
||||||
line[PATH_MAX - 1] = 0;
|
line[PATH_MAX - 1] = 0;
|
||||||
|
|
||||||
return strlen(line);
|
return strlen(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tty_script_repl_readln()
|
||||||
|
{
|
||||||
|
return tty_readln(script_repl_readline_ctx, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
int tty_subcmd_readln(const char *title_prompt)
|
||||||
|
{
|
||||||
|
return tty_readln(subcmd_readline_ctx, title_prompt);
|
||||||
|
}
|
||||||
|
|
||||||
void tty_output_mode_set(output_mode_t mode)
|
void tty_output_mode_set(output_mode_t mode)
|
||||||
{
|
{
|
||||||
switch (mode)
|
switch (mode)
|
||||||
|
|
@ -911,7 +967,7 @@ static void handle_script_repl(void)
|
||||||
strcpy(mline, "");
|
strcpy(mline, "");
|
||||||
while (true)
|
while (true)
|
||||||
{
|
{
|
||||||
tio_subcmd_readln("");
|
tty_script_repl_readln();
|
||||||
if (strcmp(line, "@exit") == 0)
|
if (strcmp(line, "@exit") == 0)
|
||||||
break;
|
break;
|
||||||
line_len = strlen(line);
|
line_len = strlen(line);
|
||||||
|
|
@ -1009,7 +1065,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||||
{
|
{
|
||||||
case KEY_0:
|
case KEY_0:
|
||||||
tio_printf("Send file with XMODEM-1K");
|
tio_printf("Send file with XMODEM-1K");
|
||||||
if (tio_subcmd_readln("Enter file name: "))
|
if (tty_subcmd_readln("Enter file name: "))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
@ -1022,7 +1078,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||||
|
|
||||||
case KEY_1:
|
case KEY_1:
|
||||||
tio_printf("Send file with XMODEM-CRC");
|
tio_printf("Send file with XMODEM-CRC");
|
||||||
if (tio_subcmd_readln("Enter file name: "))
|
if (tty_subcmd_readln("Enter file name: "))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
@ -1035,7 +1091,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||||
|
|
||||||
case KEY_2:
|
case KEY_2:
|
||||||
tio_printf("Receive file with XMODEM-CRC");
|
tio_printf("Receive file with XMODEM-CRC");
|
||||||
if (tio_subcmd_readln("Enter file name: "))
|
if (tty_subcmd_readln("Enter file name: "))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
@ -1048,7 +1104,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||||
|
|
||||||
case KEY_3:
|
case KEY_3:
|
||||||
tio_printf("Send file with XMODEM-SUM");
|
tio_printf("Send file with XMODEM-SUM");
|
||||||
if (tio_subcmd_readln("Enter file name: "))
|
if (tty_subcmd_readln("Enter file name: "))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
@ -1061,7 +1117,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||||
|
|
||||||
case KEY_4:
|
case KEY_4:
|
||||||
tio_printf("Receive file with XMODEM-SUM");
|
tio_printf("Receive file with XMODEM-SUM");
|
||||||
if (tio_subcmd_readln("Enter file name: "))
|
if (tty_subcmd_readln("Enter file name: "))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
|
|
@ -1389,7 +1445,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||||
|
|
||||||
case KEY_K:
|
case KEY_K:
|
||||||
/* Set keymap */
|
/* Set keymap */
|
||||||
tio_subcmd_readln("Enter keymap @<key>=<script-file>|!<script> :");
|
tty_subcmd_readln("Enter keymap @<key>=<script-file>|!<script> :");
|
||||||
option_parse_key_mappings(line);
|
option_parse_key_mappings(line);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -1441,7 +1497,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||||
case KEY_R:
|
case KEY_R:
|
||||||
/* Run script */
|
/* Run script */
|
||||||
tio_printf("Run Lua script");
|
tio_printf("Run Lua script");
|
||||||
tio_subcmd_readln("Enter file name or \"!\" lua commands or \"@\" direction to interpreter: ");
|
tty_subcmd_readln("Enter file name or \"!\" lua commands or \"@\" direction to interpreter: ");
|
||||||
if (strcmp(line, "@repl") == 0)
|
if (strcmp(line, "@repl") == 0)
|
||||||
{
|
{
|
||||||
handle_script_repl();
|
handle_script_repl();
|
||||||
|
|
@ -1456,7 +1512,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||||
case KEY_SHIFT_R:
|
case KEY_SHIFT_R:
|
||||||
/* Execute shell command */
|
/* Execute shell command */
|
||||||
tio_printf("Execute shell command with I/O redirected to device");
|
tio_printf("Execute shell command with I/O redirected to device");
|
||||||
if (tio_subcmd_readln("Enter command (\"?\" prefix prevents redirection of stderr): "))
|
if (tty_subcmd_readln("Enter command (\"?\" prefix prevents redirection of stderr): "))
|
||||||
{
|
{
|
||||||
state_t state_orig = state;
|
state_t state_orig = state;
|
||||||
state = STATE_EXEC_SHELL_COMMAND;
|
state = STATE_EXEC_SHELL_COMMAND;
|
||||||
|
|
@ -1522,7 +1578,7 @@ void handle_command_sequence(char input_char, char *output_char, bool *forward)
|
||||||
|
|
||||||
case KEY_Y:
|
case KEY_Y:
|
||||||
tio_printf("Send file with YMODEM");
|
tio_printf("Send file with YMODEM");
|
||||||
if (tio_subcmd_readln("Enter file name: "))
|
if (tty_subcmd_readln("Enter file name: "))
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
state_t state_orig = state;
|
state_t state_orig = state;
|
||||||
|
|
@ -2915,14 +2971,15 @@ void tty_init(void)
|
||||||
// Initialize readline like history
|
// Initialize readline like history
|
||||||
readline_ctx = readline_create();
|
readline_ctx = readline_create();
|
||||||
subcmd_readline_ctx = readline_create();
|
subcmd_readline_ctx = readline_create();
|
||||||
if (readline_ctx == NULL || subcmd_readline_ctx == NULL)
|
script_repl_readline_ctx = readline_create();
|
||||||
|
if (readline_ctx == NULL || subcmd_readline_ctx == NULL || script_repl_readline_ctx == NULL)
|
||||||
{
|
{
|
||||||
tio_error_printf("Could not allocate readline buffer.");
|
tio_error_printf("Could not allocate readline buffer.");
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
readline_set_prompt(readline_ctx, "> ");
|
readline_set_prompt(readline_ctx, "> ");
|
||||||
readline_set_prompt(subcmd_readline_ctx, ">> ");
|
readline_set_prompt(subcmd_readline_ctx, ">> ");
|
||||||
|
readline_set_prompt(script_repl_readline_ctx, "-> ");
|
||||||
}
|
}
|
||||||
|
|
||||||
int tty_connect(void)
|
int tty_connect(void)
|
||||||
|
|
|
||||||
|
|
@ -100,3 +100,6 @@ void forward_to_tty(int fd, char output_char);
|
||||||
ssize_t tty_write(int fd, const void *buffer, size_t count);
|
ssize_t tty_write(int fd, const void *buffer, size_t count);
|
||||||
void tty_sync(int fd);
|
void tty_sync(int fd);
|
||||||
int tty_tcsetattr(int fd);
|
int tty_tcsetattr(int fd);
|
||||||
|
int tty_inkey(int mseconds);
|
||||||
|
int tty_simple_readln(const char *prompt);
|
||||||
|
int tty_subcmd_readln(const char *title_prompt);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue