Added multiline editing supoort to REPL. Ctrl+o Adds a newline. (0.17.8)
This commit is contained in:
parent
5c2273da69
commit
997e5026e3
2 changed files with 49 additions and 14 deletions
|
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
project(fun VERSION 0.17.7 LANGUAGES C)
|
project(fun VERSION 0.17.8 LANGUAGES C)
|
||||||
|
|
||||||
set(CMAKE_C_STANDARD 11)
|
set(CMAKE_C_STANDARD 11)
|
||||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||||
|
|
|
||||||
61
src/repl.c
61
src/repl.c
|
|
@ -262,7 +262,7 @@ static int complete_load_path(char *buf, size_t *len_io) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Read one line with prompt, handling backspace, Up/Down history and :load path completion */
|
/* Read one line with prompt, handling backspace, Up/Down history and :load path completion (now with multi-line editing via Ctrl+O) */
|
||||||
static int read_line_edit(char *out, size_t out_cap, const char *prompt) {
|
static int read_line_edit(char *out, size_t out_cap, const char *prompt) {
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
if (prompt) fputs(prompt, stdout), fflush(stdout);
|
if (prompt) fputs(prompt, stdout), fflush(stdout);
|
||||||
|
|
@ -281,15 +281,33 @@ static int read_line_edit(char *out, size_t out_cap, const char *prompt) {
|
||||||
char saved_current[4096];
|
char saved_current[4096];
|
||||||
int has_saved = 0;
|
int has_saved = 0;
|
||||||
|
|
||||||
#define RL_REDRAW_POS() do { \
|
/* How many terminal rows were drawn in the previous repaint (prompt + lines in 'out').
|
||||||
|
We assume no automatic wrapping (only explicit '\n'). */
|
||||||
|
static int prev_rows = 1;
|
||||||
|
|
||||||
|
#define RL_REDRAW() do { \
|
||||||
|
/* Count explicit newlines to estimate rows to draw (prompt line + content lines) */ \
|
||||||
|
int rows = 1; \
|
||||||
|
int has_nl = 0; \
|
||||||
|
for (size_t __i = 0; __i < len; ++__i) { \
|
||||||
|
if (out[__i] == '\n') { rows++; has_nl = 1; } \
|
||||||
|
} \
|
||||||
|
/* Move cursor to the start (top) of the previous render block */ \
|
||||||
|
if (prev_rows > 1) { fprintf(stdout, "\x1b[%dA", prev_rows - 1); } \
|
||||||
fputc('\r', stdout); \
|
fputc('\r', stdout); \
|
||||||
|
/* Repaint prompt + content */ \
|
||||||
if (prompt) fputs(prompt, stdout); \
|
if (prompt) fputs(prompt, stdout); \
|
||||||
fwrite(out, 1, len, stdout); \
|
fwrite(out, 1, len, stdout); \
|
||||||
fputs("\x1b[K", stdout); \
|
/* Clear everything below the current cursor (removes remnants of older, longer renders) */ \
|
||||||
if (pos < len) { \
|
fputs("\x1b[J", stdout); \
|
||||||
|
/* Cursor policy: keep at end for multi-line; for single-line respect pos */ \
|
||||||
|
if (!has_nl && pos < len) { \
|
||||||
size_t back = (size_t)(len - pos); \
|
size_t back = (size_t)(len - pos); \
|
||||||
if (back > 0) fprintf(stdout, "\x1b[%zuD", back); \
|
if (back > 0) fprintf(stdout, "\x1b[%zuD", back); \
|
||||||
|
} else { \
|
||||||
|
pos = len; \
|
||||||
} \
|
} \
|
||||||
|
prev_rows = rows; \
|
||||||
fflush(stdout); \
|
fflush(stdout); \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
|
@ -333,6 +351,9 @@ static int read_line_edit(char *out, size_t out_cap, const char *prompt) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* disallow fine-grained horizontal movement in multi-line mode (cursor stays at end) */
|
||||||
|
int has_nl = 0; for (size_t __i = 0; __i < len; ++__i) { if (out[__i] == '\n') { has_nl = 1; break; } }
|
||||||
|
|
||||||
if (final == 'A') {
|
if (final == 'A') {
|
||||||
if (!has_saved) {
|
if (!has_saved) {
|
||||||
size_t sl = len < sizeof(saved_current) - 1 ? len : sizeof(saved_current) - 1;
|
size_t sl = len < sizeof(saved_current) - 1 ? len : sizeof(saved_current) - 1;
|
||||||
|
|
@ -349,7 +370,7 @@ static int read_line_edit(char *out, size_t out_cap, const char *prompt) {
|
||||||
out[hl] = '\0';
|
out[hl] = '\0';
|
||||||
len = hl;
|
len = hl;
|
||||||
pos = len;
|
pos = len;
|
||||||
RL_REDRAW_POS();
|
RL_REDRAW();
|
||||||
} else {
|
} else {
|
||||||
fputc('\a', stdout); fflush(stdout);
|
fputc('\a', stdout); fflush(stdout);
|
||||||
}
|
}
|
||||||
|
|
@ -375,25 +396,27 @@ static int read_line_edit(char *out, size_t out_cap, const char *prompt) {
|
||||||
len = hl;
|
len = hl;
|
||||||
}
|
}
|
||||||
pos = len;
|
pos = len;
|
||||||
RL_REDRAW_POS();
|
RL_REDRAW();
|
||||||
} else {
|
} else {
|
||||||
fputc('\a', stdout); fflush(stdout);
|
fputc('\a', stdout); fflush(stdout);
|
||||||
}
|
}
|
||||||
} else if (final == 'C') {
|
} else if (final == 'C') {
|
||||||
if (ctrl) {
|
if (has_nl) { fputc('\a', stdout); fflush(stdout); pos = len; RL_REDRAW(); }
|
||||||
|
else if (ctrl) {
|
||||||
size_t old = pos;
|
size_t old = pos;
|
||||||
rl_word_right(out, len, &pos);
|
rl_word_right(out, len, &pos);
|
||||||
if (pos != old) RL_REDRAW_POS();
|
if (pos != old) RL_REDRAW();
|
||||||
else { fputc('\a', stdout); fflush(stdout); }
|
else { fputc('\a', stdout); fflush(stdout); }
|
||||||
} else {
|
} else {
|
||||||
if (pos < len) { pos++; fputs("\x1b[C", stdout); fflush(stdout); }
|
if (pos < len) { pos++; fputs("\x1b[C", stdout); fflush(stdout); }
|
||||||
else { fputc('\a', stdout); fflush(stdout); }
|
else { fputc('\a', stdout); fflush(stdout); }
|
||||||
}
|
}
|
||||||
} else if (final == 'D') {
|
} else if (final == 'D') {
|
||||||
if (ctrl) {
|
if (has_nl) { fputc('\a', stdout); fflush(stdout); pos = len; RL_REDRAW(); }
|
||||||
|
else if (ctrl) {
|
||||||
size_t old = pos;
|
size_t old = pos;
|
||||||
rl_word_left(out, len, &pos);
|
rl_word_left(out, len, &pos);
|
||||||
if (pos != old) RL_REDRAW_POS();
|
if (pos != old) RL_REDRAW();
|
||||||
else { fputc('\a', stdout); fflush(stdout); }
|
else { fputc('\a', stdout); fflush(stdout); }
|
||||||
} else {
|
} else {
|
||||||
if (pos > 0) { pos--; fputs("\x1b[D", stdout); fflush(stdout); }
|
if (pos > 0) { pos--; fputs("\x1b[D", stdout); fflush(stdout); }
|
||||||
|
|
@ -409,7 +432,7 @@ static int read_line_edit(char *out, size_t out_cap, const char *prompt) {
|
||||||
len--;
|
len--;
|
||||||
pos--;
|
pos--;
|
||||||
out[len] = '\0';
|
out[len] = '\0';
|
||||||
RL_REDRAW_POS();
|
RL_REDRAW();
|
||||||
} else {
|
} else {
|
||||||
fputc('\a', stdout);
|
fputc('\a', stdout);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
@ -425,7 +448,19 @@ static int read_line_edit(char *out, size_t out_cap, const char *prompt) {
|
||||||
len = newlen;
|
len = newlen;
|
||||||
pos = len;
|
pos = len;
|
||||||
}
|
}
|
||||||
RL_REDRAW_POS();
|
RL_REDRAW();
|
||||||
|
}
|
||||||
|
} else if (ch == 15) { /* Ctrl+O -> insert newline at cursor (multi-line editing) */
|
||||||
|
if (len + 1 < out_cap) {
|
||||||
|
memmove(out + pos + 1, out + pos, len - pos);
|
||||||
|
out[pos] = '\n';
|
||||||
|
len++;
|
||||||
|
pos++;
|
||||||
|
out[len] = '\0';
|
||||||
|
hist_pos = rl_count;
|
||||||
|
RL_REDRAW();
|
||||||
|
} else {
|
||||||
|
fputc('\a', stdout); fflush(stdout);
|
||||||
}
|
}
|
||||||
} else if (ch >= 32 && ch <= 126) {
|
} else if (ch >= 32 && ch <= 126) {
|
||||||
if (len + 1 < out_cap) {
|
if (len + 1 < out_cap) {
|
||||||
|
|
@ -435,7 +470,7 @@ static int read_line_edit(char *out, size_t out_cap, const char *prompt) {
|
||||||
pos++;
|
pos++;
|
||||||
out[len] = '\0';
|
out[len] = '\0';
|
||||||
hist_pos = rl_count;
|
hist_pos = rl_count;
|
||||||
RL_REDRAW_POS();
|
RL_REDRAW();
|
||||||
} else {
|
} else {
|
||||||
fputc('\a', stdout);
|
fputc('\a', stdout);
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue