static const char *cursors_select_next(Vis *vis, const char *keys, const Arg *arg) { Text *txt = vis_text(vis); View *view = vis_view(vis); Cursor *cursor = view_cursor(view); Filerange sel = view_cursors_selection_get(cursor); if (!text_range_valid(&sel)) return keys; size_t len = text_range_size(&sel); char *buf = malloc(len+1); if (!buf) return keys; len = text_bytes_get(txt, sel.start, len, buf); buf[len] = '\0'; Filerange word = text_object_word_find_next(txt, sel.end, buf); free(buf); if (text_range_valid(&word)) { cursor = view_cursors_new(view); if (!cursor) return keys; view_cursors_selection_set(cursor, &word); view_cursors_to(cursor, text_char_prev(txt, word.end)); } return keys; }
static bool cmd_delete(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor *cur, Filerange *range) { if (!win) return false; bool ret = text_delete(win->file->text, range->start, text_range_size(range)); if (ret) *range = text_range_new(range->start, range->start); return ret; }
static bool cmd_guard(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor *cur, Filerange *range) { if (!win) return false; bool match = !text_search_range_forward(win->file->text, range->start, text_range_size(range), cmd->regex, 0, NULL, 0); if (match ^ (argv[0][0] == 'v')) return sam_execute(vis, win, cmd->cmd, cur, range); view_cursors_dispose(cur); return true; }
static size_t op_put(Vis *vis, Text *txt, OperatorContext *c) { size_t pos = c->pos; bool sel = text_range_size(&c->range) > 0; bool sel_linewise = sel && text_range_is_linewise(txt, &c->range); if (sel) { text_delete_range(txt, &c->range); pos = c->pos = c->range.start; } switch (c->arg->i) { case VIS_OP_PUT_AFTER: case VIS_OP_PUT_AFTER_END: if (c->reg->linewise && !sel_linewise) pos = text_line_next(txt, pos); else if (!sel) pos = text_char_next(txt, pos); break; case VIS_OP_PUT_BEFORE: case VIS_OP_PUT_BEFORE_END: if (c->reg->linewise) pos = text_line_begin(txt, pos); break; } size_t len; const char *data = register_get(vis, c->reg, &len); for (int i = 0; i < c->count; i++) { text_insert(txt, pos, data, len); pos += len; } if (c->reg->linewise) { switch (c->arg->i) { case VIS_OP_PUT_BEFORE_END: case VIS_OP_PUT_AFTER_END: pos = text_line_start(txt, pos); break; case VIS_OP_PUT_AFTER: pos = text_line_start(txt, text_line_next(txt, c->pos)); break; case VIS_OP_PUT_BEFORE: pos = text_line_start(txt, c->pos); break; } } else { switch (c->arg->i) { case VIS_OP_PUT_AFTER: case VIS_OP_PUT_BEFORE: pos = text_char_prev(txt, pos); break; } } return pos; }
static const char *prompt_enter(Vis *vis, const char *keys, const Arg *arg) { Win *prompt = vis->win; View *view = prompt->view; Text *txt = prompt->file->text; Win *win = prompt->parent; char *cmd = NULL; Filerange range = view_selection_get(view); if (!text_range_valid(&range)) range = text_object_line(txt, view_cursor_get(view)); if (text_range_valid(&range)) cmd = text_bytes_alloc0(txt, range.start, text_range_size(&range)); if (!win || !cmd) { vis_info_show(vis, "Prompt window invalid\n"); prompt_restore(prompt); prompt_hide(prompt); free(cmd); return keys; } size_t len = strlen(cmd); if (len > 0 && cmd[len-1] == '\n') cmd[len-1] = '\0'; bool lastline = (range.end == text_size(txt)); prompt_restore(prompt); if (vis_prompt_cmd(vis, cmd)) { prompt_hide(prompt); if (!lastline) { text_delete(txt, range.start, text_range_size(&range)); text_appendf(txt, "%s\n", cmd); } } else { vis->win = prompt; vis->mode = &vis_modes[VIS_MODE_INSERT]; } free(cmd); vis_draw(vis); return keys; }
static bool cmd_change(Vis *vis, Win *win, Command *cmd, const char *argv[], Cursor *cur, Filerange *range) { if (!win) return false; Text *txt = win->file->text; size_t len = strlen(argv[1]); bool ret = text_delete(txt, range->start, text_range_size(range)) && text_insert(txt, range->start, argv[1], len); if (ret) *range = text_range_new(range->start, range->start + len); return ret; }
Filerange text_object_word_find_prev(Text *txt, size_t pos, const char *word) { size_t len = strlen(word); for (;;) { size_t match_pos = text_find_prev(txt, pos, word); if (match_pos != pos) { Filerange match_word = text_object_word(txt, match_pos); if (text_range_size(&match_word) == len) return match_word; pos = match_pos; } else { return text_range_empty(); } } }
static void prompt_hide(Win *win) { Text *txt = win->file->text; size_t size = text_size(txt); /* make sure that file is new line terminated */ char lastchar; if (size > 1 && text_byte_get(txt, size-1, &lastchar) && lastchar != '\n') text_insert(txt, size, "\n", 1); /* remove empty entries */ Filerange line = text_object_line(txt, size); size_t line_size = text_range_size(&line); if (line_size <= 2) text_delete(txt, line.start, line_size); vis_window_close(win); }
Filerange text_object_number(Text *txt, size_t pos) { char *buf, *err = NULL; Filerange r = text_object_range(txt, pos, is_number); if (!text_range_valid(&r)) return r; if (!(buf = text_bytes_alloc0(txt, r.start, text_range_size(&r)))) return text_range_empty(); errno = 0; strtoll(buf, &err, 0); if (errno || err == buf) r = text_range_empty(); else r.end = r.start + (err - buf); free(buf); return r; }
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 == VIS_OP_CASE_SWAP) *cur = islower(ch) ? toupper(ch) : tolower(ch); else if (c->arg->i == VIS_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; }