mirror of
https://github.com/janet-lang/janet
synced 2026-02-06 10:10:20 +00:00
Add persistent repl history.
This commit is contained in:
5
janet.1
5
janet.1
@@ -272,6 +272,11 @@ This variable does nothing in the default configuration of Janet, as PRF is disa
|
||||
cannot be defined for this variable to have an effect.
|
||||
.RE
|
||||
|
||||
.B JANET_HISTFILE
|
||||
.RS
|
||||
A file location to use for the default shell's REPL history. This relative path is where commands are persisted between sessions.
|
||||
.RE
|
||||
|
||||
.B NO_COLOR
|
||||
.RS
|
||||
Turn off color by default in the repl and in the error handler of scripts. This can be changed at runtime
|
||||
|
||||
@@ -718,6 +718,18 @@ JANET_CORE_FN(cfun_io_eflush,
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
void janet_xprintf(FILE *file, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
JanetBuffer buffer;
|
||||
int32_t len = 0;
|
||||
while (format[len]) len++;
|
||||
janet_buffer_init(&buffer, len);
|
||||
janet_formatbv(&buffer, format, args);
|
||||
fwrite(buffer.data, buffer.count, 1, file);
|
||||
janet_buffer_deinit(&buffer);
|
||||
}
|
||||
|
||||
void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
@@ -1439,6 +1439,7 @@ JANET_API void janet_loop(void);
|
||||
* } else {
|
||||
* janet_schedule(interrupted_fiber, janet_wrap_nil());
|
||||
* }
|
||||
* janet_interpreter_interrupt_handled(NULL);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
@@ -1889,7 +1890,7 @@ JANET_API void janet_vm_free(JanetVM *vm);
|
||||
JANET_API void janet_vm_save(JanetVM *into);
|
||||
JANET_API void janet_vm_load(JanetVM *from);
|
||||
JANET_API void janet_interpreter_interrupt(JanetVM *vm);
|
||||
JANET_API void janet_interpreter_interrupt_handled(JanetVM *vm);
|
||||
JANET_API void janet_interpreter_interrupt_handled(JanetVM *vm); /* Call this after running interrupt handler */
|
||||
JANET_API JanetSignal janet_continue(JanetFiber *fiber, Janet in, Janet *out);
|
||||
JANET_API JanetSignal janet_continue_signal(JanetFiber *fiber, Janet in, Janet *out, JanetSignal sig);
|
||||
JANET_API JanetSignal janet_pcall(JanetFunction *fun, int32_t argn, const Janet *argv, Janet *out, JanetFiber **f);
|
||||
@@ -2051,6 +2052,7 @@ JANET_NO_RETURN JANET_API void janet_panicv(Janet message);
|
||||
JANET_NO_RETURN JANET_API void janet_panic(const char *message);
|
||||
JANET_NO_RETURN JANET_API void janet_panics(JanetString message);
|
||||
JANET_NO_RETURN JANET_API void janet_panicf(const char *format, ...);
|
||||
JANET_API void janet_xprintf(FILE *file, const char *format, ...);
|
||||
JANET_API void janet_dynprintf(const char *name, FILE *dflt_file, const char *format, ...);
|
||||
#define janet_printf(...) janet_dynprintf("out", stdout, __VA_ARGS__)
|
||||
#define janet_eprintf(...) janet_dynprintf("err", stderr, __VA_ARGS__)
|
||||
|
||||
@@ -96,9 +96,9 @@ static void simpleline(JanetBuffer *buffer) {
|
||||
|
||||
#ifndef JANET_SIMPLE_GETLINE
|
||||
/* static state */
|
||||
#define JANET_LINE_MAX 1024
|
||||
#define JANET_LINE_MAX 4096
|
||||
#define JANET_MATCH_MAX 256
|
||||
#define JANET_HISTORY_MAX 100
|
||||
#define JANET_HISTORY_MAX 1000
|
||||
static JANET_THREAD_LOCAL int gbl_israwmode = 0;
|
||||
static JANET_THREAD_LOCAL const char *gbl_prompt = "> ";
|
||||
static JANET_THREAD_LOCAL int gbl_plen = 2;
|
||||
@@ -112,6 +112,8 @@ static JANET_THREAD_LOCAL int gbl_historyi = 0;
|
||||
static JANET_THREAD_LOCAL JanetByteView gbl_matches[JANET_MATCH_MAX];
|
||||
static JANET_THREAD_LOCAL int gbl_match_count = 0;
|
||||
static JANET_THREAD_LOCAL int gbl_lines_below = 0;
|
||||
static JANET_THREAD_LOCAL int gbl_history_loaded = 0;
|
||||
static JANET_THREAD_LOCAL char *gbl_history_file = NULL;
|
||||
#endif
|
||||
|
||||
/* Fallback */
|
||||
@@ -430,6 +432,74 @@ static int insert(char c, int draw) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void calc_history_file(void) {
|
||||
char *hist = getenv("JANET_HISTFILE");
|
||||
if (hist) {
|
||||
gbl_history_file = sdup(hist);
|
||||
} else {
|
||||
const char *home = (const char *) getenv("HOME");
|
||||
if (NULL == home) home = "";
|
||||
const char *filename = ".janet_history.jdn";
|
||||
size_t homelen = strlen(home);
|
||||
size_t filelen = strlen(filename);
|
||||
size_t buflen = homelen + filelen + 1;
|
||||
char *buffer = janet_malloc(buflen + 1);
|
||||
if (homelen) memcpy(buffer, home, homelen);
|
||||
buffer[homelen] = '/';
|
||||
memcpy(buffer + homelen + 1, filename, filelen);
|
||||
buffer[buflen] = '\0';
|
||||
gbl_history_file = buffer;
|
||||
}
|
||||
/* fprintf(stderr, "history_file: %s\n", gbl_history_file); */
|
||||
}
|
||||
|
||||
static void loadhistory(void) {
|
||||
if (gbl_history_loaded) return;
|
||||
calc_history_file();
|
||||
gbl_history_loaded = 1;
|
||||
FILE *history_file = fopen(gbl_history_file, "rb");
|
||||
if (NULL == history_file) return;
|
||||
JanetParser p;
|
||||
janet_parser_init(&p);
|
||||
int c = 0;
|
||||
while ((c = fgetc(history_file))) {
|
||||
if (c == EOF) {
|
||||
janet_parser_eof(&p);
|
||||
} else {
|
||||
janet_parser_consume(&p, c);
|
||||
}
|
||||
|
||||
while (janet_parser_has_more(&p) && gbl_history_count < JANET_HISTORY_MAX) {
|
||||
if (janet_parser_status(&p) == JANET_PARSE_ERROR) {
|
||||
janet_eprintf("bad history file: %s\n", janet_parser_error(&p));
|
||||
goto parsing_done;
|
||||
}
|
||||
Janet x = janet_parser_produce(&p);
|
||||
const char *cstr = (const char *) janet_to_string(x);
|
||||
if (cstr[0]) { /* Drop empty strings */
|
||||
gbl_history[gbl_history_count++] = sdup(cstr);
|
||||
}
|
||||
}
|
||||
|
||||
if (c == EOF) break;
|
||||
}
|
||||
parsing_done:
|
||||
janet_parser_deinit(&p);
|
||||
gbl_historyi = 0;
|
||||
fclose(history_file);
|
||||
}
|
||||
|
||||
static void savehistory(void) {
|
||||
if (gbl_history_count <= 1 || !gbl_history_file) return;
|
||||
FILE *history_file = fopen(gbl_history_file, "wb");
|
||||
for (int i = 0; i < gbl_history_count; i++) {
|
||||
if (gbl_history[i][0]) { /* Drop empty strings */
|
||||
janet_xprintf(history_file, "%j\n", janet_cstringv(gbl_history[i]));
|
||||
}
|
||||
}
|
||||
fclose(history_file);
|
||||
}
|
||||
|
||||
static void historymove(int delta) {
|
||||
if (gbl_history_count > 1) {
|
||||
janet_free(gbl_history[gbl_historyi]);
|
||||
@@ -896,6 +966,7 @@ static int line() {
|
||||
case 3: /* ctrl-c */
|
||||
clearlines();
|
||||
norawmode();
|
||||
savehistory();
|
||||
#ifdef _WIN32
|
||||
ExitProcess(1);
|
||||
#else
|
||||
@@ -1089,17 +1160,18 @@ void janet_line_init() {
|
||||
}
|
||||
|
||||
void janet_line_deinit() {
|
||||
int i;
|
||||
norawmode();
|
||||
for (i = 0; i < gbl_history_count; i++)
|
||||
for (int i = 0; i < gbl_history_count; i++)
|
||||
janet_free(gbl_history[i]);
|
||||
gbl_historyi = 0;
|
||||
if (gbl_history_file) janet_free(gbl_history_file);
|
||||
}
|
||||
|
||||
void janet_line_get(const char *p, JanetBuffer *buffer) {
|
||||
gbl_prompt = p;
|
||||
buffer->count = 0;
|
||||
gbl_historyi = 0;
|
||||
loadhistory();
|
||||
if (check_simpleline(buffer)) return;
|
||||
FILE *out = janet_dynfile("err", stderr);
|
||||
if (line()) {
|
||||
@@ -1130,6 +1202,13 @@ static void clear_at_exit(void) {
|
||||
* Entry
|
||||
*/
|
||||
|
||||
static void cleanup_at_exit(void) {
|
||||
/* Deinitialize vm */
|
||||
savehistory();
|
||||
janet_deinit();
|
||||
janet_line_deinit();
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
int i, status;
|
||||
JanetArray *args;
|
||||
@@ -1146,6 +1225,7 @@ int main(int argc, char **argv) {
|
||||
#if !defined(JANET_SIMPLE_GETLINE)
|
||||
atexit(clear_at_exit);
|
||||
#endif
|
||||
atexit(cleanup_at_exit);
|
||||
|
||||
#if defined(JANET_PRF)
|
||||
uint8_t hash_key[JANET_HASH_KEY_SIZE + 1];
|
||||
@@ -1193,9 +1273,6 @@ int main(int argc, char **argv) {
|
||||
/* Run the fiber in an event loop */
|
||||
status = janet_loop_fiber(fiber);
|
||||
|
||||
/* Deinitialize vm */
|
||||
janet_deinit();
|
||||
janet_line_deinit();
|
||||
|
||||
/* Deinit moved to atexit */
|
||||
return status;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user