aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README4
-rw-r--r--config.def.h43
-rw-r--r--vis.c22
-rw-r--r--window.c9
-rw-r--r--window.h2
5 files changed, 63 insertions, 17 deletions
diff --git a/README b/README
index 6926c1e..73ffdf7 100644
--- a/README
+++ b/README
@@ -382,9 +382,7 @@ and their current support in vis.
-----
At the moment there exists a more or less functional insert, replace
- and character wise visual mode.
-
- A line wise visual mode is planned.
+ and visual mode (in both line and character wise variants).
Marks
-----
diff --git a/config.def.h b/config.def.h
index 46ff32b..6003918 100644
--- a/config.def.h
+++ b/config.def.h
@@ -37,6 +37,7 @@ enum {
VIS_MODE_REGISTER,
VIS_MODE_NORMAL,
VIS_MODE_VISUAL,
+ VIS_MODE_VISUAL_LINE,
VIS_MODE_READLINE,
VIS_MODE_PROMPT,
VIS_MODE_INSERT_REGISTER,
@@ -372,6 +373,7 @@ static KeyBinding vis_mode_normal[] = {
{ { NONE('r') }, replace, { NULL } },
{ { NONE('i') }, switchmode, { .i = VIS_MODE_INSERT } },
{ { NONE('v') }, switchmode, { .i = VIS_MODE_VISUAL } },
+ { { NONE('V') }, switchmode, { .i = VIS_MODE_VISUAL_LINE } },
{ { NONE('R') }, switchmode, { .i = VIS_MODE_REPLACE } },
{ { NONE('S') }, operator_twice, { .i = OP_CHANGE } },
{ { NONE('s') }, change, { .i = MOVE_CHAR_NEXT } },
@@ -388,6 +390,7 @@ static KeyBinding vis_mode_visual[] = {
{ { NONE(ESC) }, switchmode, { .i = VIS_MODE_NORMAL } },
{ { CONTROL('c') }, switchmode, { .i = VIS_MODE_NORMAL } },
{ { NONE('v') }, switchmode, { .i = VIS_MODE_NORMAL } },
+ { { NONE('V') }, switchmode, { .i = VIS_MODE_VISUAL_LINE } },
BACKSPACE( operator, i, OP_DELETE ),
{ { CONTROL('H') }, operator, { .i = OP_DELETE } },
{ { NONE('d') }, operator, { .i = OP_DELETE } },
@@ -400,11 +403,32 @@ static KeyBinding vis_mode_visual[] = {
};
static void vis_mode_visual_enter(Mode *old) {
- window_selection_start(vis->win->win);
+ if (old != &vis_modes[VIS_MODE_VISUAL_LINE])
+ window_selection_start(vis->win->win);
}
static void vis_mode_visual_leave(Mode *new) {
- window_selection_clear(vis->win->win);
+ if (new != &vis_modes[VIS_MODE_VISUAL_LINE])
+ window_selection_clear(vis->win->win);
+}
+
+static KeyBinding vis_mode_visual_line[] = {
+ { { NONE('v') }, switchmode, { .i = VIS_MODE_VISUAL } },
+ { { NONE('V') }, switchmode, { .i = VIS_MODE_NORMAL } },
+ { /* empty last element, array terminator */ },
+};
+
+static void vis_mode_visual_line_enter(Mode *old) {
+ Win *win = vis->win->win;
+ window_cursor_to(win, text_line_begin(vis->win->text, window_cursor_get(win)));
+ if (old != &vis_modes[VIS_MODE_VISUAL])
+ window_selection_start(vis->win->win);
+ movement(&(const Arg){ .i = MOVE_LINE_END });
+}
+
+static void vis_mode_visual_line_leave(Mode *new) {
+ if (new != &vis_modes[VIS_MODE_VISUAL])
+ window_selection_clear(vis->win->win);
}
static KeyBinding vis_mode_readline[] = {
@@ -543,10 +567,10 @@ static void vis_mode_replace_input(const char *str, size_t len) {
* /-----------/ | \\ |
* / | \\ |
* VISUAL MARK-SET \\ OPERATOR-OPTION
- * (m [a-z]) \\ (v,V)
- * | \\ //
- * | \\======//
- * NORMAL
+ * | (m [a-z]) \\ (v,V)
+ * | | \\ //
+ * | | \\======//
+ * VISUAL-LINE NORMAL
*/
static Mode vis_modes[] = {
@@ -621,6 +645,13 @@ static Mode vis_modes[] = {
.enter = vis_mode_visual_enter,
.leave = vis_mode_visual_leave,
},
+ [VIS_MODE_VISUAL_LINE] = {
+ .name = "--VISUAL LINE--",
+ .parent = &vis_modes[VIS_MODE_VISUAL],
+ .bindings = vis_mode_visual_line,
+ .enter = vis_mode_visual_line_enter,
+ .leave = vis_mode_visual_line_leave,
+ },
[VIS_MODE_READLINE] = {
.name = "READLINE",
.parent = &vis_modes[VIS_MODE_BASIC],
diff --git a/vis.c b/vis.c
index 881ec81..35eb4fb 100644
--- a/vis.c
+++ b/vis.c
@@ -626,7 +626,7 @@ static void linewise(const Arg *arg) {
static void operator(const Arg *arg) {
Operator *op = &ops[arg->i];
- if (mode == &vis_modes[VIS_MODE_VISUAL]) {
+ if (mode == &vis_modes[VIS_MODE_VISUAL] || mode == &vis_modes[VIS_MODE_VISUAL_LINE]) {
action.op = op;
action_do(&action);
return;
@@ -918,6 +918,22 @@ static void action_do(Action *a) {
window_scroll_to(win, pos);
else
window_cursor_to(win, pos);
+
+ if (mode == &vis_modes[VIS_MODE_VISUAL_LINE]) {
+ Filerange sel = window_selection_get(win);
+ sel.end = text_char_prev(txt, sel.end);
+ size_t start = text_line_begin(txt, sel.start);
+ size_t end = text_line_end(txt, sel.end);
+ if (sel.start == pos) { /* extend selection upwards */
+ sel.end = start;
+ sel.start = end;
+ } else { /* extend selection downwards */
+ sel.start = start;
+ sel.end = end;
+ }
+ window_selection_set(win, &sel);
+ c.range = sel;
+ }
} else if (a->movement->type & INCLUSIVE) {
Iterator it = text_iterator_get(txt, c.range.end);
text_iterator_char_next(&it, NULL);
@@ -945,7 +961,7 @@ static void action_do(Action *a) {
}
}
}
- } else if (mode == &vis_modes[VIS_MODE_VISUAL]) {
+ } else if (mode == &vis_modes[VIS_MODE_VISUAL] || mode == &vis_modes[VIS_MODE_VISUAL_LINE]) {
c.range = window_selection_get(win);
if (!text_range_valid(&c.range))
c.range.start = c.range.end = pos;
@@ -955,7 +971,7 @@ static void action_do(Action *a) {
a->op->func(&c);
if (mode == &vis_modes[VIS_MODE_OPERATOR])
switchmode_to(mode_prev);
- else if (mode == &vis_modes[VIS_MODE_VISUAL])
+ else if (mode == &vis_modes[VIS_MODE_VISUAL] || mode == &vis_modes[VIS_MODE_VISUAL_LINE])
switchmode(&(const Arg){ .i = VIS_MODE_NORMAL });
text_snapshot(txt);
}
diff --git a/window.c b/window.c
index 8a2ad12..716d9e5 100644
--- a/window.c
+++ b/window.c
@@ -137,6 +137,11 @@ Filerange window_selection_get(Win *win) {
return sel;
}
+void window_selection_set(Win *win, Filerange *sel) {
+ win->sel = *sel;
+ window_draw(win);
+}
+
Filerange window_viewport_get(Win *win) {
return (Filerange){ .start = win->start, .end = win->end };
}
@@ -782,10 +787,6 @@ void window_selection_start(Win *win) {
curs_set(0);
}
-void window_selection_end(Win *win) {
- win->sel.end = window_cursor_get(win);
-}
-
void window_syntax_set(Win *win, Syntax *syntax) {
win->syntax = syntax;
}
diff --git a/window.h b/window.h
index ec52f48..816efcd 100644
--- a/window.h
+++ b/window.h
@@ -58,10 +58,10 @@ void window_cursor_to(Win*, size_t pos);
/* start selected area at current cursor position. further cursor movements will
* affect the selected region. */
void window_selection_start(Win*);
-void window_selection_end(Win*);
/* returns the currently selected text region, is either empty or well defined,
* i.e. sel.start <= sel.end */
Filerange window_selection_get(Win*);
+void window_selection_set(Win*, Filerange *sel);
/* clear selection and redraw window */
void window_selection_clear(Win*);
/* get the currently displayed area in bytes from the start of the file */