diff options
| -rw-r--r-- | config.def.h | 77 | ||||
| -rw-r--r-- | main.c | 4 | ||||
| -rw-r--r-- | vis.c | 126 | ||||
| -rw-r--r-- | vis.h | 16 |
4 files changed, 209 insertions, 14 deletions
diff --git a/config.def.h b/config.def.h index f4d20a3..4eb0d2b 100644 --- a/config.def.h +++ b/config.def.h @@ -29,6 +29,8 @@ enum { VIS_MODE_REGISTER, VIS_MODE_NORMAL, VIS_MODE_VISUAL, + VIS_MODE_READLINE, + VIS_MODE_PROMPT, VIS_MODE_INSERT, VIS_MODE_REPLACE, }; @@ -459,6 +461,26 @@ static void insert_register(const Arg *arg) { vis_insert(vis, window_cursor_get(vis->win->win), reg->data, reg->len); } +static void prompt(const Arg *arg) { + vis_prompt_show(vis, arg->s); + switchmode(&(const Arg){ .i = VIS_MODE_PROMPT }); +} + +static void prompt_enter(const Arg *arg) { + char *s = vis_prompt_get(vis); + fprintf(stderr, "prompt: %s\n", s); + free(s); + switchmode(&(const Arg){ .i = VIS_MODE_NORMAL }); +} + +static void prompt_up(const Arg *arg) { + +} + +static void prompt_down(const Arg *arg) { + +} + static void insert_verbatim(const Arg *arg) { int value = 0; for (int i = 0; i < 3; i++) { @@ -581,11 +603,11 @@ static KeyBinding vis_operators[] = { { /* empty last element, array terminator */ }, }; -static void vis_operators_enter(void) { +static void vis_operators_enter(Mode *old) { vis_modes[VIS_MODE_OPERATOR].parent = &vis_modes[VIS_MODE_OPERATOR_OPTION]; } -static void vis_operators_leave(void) { +static void vis_operators_leave(Mode *new) { vis_modes[VIS_MODE_OPERATOR].parent = &vis_modes[VIS_MODE_MOVE]; } @@ -639,6 +661,9 @@ static KeyBinding vis_normal[] = { { { NONE('u') }, call, { .f = vis_undo } }, { { CONTROL('R') }, call, { .f = vis_redo } }, { { CONTROL('L') }, call, { .f = vis_draw } }, + { { NONE(':') }, prompt, { .s = ":" } }, + { { NONE('/') }, prompt, { .s = "/" } }, + { { NONE('?') }, prompt, { .s = "?" } }, { /* empty last element, array terminator */ }, }; @@ -656,27 +681,43 @@ static KeyBinding vis_visual[] = { { /* empty last element, array terminator */ }, }; -static void vis_visual_enter(void) { +static void vis_visual_enter(Mode *old) { window_selection_start(vis->win->win); } -static void vis_visual_leave(void) { +static void vis_visual_leave(Mode *new) { window_selection_clear(vis->win->win); } -static KeyBinding vis_insert_mode[] = { +static KeyBinding vis_readline_mode[] = { { { NONE(ESC) }, switchmode, { .i = VIS_MODE_NORMAL } }, { { CONTROL('c') }, switchmode, { .i = VIS_MODE_NORMAL } }, + BACKSPACE( call, f, vis_backspace_key ), + { { CONTROL('D') }, call, { .f = vis_delete_key } }, + { { CONTROL('W') }, delete_word, { NULL } }, + { /* empty last element, array terminator */ }, +}; + +static KeyBinding vis_prompt_mode[] = { + { { KEY(ENTER) }, prompt_enter, { NULL } }, + { { CONTROL('J') }, prompt_enter, { NULL } }, + { { KEY(UP) }, prompt_up, { NULL } }, + { { KEY(DOWN) }, prompt_down, { NULL } }, + { /* empty last element, array terminator */ }, +}; + +static void vis_prompt_leave(Mode *new) { + if (new != &vis_modes[VIS_MODE_OPERATOR]) + vis_prompt_hide(vis); +} + +static KeyBinding vis_insert_mode[] = { { { CONTROL('L') }, switchmode, { .i = VIS_MODE_NORMAL } }, { { CONTROL('[') }, switchmode, { .i = VIS_MODE_NORMAL } }, - { { CONTROL('D') }, call, { .f = vis_delete_key } }, - BACKSPACE( call, f, vis_backspace_key ), - { { CONTROL('H') }, call, { .f = vis_backspace_key } }, { { CONTROL('I') }, insert_tab, { NULL } }, { { CONTROL('J') }, insert_newline, { NULL } }, { { CONTROL('M') }, insert_newline, { NULL } }, { { CONTROL('O') }, switchmode, { .i = VIS_MODE_OPERATOR } }, - { { CONTROL('W') }, delete_word, { NULL } }, { { CONTROL('R'), NONE('a') }, insert_register, { .i = REG_a } }, { { CONTROL('R'), NONE('b') }, insert_register, { .i = REG_b } }, { { CONTROL('R'), NONE('c') }, insert_register, { .i = REG_c } }, @@ -764,9 +805,21 @@ static Mode vis_modes[] = { .enter = vis_visual_enter, .leave = vis_visual_leave, }, + [VIS_MODE_READLINE] = { + .name = "READLINE", + .parent = &vis_modes[VIS_MODE_BASIC], + .bindings = vis_readline_mode, + }, + [VIS_MODE_PROMPT] = { + .name = "PROMPT", + .parent = &vis_modes[VIS_MODE_READLINE], + .bindings = vis_prompt_mode, + .input = vis_insert_input, + .leave = vis_prompt_leave, + }, [VIS_MODE_INSERT] = { .name = "INSERT", - .parent = &vis_modes[VIS_MODE_BASIC], + .parent = &vis_modes[VIS_MODE_READLINE], .bindings = vis_insert_mode, .input = vis_insert_input, }, @@ -782,12 +835,12 @@ static void switchmode_to(Mode *new_mode) { if (mode == new_mode) return; if (mode->leave) - mode->leave(); + mode->leave(new_mode); mode_prev = mode; //fprintf(stderr, "%s -> %s\n", mode_prev->name, new_mode->name); mode = new_mode; if (mode->enter) - mode->enter(); + mode->enter(mode_prev); // TODO display mode name somewhere? } @@ -43,8 +43,8 @@ struct Mode { KeyBinding *bindings; const char *name; bool common_prefix; - void (*enter)(void); - void (*leave)(void); + void (*enter)(Mode *old); + void (*leave)(Mode *new); bool (*unknown)(Key *key0, Key *key1); /* unknown key for this mode, return value determines whether parent modes will be checked */ bool (*input)(const char *str, size_t len); /* unknown key for this an all parent modes */ }; @@ -1,4 +1,6 @@ +#define _BSD_SOURCE #include <stdlib.h> +#include <string.h> #include "vis.h" #include "util.h" @@ -12,6 +14,13 @@ static void vis_search_backward(Vis *vis, Regex *regex); static void vis_windows_arrange_horizontal(Vis *vis); static void vis_windows_arrange_vertical(Vis *vis); +static Prompt *vis_prompt_new(); +static void vis_prompt_free(Prompt *prompt); +static void vis_prompt_clear(Prompt *prompt); +static void vis_prompt_resize(Prompt *prompt, int width, int height); +static void vis_prompt_move(Prompt *prompt, int x, int y); +static void vis_prompt_draw(Prompt *prompt); +static void vis_prompt_update(Prompt *prompt); static void vis_window_resize(VisWin *win, int width, int height) { window_resize(win->win, width, win->statuswin ? height - 1 : height); @@ -163,6 +172,12 @@ void vis_window_vsplit(Vis *vis, const char *filename) { void vis_resize(Vis *vis, int width, int height) { vis->width = width; vis->height = height; + if (vis->prompt->active) { + vis->height--; + vis_prompt_resize(vis->prompt, vis->width, 1); + vis_prompt_move(vis->prompt, 0, vis->height); + vis_prompt_draw(vis->prompt); + } vis_draw(vis); } @@ -268,6 +283,8 @@ void vis_update(Vis *vis) { if (vis->win->statuswin) wnoutrefresh(vis->win->statuswin); + if (vis->prompt && vis->prompt->active) + vis_prompt_update(vis->prompt); window_update(vis->win->win); } @@ -333,6 +350,10 @@ Vis *vis_new(int width, int height) { Vis *vis = calloc(1, sizeof(Vis)); if (!vis) return NULL; + if (!(vis->prompt = vis_prompt_new())) { + vis_free(vis); + return NULL; + } vis->width = width; vis->height = height; vis->windows_arrange = vis_windows_arrange_horizontal; @@ -344,6 +365,7 @@ void vis_free(Vis *vis) { next = win->next; vis_window_free(win); } + vis_prompt_free(vis->prompt); free(vis); } @@ -382,3 +404,107 @@ void vis_delete(Vis *vis, size_t pos, size_t len) { text_delete(vis->win->text, pos, len); vis_windows_invalidate(vis, pos, pos + len); } + + +static void vis_prompt_free(Prompt *prompt) { + if (!prompt) + return; + vis_window_free(prompt->win); + if (prompt->titlewin) + delwin(prompt->titlewin); + free(prompt->title); + free(prompt); +} + +static Prompt *vis_prompt_new() { + Text *text = text_load(NULL); + if (!text) + return NULL; + Prompt *prompt = calloc(1, sizeof(Prompt)); + if (!prompt) + goto err; + + if (!(prompt->win = calloc(1, sizeof(VisWin)))) + goto err; + + if (!(prompt->win->win = window_new(text))) + goto err; + + prompt->win->text = text; + + if (!(prompt->titlewin = newwin(0, 0, 0, 0))) + goto err; + + return prompt; +err: + if (!prompt || !prompt->win) + text_free(text); + vis_prompt_free(prompt); + return NULL; +} + +static void vis_prompt_resize(Prompt *prompt, int width, int height) { + size_t title_width = strlen(prompt->title); + wresize(prompt->titlewin, height, title_width); + vis_window_resize(prompt->win, width - title_width, height); +} + +static void vis_prompt_move(Prompt *prompt, int x, int y) { + size_t title_width = strlen(prompt->title); + mvwin(prompt->titlewin, y, x); + vis_window_move(prompt->win, x + title_width, y); +} + +void vis_prompt_show(Vis *vis, const char *title) { + Prompt *prompt = vis->prompt; + if (prompt->active) + return; + prompt->active = true; + prompt->editor = vis->win; + vis->win = prompt->win; + free(prompt->title); + prompt->title = strdup(title); + vis_resize(vis, vis->width, vis->height); +} + +static void vis_prompt_draw(Prompt *prompt) { + mvwaddstr(prompt->titlewin, 0, 0, prompt->title); +} + +static void vis_prompt_update(Prompt *prompt) { + wnoutrefresh(prompt->titlewin); +} + +static void vis_prompt_clear(Prompt *prompt) { + Text *text = prompt->win->text; + while (text_undo(text)); +} + +void vis_prompt_hide(Vis *vis) { + Prompt *prompt = vis->prompt; + if (!prompt->active) + return; + prompt->active = false; + vis->win = prompt->editor; + prompt->editor = NULL; + vis->height++; + vis_prompt_clear(prompt); + vis_draw(vis); +} + +void vis_prompt_set(Vis *vis, const char *line) { + Text *text = vis->prompt->win->text; + vis_prompt_clear(vis->prompt); + text_insert_raw(text, 0, line, strlen(line)); + vis_window_draw(vis->prompt->win); +} + +char *vis_prompt_get(Vis *vis) { + Text *text = vis->prompt->win->text; + char *buf = malloc(text_size(text) + 1); + if (!buf) + return NULL; + size_t len = text_bytes_get(text, 0, text_size(text), buf); + buf[len] = '\0'; + return buf; +} @@ -20,6 +20,14 @@ struct VisWin { VisWin *prev, *next; /* neighbouring windows */ }; +typedef struct { + VisWin *win; + VisWin *editor; /* active editor window before prompt is shown */ + char *title; + WINDOW *titlewin; + bool active; +} Prompt; + typedef void (*vis_statusbar_t)(WINDOW *win, bool active, const char *filename, size_t line, size_t col); enum Reg { @@ -47,6 +55,7 @@ struct Vis { VisWin *win; /* currently active window */ Syntax *syntaxes; /* NULL terminated array of syntax definitions */ Register registers[REG_LAST]; + Prompt *prompt; void (*windows_arrange)(Vis*); /* current layout which places the windows */ vis_statusbar_t statusbar; /* configurable user hook to draw statusbar */ }; @@ -102,6 +111,13 @@ void vis_window_vsplit(Vis*, const char *filename); void vis_window_next(Vis*); void vis_window_prev(Vis*); + +char *vis_prompt_get(Vis *vis); +void vis_prompt_set(Vis *vis, const char *line); +void vis_prompt_show(Vis *vis, const char *title); +void vis_prompt_hide(Vis *vis); + + void vis_statusbar_set(Vis*, vis_statusbar_t); /* library initialization code, should be run at startup */ |
