vis

a vi-like editor based on Plan 9's structural regular expressions

git clone https://9o.is/git/vis.git

commit b9c8f08c91d21c3f252afac9f8d761e938350d77
parent 8e88b90747fd03217138615737f688888114b9ef
Author: Marc André Tanner <mat@brain-dump.org>
Date:   Wed, 24 Aug 2016 11:03:34 +0200

vis: implement gJ like behavior

The behavior is not exactly the same because vim preserves any
existing white spaces wihle we remove existing ones but do
not insert additional ones.

The vim behavior (essentially only deleating new lines) can be
achived using something like:

 :x/\n/d

Close #374

Diffstat:
Mconfig.def.h | 4+++-
Mmain.c | 27+++++++++++++++------------
Mvis-operators.c | 7++++++-
Mvis.h | 1+
4 files changed, 25 insertions(+), 14 deletions(-)

diff --git a/config.def.h b/config.def.h @@ -234,7 +234,8 @@ static const KeyBinding bindings_normal[] = { { "gv", ACTION(SELECTION_RESTORE) }, { "I", ACTION(INSERT_LINE_START) }, { "i", ACTION(MODE_INSERT) }, - { "J", ACTION(JOIN_LINE_BELOW) }, + { "J", ACTION(JOIN_LINES) }, + { "gJ", ACTION(JOIN_LINES_TRIM) }, { "m", ACTION(MARK_SET) }, { "<M-C-j>", ACTION(CURSORS_NEW_LINE_BELOW_LAST) }, { "<M-C-k>", ACTION(CURSORS_NEW_LINE_ABOVE_FIRST) }, @@ -285,6 +286,7 @@ static const KeyBinding bindings_visual[] = { { "<Escape>", ACTION(MODE_NORMAL) }, { "I", ACTION(CURSORS_NEW_LINES_BEGIN) }, { "J", ACTION(JOIN_LINES) }, + { "gJ", ACTION(JOIN_LINES_TRIM) }, { "o", ACTION(SELECTION_FLIP) }, { "r", ALIAS("c") }, { "s", ALIAS("c") }, diff --git a/main.c b/main.c @@ -239,8 +239,8 @@ enum { VIS_ACTION_INSERT_LINE_START, VIS_ACTION_OPEN_LINE_ABOVE, VIS_ACTION_OPEN_LINE_BELOW, - VIS_ACTION_JOIN_LINE_BELOW, VIS_ACTION_JOIN_LINES, + VIS_ACTION_JOIN_LINES_TRIM, VIS_ACTION_PROMPT_SHOW, VIS_ACTION_REPEAT, VIS_ACTION_SELECTION_FLIP, @@ -857,15 +857,15 @@ static const KeyAction vis_action[] = { "Begin a new line below the cursor", openline, { .i = +1 } }, - [VIS_ACTION_JOIN_LINE_BELOW] = { - "join-line-below", - "Join line(s)", - join, { .i = VIS_MOVE_LINE_NEXT }, - }, [VIS_ACTION_JOIN_LINES] = { "join-lines", "Join selected lines", - operator, { .i = VIS_OP_JOIN } + join, { .s = " " } + }, + [VIS_ACTION_JOIN_LINES_TRIM] = { + "join-lines-trim", + "Join selected lines, remove white space", + join, { .s = "" } }, [VIS_ACTION_PROMPT_SHOW] = { "prompt-show", @@ -1973,11 +1973,14 @@ static const char *openline(Vis *vis, const char *keys, const Arg *arg) { } static const char *join(Vis *vis, const char *keys, const Arg *arg) { - int count = vis_count_get_default(vis, 0); - if (count) - vis_count_set(vis, count-1); - vis_operator(vis, VIS_OP_JOIN); - vis_motion(vis, arg->i); + bool normal = (vis_mode_get(vis) == VIS_MODE_NORMAL); + vis_operator(vis, VIS_OP_JOIN, arg->s); + if (normal) { + int count = vis_count_get_default(vis, 0); + if (count) + vis_count_set(vis, count-1); + vis_motion(vis, VIS_MOVE_LINE_NEXT); + } return keys; } diff --git a/vis-operators.c b/vis-operators.c @@ -193,13 +193,15 @@ static size_t op_join(Vis *vis, Text *txt, OperatorContext *c) { pos = line_prev; } + size_t len = c->arg->s ? strlen(c->arg->s) : 0; + do { prev_pos = pos; size_t end = text_line_start(txt, pos); pos = text_char_next(txt, text_line_finish(txt, text_line_prev(txt, end))); if (pos >= c->range.start && end > pos) { text_delete(txt, pos, end - pos); - text_insert(txt, pos, " ", 1); + text_insert(txt, pos, c->arg->s, len); if (!mark) mark = text_mark_set(txt, pos); } else { @@ -246,6 +248,9 @@ bool vis_operator(Vis *vis, enum VisOperator id, ...) { vis->action.arg.i = id; id = VIS_OP_PUT_AFTER; break; + case VIS_OP_JOIN: + vis->action.arg.s = va_arg(ap, char*); + break; case VIS_OP_FILTER: vis->action.arg.s = va_arg(ap, char*); /* fall through */ diff --git a/vis.h b/vis.h @@ -202,6 +202,7 @@ enum VisOperator { * the expected varying arguments are as follows: * * - VIS_OP_FILTER a char pointer referring to the command to run + * - VIS_OP_JOIN a char pointer referring to the text to insert between lines */ bool vis_operator(Vis*, enum VisOperator, ...);