aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarc André Tanner <mat@brain-dump.org>2015-07-31 13:34:27 +0200
committerMarc André Tanner <mat@brain-dump.org>2015-07-31 15:39:12 +0200
commitf38cdb2d38357f8f01a766ea21cb30661a0d99e8 (patch)
treefef5d07b8c47ad3a7c7f9d18e957226cafc53833
parent45994302f232fc4b13fde1b85f512f9238d36613 (diff)
downloadvis-f38cdb2d38357f8f01a766ea21cb30661a0d99e8.tar.gz
vis-f38cdb2d38357f8f01a766ea21cb30661a0d99e8.tar.xz
vis: cleanup handling of charwise/linewise motions
Also text objects in visual mode should now work better.
-rw-r--r--config.def.h4
-rw-r--r--editor.h3
-rw-r--r--view.c20
-rw-r--r--view.h2
-rw-r--r--vis.c135
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 */ },
};
diff --git a/editor.h b/editor.h
index 9c462b3..2d0819b 100644
--- a/editor.h
+++ b/editor.h
@@ -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;
diff --git a/view.c b/view.c
index ff3ab42..6d62dde 100644
--- a/view.c
+++ b/view.c
@@ -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) {
diff --git a/view.h b/view.h
index d0e7070..dd28ed9 100644
--- a/view.h
+++ b/view.h
@@ -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*);
diff --git a/vis.c b/vis.c
index f630e7f..815588e 100644
--- a/vis.c
+++ b/vis.c
@@ -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;