diff options
| -rw-r--r-- | config.def.h | 4 | ||||
| -rw-r--r-- | editor.h | 3 | ||||
| -rw-r--r-- | view.c | 20 | ||||
| -rw-r--r-- | view.h | 2 | ||||
| -rw-r--r-- | vis.c | 135 |
5 files changed, 73 insertions, 91 deletions
diff --git a/config.def.h b/config.def.h index 859b3db..181dc7c 100644 --- a/config.def.h +++ b/config.def.h @@ -229,8 +229,8 @@ static void vis_mode_operator_input(const char *str, size_t len) { } static KeyBinding vis_operator_options[] = { - { { NONE('v') }, linewise, { .b = false } }, - { { NONE('V') }, linewise, { .b = true } }, + { { NONE('v') }, motiontype, { .i = CHARWISE } }, + { { NONE('V') }, motiontype, { .i = LINEWISE } }, { /* empty last element, array terminator */ }, }; @@ -67,7 +67,6 @@ typedef struct { size_t pos; /* at which byte from the start of the file should the operation start? */ bool linewise; /* should the changes always affect whole lines? */ const Arg *arg; /* arbitrary arguments */ - Cursor *cursor; /* cursor (if any) which issued this operator */ } OperatorContext; typedef struct { @@ -100,7 +99,7 @@ typedef struct { typedef struct { /** collects all information until an operator is executed */ int count; - bool linewise; + int type; const Operator *op; const Movement *movement; const TextObject *textobj; @@ -1005,14 +1005,20 @@ void view_cursors_selection_clear(Cursor *c) { void view_cursors_selection_swap(Cursor *c) { if (!c->sel) return; - Text *txt = c->view->text; - bool left_extending = c->mark == c->sel->cursor; view_selections_swap(c->sel); - c->mark = c->sel->cursor; - size_t pos = text_mark_get(txt, c->mark); - if (left_extending) - pos = text_char_prev(txt, pos); - cursor_to(c, pos); + view_cursors_selection_sync(c); +} + +void view_cursors_selection_sync(Cursor *c) { + if (!c->sel) + return; + Text *txt = c->view->text; + size_t anchor = text_mark_get(txt, c->sel->anchor); + size_t cursor = text_mark_get(txt, c->sel->cursor); + bool right_extending = anchor < cursor; + if (right_extending) + cursor = text_char_prev(txt, cursor); + cursor_to(c, cursor); } Filerange view_cursors_selection_get(Cursor *c) { @@ -148,6 +148,8 @@ void view_cursors_selection_stop(Cursor*); void view_cursors_selection_clear(Cursor*); /* move cursor position from one end of the selection to the other */ void view_cursors_selection_swap(Cursor*); +/* move cursor to the end/boundary of the associated selection */ +void view_cursors_selection_sync(Cursor*); /* get/set the selected region associated with this cursor */ Filerange view_cursors_selection_get(Cursor*); void view_cursors_selection_set(Cursor*, Filerange*); @@ -175,20 +175,20 @@ static size_t view_lines_middle(const Arg *arg); static size_t view_lines_bottom(const Arg *arg); static Movement moves[] = { - [MOVE_LINE_UP] = { .view = view_line_up }, - [MOVE_LINE_DOWN] = { .view = view_line_down }, - [MOVE_SCREEN_LINE_UP] = { .view = view_screenline_up }, - [MOVE_SCREEN_LINE_DOWN] = { .view = view_screenline_down }, - [MOVE_SCREEN_LINE_BEGIN] = { .view = view_screenline_begin, .type = CHARWISE }, - [MOVE_SCREEN_LINE_MIDDLE] = { .view = view_screenline_middle, .type = CHARWISE }, - [MOVE_SCREEN_LINE_END] = { .view = view_screenline_end, .type = CHARWISE|INCLUSIVE }, - [MOVE_LINE_PREV] = { .txt = text_line_prev, .type = LINEWISE }, - [MOVE_LINE_BEGIN] = { .txt = text_line_begin, .type = LINEWISE }, - [MOVE_LINE_START] = { .txt = text_line_start, .type = LINEWISE }, - [MOVE_LINE_FINISH] = { .txt = text_line_finish, .type = LINEWISE|INCLUSIVE }, - [MOVE_LINE_LASTCHAR] = { .txt = text_line_lastchar, .type = LINEWISE|INCLUSIVE }, - [MOVE_LINE_END] = { .txt = text_line_end, .type = LINEWISE }, - [MOVE_LINE_NEXT] = { .txt = text_line_next, .type = LINEWISE }, + [MOVE_LINE_UP] = { .view = view_line_up, .type = LINEWISE }, + [MOVE_LINE_DOWN] = { .view = view_line_down, .type = LINEWISE }, + [MOVE_SCREEN_LINE_UP] = { .view = view_screenline_up, }, + [MOVE_SCREEN_LINE_DOWN] = { .view = view_screenline_down, }, + [MOVE_SCREEN_LINE_BEGIN] = { .view = view_screenline_begin, .type = CHARWISE }, + [MOVE_SCREEN_LINE_MIDDLE] = { .view = view_screenline_middle, .type = CHARWISE }, + [MOVE_SCREEN_LINE_END] = { .view = view_screenline_end, .type = CHARWISE|INCLUSIVE }, + [MOVE_LINE_PREV] = { .txt = text_line_prev, }, + [MOVE_LINE_BEGIN] = { .txt = text_line_begin, }, + [MOVE_LINE_START] = { .txt = text_line_start, }, + [MOVE_LINE_FINISH] = { .txt = text_line_finish, .type = INCLUSIVE }, + [MOVE_LINE_LASTCHAR] = { .txt = text_line_lastchar, .type = INCLUSIVE }, + [MOVE_LINE_END] = { .txt = text_line_end, }, + [MOVE_LINE_NEXT] = { .txt = text_line_next, }, [MOVE_LINE] = { .txt = line, .type = LINEWISE|IDEMPOTENT|JUMP}, [MOVE_COLUMN] = { .txt = column, .type = CHARWISE|IDEMPOTENT}, [MOVE_CHAR_PREV] = { .txt = text_char_prev, .type = CHARWISE }, @@ -207,19 +207,19 @@ static Movement moves[] = { [MOVE_SENTENCE_NEXT] = { .txt = text_sentence_next, .type = LINEWISE }, [MOVE_PARAGRAPH_PREV] = { .txt = text_paragraph_prev, .type = LINEWISE|JUMP }, [MOVE_PARAGRAPH_NEXT] = { .txt = text_paragraph_next, .type = LINEWISE|JUMP }, - [MOVE_BRACKET_MATCH] = { .txt = text_bracket_match, .type = LINEWISE|INCLUSIVE|JUMP }, + [MOVE_BRACKET_MATCH] = { .txt = text_bracket_match, .type = INCLUSIVE|JUMP }, [MOVE_FILE_BEGIN] = { .txt = text_begin, .type = LINEWISE|JUMP }, [MOVE_FILE_END] = { .txt = text_end, .type = LINEWISE|JUMP }, - [MOVE_LEFT_TO] = { .txt = to_left, .type = LINEWISE }, - [MOVE_RIGHT_TO] = { .txt = to, .type = LINEWISE|INCLUSIVE }, - [MOVE_LEFT_TILL] = { .txt = till_left, .type = LINEWISE }, - [MOVE_RIGHT_TILL] = { .txt = till, .type = LINEWISE|INCLUSIVE }, - [MOVE_MARK] = { .file = mark_goto, .type = LINEWISE|JUMP|IDEMPOTENT }, - [MOVE_MARK_LINE] = { .file = mark_line_goto, .type = LINEWISE|JUMP|IDEMPOTENT }, - [MOVE_SEARCH_WORD_FORWARD] = { .txt = search_word_forward, .type = LINEWISE|JUMP }, - [MOVE_SEARCH_WORD_BACKWARD]= { .txt = search_word_backward, .type = LINEWISE|JUMP }, - [MOVE_SEARCH_FORWARD] = { .txt = search_forward, .type = LINEWISE|JUMP }, - [MOVE_SEARCH_BACKWARD] = { .txt = search_backward, .type = LINEWISE|JUMP }, + [MOVE_LEFT_TO] = { .txt = to_left, }, + [MOVE_RIGHT_TO] = { .txt = to, .type = INCLUSIVE }, + [MOVE_LEFT_TILL] = { .txt = till_left, }, + [MOVE_RIGHT_TILL] = { .txt = till, .type = INCLUSIVE }, + [MOVE_MARK] = { .file = mark_goto, .type = JUMP|IDEMPOTENT }, + [MOVE_MARK_LINE] = { .file = mark_line_goto, .type = LINEWISE|JUMP|IDEMPOTENT}, + [MOVE_SEARCH_WORD_FORWARD] = { .txt = search_word_forward, .type = JUMP }, + [MOVE_SEARCH_WORD_BACKWARD]= { .txt = search_word_backward, .type = JUMP }, + [MOVE_SEARCH_FORWARD] = { .txt = search_forward, .type = JUMP }, + [MOVE_SEARCH_BACKWARD] = { .txt = search_backward, .type = JUMP }, [MOVE_WINDOW_LINE_TOP] = { .cmd = view_lines_top, .type = LINEWISE|JUMP|IDEMPOTENT }, [MOVE_WINDOW_LINE_MIDDLE] = { .cmd = view_lines_middle, .type = LINEWISE|JUMP|IDEMPOTENT }, [MOVE_WINDOW_LINE_BOTTOM] = { .cmd = view_lines_bottom, .type = LINEWISE|JUMP|IDEMPOTENT }, @@ -231,8 +231,6 @@ enum { TEXT_OBJ_OUTER_WORD, TEXT_OBJ_INNER_LONGWORD, TEXT_OBJ_OUTER_LONGWORD, - TEXT_OBJ_LINE_UP, - TEXT_OBJ_LINE_DOWN, TEXT_OBJ_SENTENCE, TEXT_OBJ_PARAGRAPH, TEXT_OBJ_OUTER_SQUARE_BRACKET, @@ -256,8 +254,6 @@ static TextObject textobjs[] = { [TEXT_OBJ_OUTER_WORD] = { text_object_word_outer }, [TEXT_OBJ_INNER_LONGWORD] = { text_object_longword }, [TEXT_OBJ_OUTER_LONGWORD] = { text_object_longword_outer }, - [TEXT_OBJ_LINE_UP] = { text_object_line }, - [TEXT_OBJ_LINE_DOWN] = { text_object_line }, [TEXT_OBJ_SENTENCE] = { text_object_sentence }, [TEXT_OBJ_PARAGRAPH] = { text_object_paragraph }, [TEXT_OBJ_OUTER_SQUARE_BRACKET] = { text_object_square_bracket, OUTER }, @@ -276,14 +272,6 @@ static TextObject textobjs[] = { [TEXT_OBJ_INNER_BACKTICK] = { text_object_backtick, INNER }, }; -/* if some movements are forced to be linewise, they are translated to text objects */ -static TextObject *moves_linewise[] = { - [MOVE_LINE_UP] = &textobjs[TEXT_OBJ_LINE_UP], - [MOVE_LINE_DOWN] = &textobjs[TEXT_OBJ_LINE_DOWN], - [MOVE_SCREEN_LINE_UP] = &textobjs[TEXT_OBJ_LINE_UP], - [MOVE_SCREEN_LINE_DOWN] = &textobjs[TEXT_OBJ_LINE_DOWN], -}; - /** functions to be called from keybindings */ /* navigate jump list either in forward (arg->i>0) or backward (arg->i<0) direction */ static void jumplist(const Arg *arg); @@ -339,8 +327,8 @@ static void count(const Arg *arg); /* move to the action.count-th line or if not given either to the first (arg->i < 0) * or last (arg->i > 0) line of file */ static void gotoline(const Arg *arg); -/* force operator to linewise (if arg->b is set) */ -static void linewise(const Arg *arg); +/* set motion type either LINEWISE or CHARWISE via arg->i */ +static void motiontype(const Arg *arg); /* make the current action use the operator indicated by arg->i */ static void operator(const Arg *arg); /* execute operator twice useful for synonyms (e.g. 'cc') */ @@ -600,15 +588,13 @@ static size_t op_cursor(OperatorContext *c) { static size_t op_join(OperatorContext *c) { Text *txt = vis->win->file->text; size_t pos = text_line_begin(txt, c->range.end), prev_pos; - if (c->cursor) { - /* if selection is from visual linewiese mode, skip last line break */ - Filerange sel = view_cursors_selection_get(c->cursor); - if (text_range_equal(&sel, &c->range) && text_range_is_linewise(txt, &sel)) { - size_t line_prev = text_line_prev(txt, pos); - size_t line_prev_prev = text_line_prev(txt, line_prev); - if (line_prev_prev >= sel.start) - pos = line_prev; - } + + /* if operator and range are both linewise, skip last line break */ + if (c->linewise && text_range_is_linewise(txt, &c->range)) { + size_t line_prev = text_line_prev(txt, pos); + size_t line_prev_prev = text_line_prev(txt, line_prev); + if (line_prev_prev >= c->range.start) + pos = line_prev; } do { @@ -957,8 +943,8 @@ static void gotoline(const Arg *arg) { movement(&(const Arg){ .i = MOVE_FILE_END }); } -static void linewise(const Arg *arg) { - vis->action.linewise = arg->b; +static void motiontype(const Arg *arg) { + vis->action.type = arg->i; } static void operator(const Arg *arg) { @@ -974,8 +960,8 @@ static void operator(const Arg *arg) { if (vis->action.op == op) { /* hacky way to handle double operators i.e. things like * dd, yy etc where the second char isn't a movement */ - vis->action.linewise = true; - vis->action.textobj = moves_linewise[MOVE_SCREEN_LINE_DOWN]; + vis->action.type = LINEWISE; + vis->action.movement = &moves[MOVE_LINE_NEXT]; action_do(&vis->action); } else { vis->action.op = op; @@ -1005,10 +991,7 @@ static void movement_key(const Arg *arg) { } static void movement(const Arg *arg) { - if (vis->action.linewise && arg->i < LENGTH(moves_linewise)) - vis->action.textobj = moves_linewise[arg->i]; - else - vis->action.movement = &moves[arg->i]; + vis->action.movement = &moves[arg->i]; if (vis->action.op == &ops[OP_CHANGE]) { if (vis->action.movement == &moves[MOVE_WORD_START_NEXT]) @@ -1340,6 +1323,9 @@ static void action_do(Action *a) { View *view = vis->win->view; int count = MAX(1, a->count); bool multiple_cursors = view_cursors_count(view) > 1; + bool linewise = !(a->type & CHARWISE) && ( + a->type & LINEWISE || (a->movement && a->movement->type & LINEWISE) || + vis->mode == &vis_modes[VIS_MODE_VISUAL_LINE]); for (Cursor *cursor = view_cursors(view), *next; cursor; cursor = next) { @@ -1354,9 +1340,8 @@ static void action_do(Action *a) { .pos = pos, .range = text_range_empty(), .reg = reg, - .linewise = a->linewise, + .linewise = linewise, .arg = &a->arg, - .cursor = cursor, }; if (a->movement) { @@ -1379,8 +1364,7 @@ static void action_do(Action *a) { c.range.end = start; pos = start; } else { - c.range.start = MIN(start, pos); - c.range.end = MAX(start, pos); + c.range = text_range_new(start, pos); } if (!a->op) { @@ -1388,14 +1372,14 @@ static void action_do(Action *a) { view_cursors_scroll_to(cursor, pos); else view_cursors_to(cursor, pos); + if (vis->mode->visual) + c.range = view_cursors_selection_get(cursor); if (a->movement->type & JUMP) editor_window_jumplist_add(vis->win, pos); else editor_window_jumplist_invalidate(vis->win); } else if (a->movement->type & INCLUSIVE) { - Iterator it = text_iterator_get(txt, c.range.end); - text_iterator_char_next(&it, NULL); - c.range.end = it.pos; + c.range.end = text_char_next(txt, c.range.end); } } else if (a->textobj) { if (vis->mode->visual) @@ -1413,19 +1397,8 @@ static void action_do(Action *a) { c.range = text_range_union(&c.range, &r); - if (i < count - 1) { - if (a->textobj == &textobjs[TEXT_OBJ_LINE_UP]) { - pos = c.range.start - 1; - } else { - pos = c.range.end + 1; - } - } - } - - if (vis->mode->visual) { - view_cursors_selection_set(cursor, &c.range); - pos = c.range.end; - view_cursors_to(cursor, pos); + if (i < count - 1) + pos = c.range.end + 1; } } else if (vis->mode->visual) { c.range = view_cursors_selection_get(cursor); @@ -1433,10 +1406,12 @@ static void action_do(Action *a) { c.range.start = c.range.end = pos; } - if (vis->mode == &vis_modes[VIS_MODE_VISUAL_LINE] && (a->movement || a->textobj)) { - Filerange sel = view_cursors_selection_get(cursor); - c.range = text_range_linewise(txt, &sel); + if (linewise && vis->mode != &vis_modes[VIS_MODE_VISUAL]) + c.range = text_range_linewise(txt, &c.range); + if (vis->mode->visual) { view_cursors_selection_set(cursor, &c.range); + if (vis->mode == &vis_modes[VIS_MODE_VISUAL] || a->textobj) + view_cursors_selection_sync(cursor); } if (a->op) { @@ -1469,7 +1444,7 @@ static void action_do(Action *a) { static void action_reset(Action *a) { a->count = 0; - a->linewise = false; + a->type = 0; a->op = NULL; a->movement = NULL; a->textobj = NULL; |
