diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2015-07-28 12:10:22 +0200 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2015-07-28 13:21:50 +0200 |
| commit | b366f55f29af3775c055115572dd84873b1921e0 (patch) | |
| tree | b9c6a710997272d8b84238965e6f992abfbed42c | |
| parent | a19159c506577a168655afcd961381dd1f995610 (diff) | |
| download | vis-b366f55f29af3775c055115572dd84873b1921e0.tar.gz vis-b366f55f29af3775c055115572dd84873b1921e0.tar.xz | |
vis: use multiple cursor/selection infrastructure
This commits introduces the following keybindings, in normal mode:
CTRL-N select word the cursor is currently over, switch to visual mode
CTRL-P remove least recently added cursor
ESC if a selection is active, clear it.
Otherwise dispose all but the primary cursor.
In visual mode:
CTRL-N create new cursor and select next word matching current selection
CTRL-X clear (skip) current selection, but select next matching word
CTRL-P remove least recently added cursor
| -rw-r--r-- | config.def.h | 5 | ||||
| -rw-r--r-- | view.c | 11 | ||||
| -rw-r--r-- | view.h | 5 | ||||
| -rw-r--r-- | vis.c | 61 |
4 files changed, 81 insertions, 1 deletions
diff --git a/config.def.h b/config.def.h index 4402cd0..859b3db 100644 --- a/config.def.h +++ b/config.def.h @@ -363,6 +363,8 @@ static KeyBinding vis_mode_normal[] = { { { CONTROL('K') }, cursors_new, { .i = -1 } }, { { CONTROL('J') }, cursors_new, { .i = +1 } }, { { CONTROL('A') }, cursors_align, { } }, + { { CONTROL('N') }, cursors_select, { } }, + { { CONTROL('P') }, cursors_remove, { } }, { { CONTROL('w'), NONE('n') }, cmd, { .s = "open" } }, { { CONTROL('w'), NONE('c') }, cmd, { .s = "q" } }, { { CONTROL('w'), NONE('s') }, cmd, { .s = "split" } }, @@ -423,6 +425,9 @@ static KeyBinding vis_mode_normal[] = { }; static KeyBinding vis_mode_visual[] = { + { { CONTROL('N') }, cursors_select_next, { } }, + { { CONTROL('X') }, cursors_select_skip, { } }, + { { CONTROL('P') }, cursors_remove, { } }, { { KEY(BACKSPACE) }, operator, { .i = OP_DELETE } }, { { KEY(DELETE) }, operator, { .i = OP_DELETE } }, { { CONTROL('O') }, operator, { .i = OP_CURSOR } }, @@ -912,6 +912,17 @@ void view_cursors_free(Cursor *c) { free(c); } +void view_cursors_dispose(Cursor *c) { + if (!c) + return; + View *view = c->view; + if (view->cursors && view->cursors->next) { + view_selections_free(c->sel); + view_cursors_free(c); + view_draw(view); + } +} + Cursor *view_cursors(View *view) { return view->cursors; } @@ -117,7 +117,10 @@ void view_cursor_to(View*, size_t pos); Cursor *view_cursors_new(View*); /* get number of active cursors */ int view_cursors_count(View*); -/* dispose an existing cursor */ +/* dispose an existing cursor with its associated selection (if any), + * not applicaple for the last existing cursor */ +void view_cursors_dispose(Cursor*); +/* dispose an existing cursor, no matter what */ void view_cursors_free(Cursor*); /* only keep the main cursor, release all others together with their * selections (if any) */ @@ -326,6 +326,14 @@ static void cursors_new(const Arg *arg); static void cursors_align(const Arg *arg); /* remove all but the primary cursor and their selections */ static void cursors_clear(const Arg *arg); +/* remove the least recently added cursor */ +static void cursors_remove(const Arg *arg); +/* select the word the cursor is currently over */ +static void cursors_select(const Arg *arg); +/* select the next region matching the current selection */ +static void cursors_select_next(const Arg *arg); +/* clear current selection but select next match */ +static void cursors_select_skip(const Arg *arg); /* adjust action.count by arg->i */ static void count(const Arg *arg); /* move to the action.count-th line or if not given either to the first (arg->i < 0) @@ -869,6 +877,59 @@ static void cursors_clear(const Arg *arg) { view_cursors_selection_clear(view_cursor(view)); } +static void cursors_select(const Arg *arg) { + Text *txt = vis->win->file->text; + View *view = vis->win->view; + for (Cursor *cursor = view_cursors(view); cursor; cursor = view_cursors_next(cursor)) { + Filerange sel = view_cursors_selection_get(cursor); + Filerange word = text_object_word(txt, view_cursors_pos(cursor)); + if (!text_range_valid(&sel) && text_range_valid(&word)) { + view_cursors_selection_set(cursor, &word); + view_cursors_to(cursor, text_char_prev(txt, word.end)); + } + } + switchmode(&(const Arg){ .i = VIS_MODE_VISUAL }); +} + +static void cursors_select_next(const Arg *arg) { + Text *txt = vis->win->file->text; + View *view = vis->win->view; + Cursor *cursor = view_cursor(view); + Filerange sel = view_cursors_selection_get(cursor); + if (!text_range_valid(&sel)) + return; + + size_t len = text_range_size(&sel); + char *buf = malloc(len+1); + if (!buf) + return; + len = text_bytes_get(txt, sel.start, len, buf); + buf[len] = '\0'; + Filerange word = text_object_word_find_next(txt, sel.end, buf); + free(buf); + + if (text_range_valid(&word)) { + cursor = view_cursors_new(view); + if (!cursor) + return; + view_cursors_selection_set(cursor, &word); + view_cursors_to(cursor, text_char_prev(txt, word.end)); + } +} + +static void cursors_select_skip(const Arg *arg) { + View *view = vis->win->view; + Cursor *cursor = view_cursor(view); + cursors_select_next(arg); + if (cursor != view_cursor(view)) + view_cursors_dispose(cursor); +} + +static void cursors_remove(const Arg *arg) { + View *view = vis->win->view; + view_cursors_dispose(view_cursor(view)); +} + static void replace(const Arg *arg) { Key k = getkey(); if (!k.str[0]) |
