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; size_t deleted = 0; /* 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); deleted += tablen; } while (pos >= c->range.start && pos != prev_pos); return c->pos - deleted; }
static size_t op_join(Vis *vis, Text *txt, OperatorContext *c) { size_t pos = text_line_begin(txt, c->range.end), prev_pos; Mark mark = NULL; /* 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); if (!mark) mark = text_mark_set(txt, pos); } else { break; } } while (pos != prev_pos); size_t newpos = text_mark_get(txt, mark); return newpos != EPOS ? newpos : c->range.start; }
static size_t op_join(Vis *vis, Text *txt, OperatorContext *c) { size_t pos = text_line_begin(txt, c->range.end), prev_pos; Mark mark = NULL; /* 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; } 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_line_prev(txt, end); if (pos < c->range.start || end <= pos) break; text_delete(txt, pos, end - pos); char prev, next; if (text_byte_get(txt, pos-1, &prev) && !isspace((unsigned char)prev) && text_byte_get(txt, pos, &next) && next != '\r' && next != '\n') text_insert(txt, pos, c->arg->s, len); if (!mark) mark = text_mark_set(txt, pos); } while (pos != prev_pos); size_t newpos = text_mark_get(txt, mark); return newpos != EPOS ? newpos : c->range.start; }
static size_t op_delete(Vis *vis, Text *txt, OperatorContext *c) { c->reg->linewise = c->linewise; register_put_range(vis, 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; }
Filerange text_object_indentation(Text *txt, size_t pos) { char c; size_t bol = text_line_begin(txt, pos); size_t sol = text_line_start(txt, bol); size_t start = bol; size_t end = text_line_next(txt, bol); size_t line_indent = sol - bol; bool line_empty = text_byte_get(txt, bol, &c) && (c == '\r' || c == '\n'); char *buf = text_bytes_alloc0(txt, bol, line_indent); char *tmp = malloc(line_indent); if (!buf || !tmp) { free(buf); free(tmp); return text_range_empty(); } while ((bol = text_line_begin(txt, text_line_prev(txt, start))) != start) { sol = text_line_start(txt, bol); size_t indent = sol - bol; if (indent < line_indent) break; bool empty = text_byte_get(txt, bol, &c) && (c == '\r' || c == '\n'); if (line_empty && !empty) break; if (line_indent == 0 && empty) break; text_bytes_get(txt, bol, line_indent, tmp); if (memcmp(buf, tmp, line_indent)) break; start = bol; } do { bol = end; sol = text_line_start(txt, bol); size_t indent = sol - bol; if (indent < line_indent) break; bool empty = text_byte_get(txt, bol, &c) && (c == '\r' || c == '\n'); if (line_empty && !empty) break; if (line_indent == 0 && empty) break; text_bytes_get(txt, bol, line_indent, tmp); if (memcmp(buf, tmp, line_indent)) break; end = text_line_next(txt, bol); } while (bol != end); free(buf); free(tmp); return text_range_new(start, end); }
size_t text_range_line_last(Text *txt, Filerange *r) { if (!text_range_valid(r)) return EPOS; size_t pos = text_line_begin(txt, r->end); if (pos == r->end) { /* range ends at a begin of a line, skip last line ending */ pos = text_line_prev(txt, pos); pos = text_line_begin(txt, pos); } return r->start <= pos ? pos : r->start; }
static size_t op_shift_right(Vis *vis, Text *txt, OperatorContext *c) { char spaces[9] = " "; spaces[MIN(vis->tabwidth, LENGTH(spaces) - 1)] = '\0'; const char *tab = vis->expandtab ? spaces : "\t"; size_t tablen = strlen(tab); size_t pos = text_line_begin(txt, c->range.end), prev_pos; size_t inserted = 0; /* 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); inserted += tablen; } while (pos >= c->range.start && pos != prev_pos); return c->pos + inserted; }
size_t text_range_line_prev(Text *txt, Filerange *r, size_t pos) { if (!text_range_contains(r, pos)) return EPOS; size_t newpos = text_line_begin(txt, text_line_prev(txt, pos)); return newpos != pos && r->start <= newpos ? newpos : EPOS; }
size_t text_line_up(Text *txt, size_t pos) { int width = text_line_width_get(txt, pos); size_t prev = text_line_prev(txt, pos); return text_line_width_set(txt, prev, width); }