diff options
| author | Marc André Tanner <mat@brain-dump.org> | 2015-11-07 08:30:10 +0100 |
|---|---|---|
| committer | Marc André Tanner <mat@brain-dump.org> | 2015-11-07 08:30:10 +0100 |
| commit | ef6ed089536d281fb0b3a274109f39ceb0586e02 (patch) | |
| tree | b252490cde495e2f7e7823df0535a7201b9e7b05 /vis-operators.c | |
| parent | d34ed26989a4775c3b5fd97355d72ef4a6552c71 (diff) | |
| download | vis-ef6ed089536d281fb0b3a274109f39ceb0586e02.tar.gz vis-ef6ed089536d281fb0b3a274109f39ceb0586e02.tar.xz | |
vis: move operators to separate file
Diffstat (limited to 'vis-operators.c')
| -rw-r--r-- | vis-operators.c | 226 |
1 files changed, 226 insertions, 0 deletions
diff --git a/vis-operators.c b/vis-operators.c new file mode 100644 index 0000000..b7201cb --- /dev/null +++ b/vis-operators.c @@ -0,0 +1,226 @@ +#include <string.h> +#include <ctype.h> +#include "vis-core.h" +#include "text-motions.h" +#include "text-objects.h" +#include "text-util.h" +#include "util.h" + +/** operators */ +static size_t op_change(Vis*, Text*, OperatorContext *c); +static size_t op_yank(Vis*, Text*, OperatorContext *c); +static size_t op_put(Vis*, Text*, OperatorContext *c); +static size_t op_delete(Vis*, Text*, OperatorContext *c); +static size_t op_shift_right(Vis*, Text*, OperatorContext *c); +static size_t op_shift_left(Vis*, Text*, OperatorContext *c); +static size_t op_case_change(Vis*, Text*, OperatorContext *c); +static size_t op_join(Vis*, Text*, OperatorContext *c); +static size_t op_insert(Vis*, Text*, OperatorContext *c); +static size_t op_replace(Vis*, Text*, OperatorContext *c); +static size_t op_cursor(Vis*, Text*, OperatorContext *c); + +Operator ops[] = { + [OP_DELETE] = { op_delete }, + [OP_CHANGE] = { op_change }, + [OP_YANK] = { op_yank }, + [OP_PUT_AFTER] = { op_put }, + [OP_SHIFT_RIGHT] = { op_shift_right }, + [OP_SHIFT_LEFT] = { op_shift_left }, + [OP_CASE_SWAP] = { op_case_change }, + [OP_JOIN] = { op_join }, + [OP_INSERT] = { op_insert }, + [OP_REPLACE] = { op_replace }, + [OP_CURSOR_SOL] = { op_cursor }, +}; + +static size_t op_delete(Vis *vis, Text *txt, OperatorContext *c) { + c->reg->linewise = c->linewise; + register_put(c->reg, txt, &c->range); + text_delete_range(txt, &c->range); + size_t pos = c->range.start; + if (c->linewise && pos == text_size(txt)) + pos = text_line_begin(txt, text_line_prev(txt, pos)); + return pos; +} + +static size_t op_change(Vis *vis, Text *txt, OperatorContext *c) { + op_delete(vis, txt, c); + macro_operator_record(vis); + return c->range.start; +} + +static size_t op_yank(Vis *vis, Text *txt, OperatorContext *c) { + c->reg->linewise = c->linewise; + register_put(c->reg, txt, &c->range); + return c->pos; +} + +static size_t op_put(Vis *vis, Text *txt, OperatorContext *c) { + size_t pos = c->pos; + switch (c->arg->i) { + case OP_PUT_AFTER: + case OP_PUT_AFTER_END: + if (c->reg->linewise) + pos = text_line_next(txt, pos); + else + pos = text_char_next(txt, pos); + break; + case OP_PUT_BEFORE: + case OP_PUT_BEFORE_END: + if (c->reg->linewise) + pos = text_line_begin(txt, pos); + break; + } + + for (int i = 0; i < c->count; i++) { + text_insert(txt, pos, c->reg->data, c->reg->len); + pos += c->reg->len; + } + + if (c->reg->linewise) { + switch (c->arg->i) { + case OP_PUT_BEFORE_END: + case OP_PUT_AFTER_END: + pos = text_line_start(txt, pos); + break; + case OP_PUT_AFTER: + pos = text_line_start(txt, text_line_next(txt, c->pos)); + break; + case OP_PUT_BEFORE: + pos = text_line_start(txt, c->pos); + break; + } + } else { + switch (c->arg->i) { + case OP_PUT_AFTER: + case OP_PUT_BEFORE: + pos = text_char_prev(txt, pos); + break; + } + } + + return pos; +} + +static size_t op_shift_right(Vis *vis, Text *txt, OperatorContext *c) { + size_t pos = text_line_begin(txt, c->range.end), prev_pos; + const char *tab = expandtab(vis); + size_t tablen = strlen(tab); + + /* if range ends at the begin of a line, skip line break */ + if (pos == c->range.end) + pos = text_line_prev(txt, pos); + + do { + prev_pos = pos = text_line_begin(txt, pos); + text_insert(txt, pos, tab, tablen); + pos = text_line_prev(txt, pos); + } while (pos >= c->range.start && pos != prev_pos); + + return c->pos + tablen; +} + +static size_t op_shift_left(Vis *vis, Text *txt, OperatorContext *c) { + size_t pos = text_line_begin(txt, c->range.end), prev_pos; + size_t tabwidth = vis->tabwidth, tablen; + + /* if range ends at the begin of a line, skip line break */ + if (pos == c->range.end) + pos = text_line_prev(txt, pos); + + do { + char c; + size_t len = 0; + prev_pos = pos = text_line_begin(txt, pos); + Iterator it = text_iterator_get(txt, pos); + if (text_iterator_byte_get(&it, &c) && c == '\t') { + len = 1; + } else { + for (len = 0; text_iterator_byte_get(&it, &c) && c == ' '; len++) + text_iterator_byte_next(&it, NULL); + } + tablen = MIN(len, tabwidth); + text_delete(txt, pos, tablen); + pos = text_line_prev(txt, pos); + } while (pos >= c->range.start && pos != prev_pos); + + return c->pos - tablen; +} + +static size_t op_case_change(Vis *vis, Text *txt, OperatorContext *c) { + size_t len = text_range_size(&c->range); + char *buf = malloc(len); + if (!buf) + return c->pos; + len = text_bytes_get(txt, c->range.start, len, buf); + size_t rem = len; + for (char *cur = buf; rem > 0; cur++, rem--) { + int ch = (unsigned char)*cur; + if (isascii(ch)) { + if (c->arg->i == OP_CASE_SWAP) + *cur = islower(ch) ? toupper(ch) : tolower(ch); + else if (c->arg->i == OP_CASE_UPPER) + *cur = toupper(ch); + else + *cur = tolower(ch); + } + } + + text_delete(txt, c->range.start, len); + text_insert(txt, c->range.start, buf, len); + free(buf); + return c->pos; +} + +static size_t op_cursor(Vis *vis, Text *txt, OperatorContext *c) { + View *view = vis->win->view; + Filerange r = text_range_linewise(txt, &c->range); + for (size_t line = text_range_line_first(txt, &r); line != EPOS; line = text_range_line_next(txt, &r, line)) { + Cursor *cursor = view_cursors_new(view); + if (cursor) { + size_t pos; + if (c->arg->i == OP_CURSOR_EOL) + pos = text_line_finish(txt, line); + else + pos = text_line_start(txt, line); + view_cursors_to(cursor, pos); + } + } + return EPOS; +} + +static size_t op_join(Vis *vis, Text *txt, OperatorContext *c) { + size_t pos = text_line_begin(txt, c->range.end), prev_pos; + + /* 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 { + 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); + } else { + break; + } + } while (pos != prev_pos); + + return c->range.start; +} + +static size_t op_insert(Vis *vis, Text *txt, OperatorContext *c) { + macro_operator_record(vis); + return c->newpos != EPOS ? c->newpos : c->pos; +} + +static size_t op_replace(Vis *vis, Text *txt, OperatorContext *c) { + macro_operator_record(vis); + return c->newpos != EPOS ? c->newpos : c->pos; +} |
