forked from martanne/vis
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
vis: move operators to separate file
- Loading branch information
Showing
4 changed files
with
247 additions
and
238 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -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; | ||
} |
Oops, something went wrong.