frontend: add a line editor for shell input
This commit is contained in:
204
frontend/line-ed/input.c
Normal file
204
frontend/line-ed/input.c
Normal file
@@ -0,0 +1,204 @@
|
||||
#include "buffer.h"
|
||||
#include "cursor.h"
|
||||
#include "history.h"
|
||||
#include "hook.h"
|
||||
#include "line-ed.h"
|
||||
#include "prompt.h"
|
||||
#include "refresh.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
void put_char(struct line_ed *ed, char c)
|
||||
{
|
||||
if (ed->l_buf_ptr > ed->l_line_end + 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct refresh_state state = {
|
||||
.r_prev_cursor_x = ed->l_cursor_x,
|
||||
.r_prev_cursor_y = ed->l_cursor_y,
|
||||
};
|
||||
|
||||
unsigned int prev_cursor = ed->l_buf_ptr - ed->l_buf;
|
||||
|
||||
char *dest = ed->l_buf_ptr;
|
||||
unsigned int len = ed->l_line_end - ed->l_buf_ptr + 1;
|
||||
|
||||
if (dest < ed->l_line_end) {
|
||||
memmove(dest + 1, dest, len);
|
||||
}
|
||||
|
||||
ed->l_cursor_x++;
|
||||
ed->l_line_end++;
|
||||
ed->l_buf_ptr++;
|
||||
*dest = c;
|
||||
|
||||
if (ed->l_buf_ptr == ed->l_line_end) {
|
||||
*ed->l_buf_ptr = '\0';
|
||||
}
|
||||
|
||||
hook_buffer_modified(ed);
|
||||
|
||||
put_refresh(ed, &state);
|
||||
}
|
||||
|
||||
static void backspace_simple(struct line_ed *ed)
|
||||
{
|
||||
if (ed->l_buf_ptr == ed->l_buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
struct refresh_state state = {
|
||||
.r_prev_cursor_x = ed->l_cursor_x,
|
||||
.r_prev_cursor_y = ed->l_cursor_y,
|
||||
};
|
||||
|
||||
unsigned int prev_cursor = ed->l_buf_ptr - ed->l_buf;
|
||||
|
||||
char *dest = ed->l_buf_ptr;
|
||||
unsigned int len = ed->l_line_end - ed->l_buf_ptr + 1;
|
||||
memmove(dest - 1, dest, len);
|
||||
|
||||
ed->l_cursor_x--;
|
||||
ed->l_line_end--;
|
||||
ed->l_buf_ptr--;
|
||||
|
||||
hook_buffer_modified(ed);
|
||||
|
||||
backspace_simple_refresh(ed, &state);
|
||||
}
|
||||
|
||||
static void backspace_nl(struct line_ed *ed)
|
||||
{
|
||||
unsigned int prev_line_len = line_length(ed, ed->l_cursor_y - 1);
|
||||
|
||||
struct refresh_state state = {
|
||||
.r_prev_cursor_x = ed->l_cursor_x,
|
||||
.r_prev_cursor_y = ed->l_cursor_y,
|
||||
.r_prev_line_len = prev_line_len,
|
||||
};
|
||||
|
||||
char *dest = ed->l_buf_ptr;
|
||||
unsigned int len = ed->l_line_end - ed->l_buf_ptr + 1;
|
||||
memmove(dest - 1, dest, len);
|
||||
|
||||
ed->l_cursor_x = prev_line_len - 1;
|
||||
ed->l_cursor_y--;
|
||||
ed->l_buf_ptr--;
|
||||
ed->l_line_end--;
|
||||
|
||||
hook_buffer_modified(ed);
|
||||
|
||||
backspace_nl_refresh(ed, &state);
|
||||
}
|
||||
|
||||
void backspace(struct line_ed *ed)
|
||||
{
|
||||
if (ed->l_buf_ptr == ed->l_buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ed->l_cursor_x == 0 && ed->l_cursor_y <= ed->l_continuations) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ed->l_cursor_x == 0 && ed->l_cursor_y > 0) {
|
||||
backspace_nl(ed);
|
||||
} else {
|
||||
backspace_simple(ed);
|
||||
}
|
||||
}
|
||||
|
||||
void cursor_left(struct line_ed *ed)
|
||||
{
|
||||
if (ed->l_cursor_x != 0) {
|
||||
fputs("\010", stdout);
|
||||
fflush(stdout);
|
||||
ed->l_cursor_x--;
|
||||
ed->l_buf_ptr--;
|
||||
return;
|
||||
}
|
||||
|
||||
if (ed->l_cursor_y <= ed->l_continuations || ed->l_buf_ptr <= ed->l_buf) {
|
||||
return;
|
||||
}
|
||||
|
||||
ed->l_cursor_y--;
|
||||
ed->l_buf_ptr--;
|
||||
unsigned int prompt_len = 0;
|
||||
if (ed->l_cursor_y == 0) {
|
||||
prompt_len = prompt_length(ed, PROMPT_MAIN);
|
||||
}
|
||||
|
||||
unsigned int len = line_length(ed, ed->l_cursor_y);
|
||||
ed->l_cursor_x = len - 1;
|
||||
|
||||
printf("\033[A\033[%dG", len + prompt_len);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void cursor_right(struct line_ed *ed)
|
||||
{
|
||||
if (ed->l_buf_ptr >= ed->l_line_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (*ed->l_buf_ptr != '\n') {
|
||||
ed->l_cursor_x++;
|
||||
ed->l_buf_ptr++;
|
||||
fputs("\033[C", stdout);
|
||||
fflush(stdout);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ed->l_buf_ptr >= ed->l_line_end) {
|
||||
return;
|
||||
}
|
||||
|
||||
ed->l_cursor_y++;
|
||||
ed->l_cursor_x = 0;
|
||||
ed->l_buf_ptr++;
|
||||
|
||||
printf("\033[B\033[G");
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void arrow_up(struct line_ed *ed)
|
||||
{
|
||||
if (ed->l_history_pos == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ed->l_cursor_y > 0) {
|
||||
printf("\033[%uA", ed->l_cursor_y);
|
||||
}
|
||||
|
||||
printf("\033[%zuG\033[J", prompt_length(ed, PROMPT_MAIN) + 1);
|
||||
|
||||
save_buf_to_history(ed);
|
||||
ed->l_history_pos--;
|
||||
load_buf_from_history(ed);
|
||||
|
||||
print_buffer(ed);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void arrow_down(struct line_ed *ed)
|
||||
{
|
||||
if (ed->l_history_pos == b_array_size(ed->l_history) - 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (ed->l_cursor_y > 0) {
|
||||
printf("\033[%uA", ed->l_cursor_y);
|
||||
}
|
||||
|
||||
printf("\033[%zuG\033[J", prompt_length(ed, PROMPT_MAIN) + 1);
|
||||
|
||||
save_buf_to_history(ed);
|
||||
ed->l_history_pos++;
|
||||
load_buf_from_history(ed);
|
||||
|
||||
print_buffer(ed);
|
||||
fflush(stdout);
|
||||
}
|
||||
Reference in New Issue
Block a user