unix: Add option to use uPy readline, and enable by default.
This gets uPy readline working with unix port, with tab completion and history. GNU readline is still supported, configure using MICROPY_USE_READLINE variable.
This commit is contained in:
parent
4a10214be2
commit
9ae3fc6523
|
@ -1,3 +1,3 @@
|
|||
# basic REPL tests
|
||||
print(1)
|
||||
OA
|
||||
[A
|
||||
|
|
|
@ -57,7 +57,12 @@ endif
|
|||
endif
|
||||
|
||||
ifeq ($(MICROPY_USE_READLINE),1)
|
||||
INC += -I../lib/mp-readline
|
||||
CFLAGS_MOD += -DMICROPY_USE_READLINE=1
|
||||
LIB_SRC_C_EXTRA += mp-readline/readline.c
|
||||
endif
|
||||
ifeq ($(MICROPY_USE_READLINE),2)
|
||||
CFLAGS_MOD += -DMICROPY_USE_READLINE=2
|
||||
LDFLAGS_MOD += -lreadline
|
||||
# the following is needed for BSD
|
||||
#LDFLAGS_MOD += -ltermcap
|
||||
|
@ -98,8 +103,13 @@ SRC_C = \
|
|||
coverage.c \
|
||||
$(SRC_MOD)
|
||||
|
||||
LIB_SRC_C = $(addprefix lib/,\
|
||||
$(LIB_SRC_C_EXTRA) \
|
||||
)
|
||||
|
||||
OBJ = $(PY_O) $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
||||
OBJ = $(PY_O)
|
||||
OBJ += $(addprefix $(BUILD)/, $(SRC_C:.c=.o))
|
||||
OBJ += $(addprefix $(BUILD)/, $(LIB_SRC_C:.c=.o))
|
||||
|
||||
include ../py/mkrules.mk
|
||||
|
||||
|
|
86
unix/input.c
86
unix/input.c
|
@ -28,26 +28,50 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/nlr.h"
|
||||
#include "py/obj.h"
|
||||
#include "py/mpstate.h"
|
||||
#include "input.h"
|
||||
|
||||
#if MICROPY_USE_READLINE
|
||||
#if MICROPY_USE_READLINE == 1
|
||||
#include MICROPY_HAL_H
|
||||
#include "lib/mp-readline/readline.h"
|
||||
#elif MICROPY_USE_READLINE == 2
|
||||
#include <readline/readline.h>
|
||||
#include <readline/history.h>
|
||||
#include <readline/tilde.h>
|
||||
#else
|
||||
#undef MICROPY_USE_READLINE_HISTORY
|
||||
#define MICROPY_USE_READLINE_HISTORY (0)
|
||||
#endif
|
||||
|
||||
char *prompt(char *p) {
|
||||
#if MICROPY_USE_READLINE
|
||||
#if MICROPY_USE_READLINE == 1
|
||||
// MicroPython supplied readline
|
||||
vstr_t vstr;
|
||||
vstr_init(&vstr, 16);
|
||||
mp_hal_stdio_mode_raw();
|
||||
int ret = readline(&vstr, p);
|
||||
mp_hal_stdio_mode_orig();
|
||||
if (ret != 0) {
|
||||
vstr_clear(&vstr);
|
||||
if (ret == CHAR_CTRL_D) {
|
||||
// EOF
|
||||
return NULL;
|
||||
} else {
|
||||
printf("\n");
|
||||
char *line = malloc(1);
|
||||
line[0] = '\0';
|
||||
return line;
|
||||
}
|
||||
}
|
||||
vstr_null_terminated_str(&vstr);
|
||||
char *line = malloc(vstr.len + 1);
|
||||
memcpy(line, vstr.buf, vstr.len + 1);
|
||||
vstr_clear(&vstr);
|
||||
#elif MICROPY_USE_READLINE == 2
|
||||
// GNU readline
|
||||
char *line = readline(p);
|
||||
if (line) {
|
||||
add_history(line);
|
||||
}
|
||||
#else
|
||||
// simple read string
|
||||
static char buf[256];
|
||||
fputs(p, stdout);
|
||||
char *s = fgets(buf, sizeof(buf), stdin);
|
||||
|
@ -68,13 +92,61 @@ char *prompt(char *p) {
|
|||
|
||||
void prompt_read_history(void) {
|
||||
#if MICROPY_USE_READLINE_HISTORY
|
||||
#if MICROPY_USE_READLINE == 1
|
||||
readline_init0(); // will clear history pointers
|
||||
char *home = getenv("HOME");
|
||||
if (home != NULL) {
|
||||
vstr_t vstr;
|
||||
vstr_init(&vstr, 50);
|
||||
vstr_printf(&vstr, "%s/.micropython.history", home);
|
||||
FILE *fp = fopen(vstr_null_terminated_str(&vstr), "r");
|
||||
if (fp != NULL) {
|
||||
vstr_reset(&vstr);
|
||||
for (;;) {
|
||||
int c = fgetc(fp);
|
||||
if (c == EOF || c == '\n') {
|
||||
readline_push_history(vstr_null_terminated_str(&vstr));
|
||||
if (c == EOF) {
|
||||
break;
|
||||
}
|
||||
vstr_reset(&vstr);
|
||||
} else {
|
||||
vstr_add_byte(&vstr, c);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
vstr_clear(&vstr);
|
||||
}
|
||||
#elif MICROPY_USE_READLINE == 2
|
||||
read_history(tilde_expand("~/.micropython.history"));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
void prompt_write_history(void) {
|
||||
#if MICROPY_USE_READLINE_HISTORY
|
||||
#if MICROPY_USE_READLINE == 1
|
||||
char *home = getenv("HOME");
|
||||
if (home != NULL) {
|
||||
vstr_t vstr;
|
||||
vstr_init(&vstr, 50);
|
||||
vstr_printf(&vstr, "%s/.micropython.history", home);
|
||||
FILE *fp = fopen(vstr_null_terminated_str(&vstr), "w");
|
||||
if (fp != NULL) {
|
||||
for (int i = MP_ARRAY_SIZE(MP_STATE_PORT(readline_hist)) - 1; i >= 0; i--) {
|
||||
const char *line = MP_STATE_PORT(readline_hist)[i];
|
||||
if (line != NULL) {
|
||||
fwrite(line, 1, strlen(line), fp);
|
||||
fputc('\n', fp);
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
}
|
||||
#elif MICROPY_USE_READLINE == 2
|
||||
write_history(tilde_expand("~/.micropython.history"));
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
|
|
|
@ -278,8 +278,6 @@ STATIC void set_sys_argv(char *argv[], int argc, int start_arg) {
|
|||
#endif
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
prompt_read_history();
|
||||
|
||||
mp_stack_set_limit(40000 * (BYTES_PER_WORD / 4));
|
||||
|
||||
pre_process_options(argc, argv);
|
||||
|
@ -445,7 +443,9 @@ int main(int argc, char **argv) {
|
|||
}
|
||||
|
||||
if (ret == NOTHING_EXECUTED) {
|
||||
prompt_read_history();
|
||||
ret = do_repl();
|
||||
prompt_write_history();
|
||||
}
|
||||
|
||||
#if MICROPY_PY_MICROPYTHON_MEM_INFO
|
||||
|
@ -463,7 +463,6 @@ int main(int argc, char **argv) {
|
|||
#endif
|
||||
|
||||
//printf("total bytes = %d\n", m_get_total_bytes_allocated());
|
||||
prompt_write_history();
|
||||
return ret & 0xff;
|
||||
}
|
||||
|
||||
|
|
|
@ -184,10 +184,15 @@ extern const struct _mp_obj_fun_builtin_t mp_builtin_open_obj;
|
|||
{ MP_OBJ_NEW_QSTR(MP_QSTR_input), (mp_obj_t)&mp_builtin_input_obj }, \
|
||||
{ MP_OBJ_NEW_QSTR(MP_QSTR_open), (mp_obj_t)&mp_builtin_open_obj },
|
||||
|
||||
#define MP_STATE_PORT MP_STATE_VM
|
||||
|
||||
#define MICROPY_PORT_ROOT_POINTERS \
|
||||
const char *readline_hist[50]; \
|
||||
mp_obj_t keyboard_interrupt_obj; \
|
||||
void *mmap_region_head; \
|
||||
|
||||
#define MICROPY_HAL_H "unix_mphal.h"
|
||||
|
||||
// We need to provide a declaration/definition of alloca()
|
||||
#ifdef __FreeBSD__
|
||||
#include <stdlib.h>
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
# Build 32-bit binaries on a 64-bit host
|
||||
MICROPY_FORCE_32BIT = 0
|
||||
|
||||
# Linking with GNU readline causes binary to be licensed under GPL
|
||||
# This variable can take the following values:
|
||||
# 0 - no readline, just simple input
|
||||
# 1 - use MicroPython version of readline
|
||||
# 2 - use GNU readline (causes binary to be licensed under GPL)
|
||||
MICROPY_USE_READLINE = 1
|
||||
|
||||
# Subset of CPython time module
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
*/
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "py/mpstate.h"
|
||||
|
@ -35,13 +36,12 @@
|
|||
|
||||
STATIC void sighandler(int signum) {
|
||||
if (signum == SIGINT) {
|
||||
if (MP_STATE_VM(mp_pending_exception) == MP_STATE_VM(keyboard_interrupt_obj)) {
|
||||
// this is the second time we are called, so die straight away
|
||||
exit(1);
|
||||
}
|
||||
mp_obj_exception_clear_traceback(MP_STATE_VM(keyboard_interrupt_obj));
|
||||
MP_STATE_VM(mp_pending_exception) = MP_STATE_VM(keyboard_interrupt_obj);
|
||||
// disable our handler so next we really die
|
||||
struct sigaction sa;
|
||||
sa.sa_handler = SIG_DFL;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sigaction(SIGINT, &sa, NULL);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
@ -67,6 +67,32 @@ void mp_hal_set_interrupt_char(char c) {
|
|||
}
|
||||
}
|
||||
|
||||
#if MICROPY_USE_READLINE == 1
|
||||
|
||||
#include <termios.h>
|
||||
|
||||
static struct termios orig_termios;
|
||||
|
||||
void mp_hal_stdio_mode_raw(void) {
|
||||
// save and set terminal settings
|
||||
tcgetattr(0, &orig_termios);
|
||||
static struct termios termios;
|
||||
termios = orig_termios;
|
||||
termios.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
termios.c_cflag = (termios.c_cflag & ~(CSIZE | PARENB)) | CS8;
|
||||
termios.c_lflag = 0;
|
||||
termios.c_cc[VMIN] = 1;
|
||||
termios.c_cc[VTIME] = 0;
|
||||
tcsetattr(0, TCSAFLUSH, &termios);
|
||||
}
|
||||
|
||||
void mp_hal_stdio_mode_orig(void) {
|
||||
// restore terminal settings
|
||||
tcsetattr(0, TCSAFLUSH, &orig_termios);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int mp_hal_stdin_rx_chr(void) {
|
||||
unsigned char c;
|
||||
int ret = read(0, &c, 1);
|
||||
|
|
|
@ -30,6 +30,9 @@
|
|||
|
||||
void mp_hal_set_interrupt_char(char c);
|
||||
|
||||
void mp_hal_stdio_mode_raw(void);
|
||||
void mp_hal_stdio_mode_orig(void);
|
||||
|
||||
int mp_hal_stdin_rx_chr(void);
|
||||
void mp_hal_stdout_tx_str(const char *str);
|
||||
void mp_hal_stdout_tx_strn(const char *str, mp_uint_t len);
|
||||
|
|
Loading…
Reference in New Issue