Break out rline, add ^W support
This commit is contained in:
parent
b54e2d1b54
commit
8a1430879a
@ -32,6 +32,7 @@
|
||||
|
||||
#include "lib/list.h"
|
||||
#include "lib/kbd.h"
|
||||
#include "lib/rline.h"
|
||||
|
||||
#define PIPE_TOKEN "\xFF\xFFPIPE\xFF\xFF"
|
||||
|
||||
@ -219,219 +220,6 @@ void sig_pass(int sig) {
|
||||
}
|
||||
}
|
||||
|
||||
struct rline_callback;
|
||||
|
||||
typedef struct {
|
||||
char * buffer;
|
||||
struct rline_callback * callbacks;
|
||||
int collected;
|
||||
int requested;
|
||||
int newline;
|
||||
int cancel;
|
||||
int offset;
|
||||
int tabbed;
|
||||
} rline_context_t;
|
||||
|
||||
typedef void (*rline_callback_t)(rline_context_t * context);
|
||||
|
||||
typedef struct rline_callback {
|
||||
rline_callback_t tab_complete;
|
||||
rline_callback_t redraw_prompt;
|
||||
rline_callback_t special_key;
|
||||
rline_callback_t key_up;
|
||||
rline_callback_t key_down;
|
||||
rline_callback_t key_left;
|
||||
rline_callback_t key_right;
|
||||
rline_callback_t rev_search;
|
||||
} rline_callbacks_t;
|
||||
|
||||
void rline_redraw(rline_context_t * context) {
|
||||
printf("\033[u%s\033[K", context->buffer);
|
||||
for (int i = context->offset; i < context->collected; ++i) {
|
||||
printf("\033[D");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void rline_redraw_clean(rline_context_t * context) {
|
||||
printf("\033[u%s", context->buffer);
|
||||
for (int i = context->offset; i < context->collected; ++i) {
|
||||
printf("\033[D");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int rline(char * buffer, int buf_size, rline_callbacks_t * callbacks) {
|
||||
/* Initialize context */
|
||||
rline_context_t context = {
|
||||
buffer,
|
||||
callbacks,
|
||||
0,
|
||||
buf_size,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
printf("\033[s");
|
||||
fflush(stdout);
|
||||
|
||||
key_event_state_t kbd_state = {0};
|
||||
|
||||
/* Read keys */
|
||||
while ((context.collected < context.requested) && (!context.newline)) {
|
||||
uint32_t key_sym = kbd_key(&kbd_state, fgetc(stdin));
|
||||
if (key_sym == KEY_NONE) continue;
|
||||
switch (key_sym) {
|
||||
case KEY_CTRL_C:
|
||||
printf("^C\n");
|
||||
context.buffer[0] = '\0';
|
||||
return 0;
|
||||
case KEY_CTRL_D:
|
||||
if (context.collected == 0) {
|
||||
printf("exit\n");
|
||||
sprintf(context.buffer, "exit\n");
|
||||
return strlen(context.buffer);
|
||||
}
|
||||
continue;
|
||||
case KEY_CTRL_R:
|
||||
if (callbacks->rev_search) {
|
||||
callbacks->rev_search(&context);
|
||||
return context.collected;
|
||||
}
|
||||
continue;
|
||||
case KEY_ARROW_UP:
|
||||
if (callbacks->key_up) {
|
||||
callbacks->key_up(&context);
|
||||
}
|
||||
continue;
|
||||
case KEY_ARROW_DOWN:
|
||||
if (callbacks->key_down) {
|
||||
callbacks->key_down(&context);
|
||||
}
|
||||
continue;
|
||||
case KEY_ARROW_RIGHT:
|
||||
if (callbacks->key_right) {
|
||||
callbacks->key_right(&context);
|
||||
} else {
|
||||
if (context.offset < context.collected) {
|
||||
printf("\033[C");
|
||||
fflush(stdout);
|
||||
context.offset++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case KEY_ARROW_LEFT:
|
||||
if (callbacks->key_left) {
|
||||
callbacks->key_left(&context);
|
||||
} else {
|
||||
if (context.offset > 0) {
|
||||
printf("\033[D");
|
||||
fflush(stdout);
|
||||
context.offset--;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case KEY_BACKSPACE:
|
||||
if (context.collected) {
|
||||
if (!context.offset) {
|
||||
continue;
|
||||
}
|
||||
printf("\010 \010");
|
||||
if (context.offset != context.collected) {
|
||||
int remaining = context.collected - context.offset;
|
||||
for (int i = 0; i < remaining; ++i) {
|
||||
printf("%c", context.buffer[context.offset + i]);
|
||||
context.buffer[context.offset + i - 1] = context.buffer[context.offset + i];
|
||||
}
|
||||
printf(" ");
|
||||
for (int i = 0; i < remaining + 1; ++i) {
|
||||
printf("\033[D");
|
||||
}
|
||||
context.offset--;
|
||||
context.collected--;
|
||||
} else {
|
||||
context.buffer[--context.collected] = '\0';
|
||||
context.offset--;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
continue;
|
||||
case KEY_CTRL_A:
|
||||
while (context.offset > 0) {
|
||||
printf("\033[D");
|
||||
context.offset--;
|
||||
}
|
||||
fflush(stdout);
|
||||
continue;
|
||||
case KEY_CTRL_E:
|
||||
while (context.offset < context.collected) {
|
||||
printf("\033[C");
|
||||
context.offset++;
|
||||
}
|
||||
fflush(stdout);
|
||||
continue;
|
||||
case KEY_CTRL_L: /* ^L: Clear Screen, redraw prompt and buffer */
|
||||
printf("\033[H\033[2J");
|
||||
if (callbacks->redraw_prompt) {
|
||||
callbacks->redraw_prompt(&context);
|
||||
}
|
||||
printf("\033[s");
|
||||
rline_redraw_clean(&context);
|
||||
continue;
|
||||
case '\t':
|
||||
if (callbacks->tab_complete) {
|
||||
callbacks->tab_complete(&context);
|
||||
}
|
||||
continue;
|
||||
case '\n':
|
||||
while (context.offset < context.collected) {
|
||||
printf("\033[C");
|
||||
context.offset++;
|
||||
}
|
||||
if (context.collected < context.requested) {
|
||||
context.buffer[context.collected] = '\n';
|
||||
context.buffer[++context.collected] = '\0';
|
||||
context.offset++;
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
context.newline = 1;
|
||||
continue;
|
||||
}
|
||||
if (context.offset != context.collected) {
|
||||
for (int i = context.collected; i > context.offset; --i) {
|
||||
context.buffer[i] = context.buffer[i-1];
|
||||
}
|
||||
if (context.collected < context.requested) {
|
||||
context.buffer[context.offset] = (char)key_sym;
|
||||
context.buffer[++context.collected] = '\0';
|
||||
context.offset++;
|
||||
}
|
||||
for (int i = context.offset - 1; i < context.collected; ++i) {
|
||||
printf("%c", context.buffer[i]);
|
||||
}
|
||||
for (int i = context.offset; i < context.collected; ++i) {
|
||||
printf("\033[D");
|
||||
}
|
||||
fflush(stdout);
|
||||
} else {
|
||||
printf("%c", (char)key_sym);
|
||||
if (context.collected < context.requested) {
|
||||
context.buffer[context.collected] = (char)key_sym;
|
||||
context.buffer[++context.collected] = '\0';
|
||||
context.offset++;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cap that with a null */
|
||||
context.buffer[context.collected] = '\0';
|
||||
return context.collected;
|
||||
}
|
||||
|
||||
void redraw_prompt_func(rline_context_t * context) {
|
||||
draw_prompt(0);
|
||||
}
|
||||
|
@ -9,11 +9,31 @@
|
||||
#define KEY_NONE 0
|
||||
#define KEY_BACKSPACE 8
|
||||
#define KEY_CTRL_A 1
|
||||
#define KEY_CTRL_B 2
|
||||
#define KEY_CTRL_C 3
|
||||
#define KEY_CTRL_D 4
|
||||
#define KEY_CTRL_E 5
|
||||
#define KEY_CTRL_F 6
|
||||
#define KEY_CTRL_G 7
|
||||
#define KEY_CTRL_H 8
|
||||
#define KEY_CTRL_I 9
|
||||
#define KEY_CTRL_J 10
|
||||
#define KEY_CTRL_K 11
|
||||
#define KEY_CTRL_L 12
|
||||
#define KEY_CTRL_M 13
|
||||
#define KEY_CTRL_N 14
|
||||
#define KEY_CTRL_O 15
|
||||
#define KEY_CTRL_P 16
|
||||
#define KEY_CTRL_Q 17
|
||||
#define KEY_CTRL_R 18
|
||||
#define KEY_CTRL_S 19
|
||||
#define KEY_CTRL_T 20
|
||||
#define KEY_CTRL_U 21
|
||||
#define KEY_CTRL_V 22
|
||||
#define KEY_CTRL_W 23
|
||||
#define KEY_CTRL_X 24
|
||||
#define KEY_CTRL_Y 25
|
||||
#define KEY_CTRL_Z 26
|
||||
#define KEY_ESCAPE 27
|
||||
#define KEY_NORMAL_MAX 256
|
||||
#define KEY_ARROW_UP 257
|
||||
|
229
userspace/lib/rline.c
Normal file
229
userspace/lib/rline.c
Normal file
@ -0,0 +1,229 @@
|
||||
/*
|
||||
* rline - a line reading library.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "kbd.h"
|
||||
#include "rline.h"
|
||||
|
||||
void rline_redraw(rline_context_t * context) {
|
||||
printf("\033[u%s\033[K", context->buffer);
|
||||
for (int i = context->offset; i < context->collected; ++i) {
|
||||
printf("\033[D");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
void rline_redraw_clean(rline_context_t * context) {
|
||||
printf("\033[u%s", context->buffer);
|
||||
for (int i = context->offset; i < context->collected; ++i) {
|
||||
printf("\033[D");
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
int rline(char * buffer, int buf_size, rline_callbacks_t * callbacks) {
|
||||
/* Initialize context */
|
||||
rline_context_t context = {
|
||||
buffer,
|
||||
callbacks,
|
||||
0,
|
||||
buf_size,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
0,
|
||||
};
|
||||
|
||||
printf("\033[s");
|
||||
fflush(stdout);
|
||||
|
||||
key_event_state_t kbd_state = {0};
|
||||
|
||||
/* Read keys */
|
||||
while ((context.collected < context.requested) && (!context.newline)) {
|
||||
uint32_t key_sym = kbd_key(&kbd_state, fgetc(stdin));
|
||||
if (key_sym == KEY_NONE) continue;
|
||||
switch (key_sym) {
|
||||
case KEY_CTRL_C:
|
||||
printf("^C\n");
|
||||
context.buffer[0] = '\0';
|
||||
return 0;
|
||||
case KEY_CTRL_D:
|
||||
if (context.collected == 0) {
|
||||
printf("exit\n");
|
||||
sprintf(context.buffer, "exit\n");
|
||||
return strlen(context.buffer);
|
||||
}
|
||||
continue;
|
||||
case KEY_CTRL_R:
|
||||
if (callbacks->rev_search) {
|
||||
callbacks->rev_search(&context);
|
||||
return context.collected;
|
||||
}
|
||||
continue;
|
||||
case KEY_ARROW_UP:
|
||||
if (callbacks->key_up) {
|
||||
callbacks->key_up(&context);
|
||||
}
|
||||
continue;
|
||||
case KEY_ARROW_DOWN:
|
||||
if (callbacks->key_down) {
|
||||
callbacks->key_down(&context);
|
||||
}
|
||||
continue;
|
||||
case KEY_ARROW_RIGHT:
|
||||
if (callbacks->key_right) {
|
||||
callbacks->key_right(&context);
|
||||
} else {
|
||||
if (context.offset < context.collected) {
|
||||
printf("\033[C");
|
||||
fflush(stdout);
|
||||
context.offset++;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case KEY_ARROW_LEFT:
|
||||
if (callbacks->key_left) {
|
||||
callbacks->key_left(&context);
|
||||
} else {
|
||||
if (context.offset > 0) {
|
||||
printf("\033[D");
|
||||
fflush(stdout);
|
||||
context.offset--;
|
||||
}
|
||||
}
|
||||
continue;
|
||||
case KEY_BACKSPACE:
|
||||
if (context.collected) {
|
||||
if (!context.offset) {
|
||||
continue;
|
||||
}
|
||||
printf("\010 \010");
|
||||
if (context.offset != context.collected) {
|
||||
int remaining = context.collected - context.offset;
|
||||
for (int i = 0; i < remaining; ++i) {
|
||||
printf("%c", context.buffer[context.offset + i]);
|
||||
context.buffer[context.offset + i - 1] = context.buffer[context.offset + i];
|
||||
}
|
||||
printf(" ");
|
||||
for (int i = 0; i < remaining + 1; ++i) {
|
||||
printf("\033[D");
|
||||
}
|
||||
context.offset--;
|
||||
context.collected--;
|
||||
} else {
|
||||
context.buffer[--context.collected] = '\0';
|
||||
context.offset--;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
continue;
|
||||
case KEY_CTRL_A:
|
||||
while (context.offset > 0) {
|
||||
printf("\033[D");
|
||||
context.offset--;
|
||||
}
|
||||
fflush(stdout);
|
||||
continue;
|
||||
case KEY_CTRL_E:
|
||||
while (context.offset < context.collected) {
|
||||
printf("\033[C");
|
||||
context.offset++;
|
||||
}
|
||||
fflush(stdout);
|
||||
continue;
|
||||
case KEY_CTRL_L: /* ^L: Clear Screen, redraw prompt and buffer */
|
||||
printf("\033[H\033[2J");
|
||||
if (callbacks->redraw_prompt) {
|
||||
callbacks->redraw_prompt(&context);
|
||||
}
|
||||
printf("\033[s");
|
||||
rline_redraw_clean(&context);
|
||||
continue;
|
||||
case KEY_CTRL_W:
|
||||
/*
|
||||
* Erase word before cursor.
|
||||
* If the character before the cursor is a space, delete it.
|
||||
* Continue deleting until the previous character is a space.
|
||||
*/
|
||||
if (context.collected) {
|
||||
if (!context.offset) {
|
||||
continue;
|
||||
}
|
||||
do {
|
||||
printf("\010 \010");
|
||||
if (context.offset != context.collected) {
|
||||
int remaining = context.collected - context.offset;
|
||||
for (int i = 0; i < remaining; ++i) {
|
||||
printf("%c", context.buffer[context.offset + i]);
|
||||
context.buffer[context.offset + i - 1] = context.buffer[context.offset + i];
|
||||
}
|
||||
printf(" ");
|
||||
for (int i = 0; i < remaining + 1; ++i) {
|
||||
printf("\033[D");
|
||||
}
|
||||
context.offset--;
|
||||
context.collected--;
|
||||
} else {
|
||||
context.buffer[--context.collected] = '\0';
|
||||
context.offset--;
|
||||
}
|
||||
} while ((context.offset) && (context.buffer[context.offset-1] != ' '));
|
||||
fflush(stdout);
|
||||
}
|
||||
continue;
|
||||
case '\t':
|
||||
if (callbacks->tab_complete) {
|
||||
callbacks->tab_complete(&context);
|
||||
}
|
||||
continue;
|
||||
case '\n':
|
||||
while (context.offset < context.collected) {
|
||||
printf("\033[C");
|
||||
context.offset++;
|
||||
}
|
||||
if (context.collected < context.requested) {
|
||||
context.buffer[context.collected] = '\n';
|
||||
context.buffer[++context.collected] = '\0';
|
||||
context.offset++;
|
||||
}
|
||||
printf("\n");
|
||||
fflush(stdout);
|
||||
context.newline = 1;
|
||||
continue;
|
||||
}
|
||||
if (context.offset != context.collected) {
|
||||
for (int i = context.collected; i > context.offset; --i) {
|
||||
context.buffer[i] = context.buffer[i-1];
|
||||
}
|
||||
if (context.collected < context.requested) {
|
||||
context.buffer[context.offset] = (char)key_sym;
|
||||
context.buffer[++context.collected] = '\0';
|
||||
context.offset++;
|
||||
}
|
||||
for (int i = context.offset - 1; i < context.collected; ++i) {
|
||||
printf("%c", context.buffer[i]);
|
||||
}
|
||||
for (int i = context.offset; i < context.collected; ++i) {
|
||||
printf("\033[D");
|
||||
}
|
||||
fflush(stdout);
|
||||
} else {
|
||||
printf("%c", (char)key_sym);
|
||||
if (context.collected < context.requested) {
|
||||
context.buffer[context.collected] = (char)key_sym;
|
||||
context.buffer[++context.collected] = '\0';
|
||||
context.offset++;
|
||||
}
|
||||
fflush(stdout);
|
||||
}
|
||||
}
|
||||
|
||||
/* Cap that with a null */
|
||||
context.buffer[context.collected] = '\0';
|
||||
return context.collected;
|
||||
}
|
35
userspace/lib/rline.h
Normal file
35
userspace/lib/rline.h
Normal file
@ -0,0 +1,35 @@
|
||||
#ifndef _RLINE_H
|
||||
#define _RLINE_H
|
||||
|
||||
struct rline_callback;
|
||||
|
||||
typedef struct {
|
||||
char * buffer;
|
||||
struct rline_callback * callbacks;
|
||||
int collected;
|
||||
int requested;
|
||||
int newline;
|
||||
int cancel;
|
||||
int offset;
|
||||
int tabbed;
|
||||
} rline_context_t;
|
||||
|
||||
typedef void (*rline_callback_t)(rline_context_t * context);
|
||||
|
||||
typedef struct rline_callback {
|
||||
rline_callback_t tab_complete;
|
||||
rline_callback_t redraw_prompt;
|
||||
rline_callback_t special_key;
|
||||
rline_callback_t key_up;
|
||||
rline_callback_t key_down;
|
||||
rline_callback_t key_left;
|
||||
rline_callback_t key_right;
|
||||
rline_callback_t rev_search;
|
||||
} rline_callbacks_t;
|
||||
|
||||
void rline_redraw(rline_context_t * context);
|
||||
void rline_redraw_clean(rline_context_t * context);
|
||||
int rline(char * buffer, int buf_size, rline_callbacks_t * callbacks);
|
||||
|
||||
#endif /* _RLINE_H */
|
||||
|
@ -37,6 +37,7 @@ class Classifier(object):
|
||||
'"lib/pex.h"': (None, 'userspace/lib/pex.o', []),
|
||||
'"lib/graphics.h"': (None, 'userspace/lib/graphics.o', ['<png.h>']),
|
||||
'"lib/shmemfonts.h"': (None, 'userspace/lib/shmemfonts.o', ['"lib/graphics.h"', '<ft2build.h>']),
|
||||
'"lib/rline.h"': (None, 'userspace/lib/rline.o', ['"lib/kbd.h"']),
|
||||
# Yutani Libraries
|
||||
'"lib/yutani.h"': (None, 'userspace/lib/yutani.o', ['"lib/list.h"', '"lib/pex.h"', '"lib/graphics.h"', '"lib/hashmap.h"']),
|
||||
'"lib/decorations.h"': (None, 'userspace/lib/decorations.o', ['"lib/shmemfonts.h"', '"lib/graphics.h"', '"lib/yutani.h"']),
|
||||
|
Loading…
Reference in New Issue
Block a user