Skip to content

Commit

Permalink
add cmd_replace_all
Browse files Browse the repository at this point in the history
  • Loading branch information
adsr committed Sep 11, 2024
1 parent 3e82f1c commit 8f32163
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 7 deletions.
60 changes: 60 additions & 0 deletions cmd.c
Original file line number Diff line number Diff line change
Expand Up @@ -506,6 +506,66 @@ int cmd_replace(cmd_context_t *ctx) {
return cursor_replace(ctx->cursor, 1, NULL, NULL);
}

// Interactive search and replace on all buffers
int cmd_replace_all(cmd_context_t *ctx) {
bview_t *bview, *bview_orig;
int num_bviews, do_replace_all, num_replacements, num_replacements_tmp;
int cancelled, buffer_done_i, i, already_done;
char *regex, *replacement;
buffer_t **buffer_done;

bview_orig = ctx->bview;
do_replace_all = 0;
num_replacements = 0;
cancelled = 0;
regex = NULL;
replacement = NULL;
num_bviews = 0;
CDL_COUNT2(ctx->editor->all_bviews, bview, num_bviews, all_next);
buffer_done = calloc(num_bviews, sizeof(buffer_t *));
buffer_done_i = 0;

do {
editor_prompt(ctx->editor, "replace_all: Search regex?", NULL, &regex);
if (!regex) break;
editor_prompt(ctx->editor, "replace_all: Replacement string?", NULL, &replacement);
if (!replacement) break;

CDL_FOREACH2(ctx->editor->all_bviews, bview, all_next) {
if (!MLE_BVIEW_IS_EDIT(bview)) continue;

// Check if buffer in done list
// TODO inefficient, could replace with hash
for (i = 0, already_done = 0; i < buffer_done_i; i++) {
if (buffer_done[i] == bview->buffer) {
already_done = 1;
break;
}
}
if (already_done) continue;

// Search and replace on this bview
editor_set_active(ctx->editor, bview);
cursor_replace_ex(bview->active_cursor, 1, regex, replacement, "replace_all", &do_replace_all, &num_replacements_tmp, &cancelled);
num_replacements += num_replacements_tmp;

// Add buffer to done list
buffer_done[buffer_done_i++] = bview->buffer;
if (cancelled) break;
}
} while (0);

editor_set_active(ctx->editor, bview_orig);

MLE_SET_INFO(ctx->editor, "replace_all: Replaced %d instance(s) in %d buffer(s)", num_replacements, buffer_done_i);

if (regex) free(regex);
if (replacement) free(replacement);
if (buffer_done) free(buffer_done);

return MLE_OK;
}

// Repeat last cmd
int cmd_repeat(cmd_context_t *ctx) {
// This is a special case in _editor_loop
Expand Down
31 changes: 24 additions & 7 deletions cursor.c
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,11 @@ int cursor_uncut_last(cursor_t *cursor) {

// Regex search and replace
int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt_replacement) {
return cursor_replace_ex(cursor, interactive, opt_regex, opt_replacement, NULL, NULL, NULL, NULL);
}

// Regex search and replace (extended params)
int cursor_replace_ex(cursor_t *cursor, int interactive, char *opt_regex, char *opt_replacement, char *opt_cmd_name, int *inout_all, int *optret_num_replacements, int *optret_cancelled) {
char *regex;
char *replacement;
int wrapped;
Expand All @@ -295,9 +300,12 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
PCRE2_SIZE pcre_ovector[30];
str_t repl_backref = {0};
int num_replacements;
char *cmd_name;

if (!interactive && (!opt_regex || !opt_replacement)) {
return MLE_ERR;
} else if ((opt_regex && !opt_replacement) || (!opt_regex && opt_replacement)) {
return MLE_ERR;
}

regex = NULL;
Expand All @@ -309,19 +317,20 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
search_mark = NULL;
search_mark_end = NULL;
anchored_before = 0;
all = interactive ? 0 : 1;
all = interactive ? (inout_all ? *inout_all : 0) : 1;
num_replacements = 0;
mark_set_pcre_capture(&pcre_rc, pcre_ovector, 30);
orig_viewport_y = -1;
cmd_name = opt_cmd_name ? opt_cmd_name : "replace";

do {
if (!interactive) {
if (!interactive || (opt_regex && opt_replacement)) {
regex = strdup(opt_regex);
replacement = strdup(opt_replacement);
} else {
editor_prompt(cursor->bview->editor, "replace: Search regex?", NULL, &regex);
editor_prompt_fmt(cursor->bview->editor, NULL, &regex, "%s: Search regex?", cmd_name);
if (!regex) break;
editor_prompt(cursor->bview->editor, "replace: Replacement string?", NULL, &replacement);
editor_prompt_fmt(cursor->bview->editor, NULL, &replacement, "%s: Replacement string?", cmd_name);
if (!replacement) break;
}
orig_mark = buffer_add_mark(cursor->bview->buffer, NULL, 0);
Expand Down Expand Up @@ -360,14 +369,16 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
buffer_add_srule(cursor->bview->buffer, highlight);
bview_rectify_viewport(cursor->bview);
bview_draw(cursor->bview);
editor_prompt(cursor->bview->editor, "replace: OK to replace? (y=yes, n=no, a=all, C-c=stop)",
&(editor_prompt_params_t) { .kmap = cursor->bview->editor->kmap_prompt_yna }, &yn
editor_prompt_fmt(cursor->bview->editor,
&(editor_prompt_params_t) { .kmap = cursor->bview->editor->kmap_prompt_yna }, &yn,
"%s: OK to replace? (y=yes, n=no, a=all, C-c=stop)", cmd_name
);
buffer_remove_srule(cursor->bview->buffer, highlight);
srule_destroy(highlight);
bview_draw(cursor->bview);
}
if (!yn) {
if (optret_cancelled) *optret_cancelled = 1;
break;
} else if (0 == strcmp(yn, MLE_PROMPT_YES) || 0 == strcmp(yn, MLE_PROMPT_ALL)) {
str_append_replace_with_backrefs(&repl_backref, search_mark->bline->data, replacement, pcre_rc, pcre_ovector, 30);
Expand Down Expand Up @@ -404,7 +415,11 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
if (search_mark_end) mark_destroy(search_mark_end);

if (interactive) {
MLE_SET_INFO(cursor->bview->editor, "replace: Replaced %d instance(s)", num_replacements);
if (optret_num_replacements) {
*optret_num_replacements = num_replacements;
} else {
MLE_SET_INFO(cursor->bview->editor, "%s: Replaced %d instance(s)", cmd_name, num_replacements);
}
if (orig_viewport_y >= 0) {
bview_set_viewport_y(cursor->bview, orig_viewport_y, 1);
} else {
Expand All @@ -413,6 +428,8 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
bview_draw(cursor->bview);
}

if (inout_all) *inout_all = all;

return MLE_OK;
}

Expand Down
17 changes: 17 additions & 0 deletions editor.c
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,21 @@ int editor_prompt(editor_t *editor, char *prompt, editor_prompt_params_t *params
return MLE_OK;
}

// A printf version of editor_prompt
int editor_prompt_fmt(editor_t *editor, editor_prompt_params_t *params, char **optret_answer, char *prompt_fmt, ...) {
char prompt[512];
va_list vl;
int rv;

va_start(vl, prompt_fmt);
rv = vsnprintf(prompt, sizeof(prompt), prompt_fmt, vl);
va_end(vl);

if (rv < 0 || rv >= (int)sizeof(prompt)) return MLE_ERR;

return editor_prompt(editor, prompt, params, optret_answer);
}

// Open dialog menu
int editor_menu(editor_t *editor, cmd_func_t callback, char *opt_buf_data, int opt_buf_data_len, aproc_t *opt_aproc, bview_t **optret_menu) {
bview_t *menu;
Expand Down Expand Up @@ -1729,6 +1744,7 @@ static void _editor_register_cmds(editor_t *editor) {
_editor_register_cmd_fn(editor, "cmd_remove_extra_cursors", cmd_remove_extra_cursors);
_editor_register_cmd_fn(editor, "cmd_repeat", cmd_repeat);
_editor_register_cmd_fn(editor, "cmd_replace", cmd_replace);
_editor_register_cmd_fn(editor, "cmd_replace_all", cmd_replace_all);
_editor_register_cmd_fn(editor, "cmd_rfind_word", cmd_rfind_word);
_editor_register_cmd_fn(editor, "cmd_rsearch", cmd_rsearch);
_editor_register_cmd_fn(editor, "cmd_save_as", cmd_save_as);
Expand Down Expand Up @@ -1825,6 +1841,7 @@ static void _editor_init_kmaps(editor_t *editor) {
MLE_KBINDING_DEF("cmd_isearch", "C-r"),
MLE_KBINDING_DEF("cmd_repeat", "f5"),
MLE_KBINDING_DEF("cmd_replace", "C-t"),
MLE_KBINDING_DEF("cmd_replace_all", "CM-t"),
MLE_KBINDING_DEF("cmd_cut", "C-k"),
MLE_KBINDING_DEF("cmd_copy", "M-k"),
MLE_KBINDING_DEF("cmd_uncut", "C-u"),
Expand Down
3 changes: 3 additions & 0 deletions mle.h
Original file line number Diff line number Diff line change
Expand Up @@ -423,6 +423,7 @@ int editor_init(editor_t *editor, int argc, char **argv);
int editor_run(editor_t *editor);
int editor_deinit(editor_t *editor);
int editor_prompt(editor_t *editor, char *prompt, editor_prompt_params_t *params, char **optret_answer);
int editor_prompt_fmt(editor_t *editor, editor_prompt_params_t *params, char **optret_answer, char *prompt_fmt, ...);
int editor_menu(editor_t *editor, cmd_func_t fn_callback, char *opt_buf_data, int opt_buf_data_len, aproc_t *opt_aproc, bview_t **optret_menu);
int editor_open_bview(editor_t *editor, bview_t *opt_parent, int type, char *opt_path, int opt_path_len, int make_active, bint_t linenum, int skip_resize, buffer_t *opt_buffer, bview_t **optret_bview);
int editor_close_bview(editor_t *editor, bview_t *bview, int *optret_num_closed);
Expand Down Expand Up @@ -477,6 +478,7 @@ int cursor_get_mark(cursor_t *cursor, mark_t **ret_mark);
int cursor_get_anchor(cursor_t *cursor, mark_t **ret_anchor);
int cursor_lift_anchor(cursor_t *cursor);
int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt_replacement);
int cursor_replace_ex(cursor_t *cursor, int interactive, char *opt_regex, char *opt_replacement, char *opt_cmd_name, int *inout_all, int *optret_num_replacements, int *optret_cancelled);
int cursor_select_between(cursor_t *cursor, mark_t *a, mark_t *b, int use_srules);
int cursor_select_by(cursor_t *cursor, const char *strat, int use_srules);
int cursor_select_by_bracket(cursor_t *cursor, int use_srules);
Expand Down Expand Up @@ -564,6 +566,7 @@ int cmd_redraw(cmd_context_t *ctx);
int cmd_remove_extra_cursors(cmd_context_t *ctx);
int cmd_repeat(cmd_context_t *ctx);
int cmd_replace(cmd_context_t *ctx);
int cmd_replace_all(cmd_context_t *ctx);
int cmd_rfind_word(cmd_context_t *ctx);
int cmd_rsearch(cmd_context_t *ctx);
int cmd_save_as(cmd_context_t *ctx);
Expand Down
16 changes: 16 additions & 0 deletions tests/func/test_search_replace.sh
Original file line number Diff line number Diff line change
Expand Up @@ -89,3 +89,19 @@ declare -A expected
expected[history_line]='^bview.0.cursor.0.mark.line_index=1$'
expected[history_col ]='^bview.0.cursor.0.mark.col=0$'
source 'test.sh'

# cmd_replace_all (all)
macro='1 a C-n 2 b C-n 3 c CM-t ( \ d ) ( \ w ) enter $ 2 $ 1 enter a'
declare -A expected
expected[replace_all_1_1]='^a1$'
expected[replace_all_1_2]='^b2$'
expected[replace_all_1_3]='^c3$'
source 'test.sh'

# cmd_replace_all (no, yes, cancel)
macro='1 a C-n 2 b C-n 3 c CM-t ( \ d ) ( \ w ) enter $ 2 $ 1 enter n y C-c'
declare -A expected
expected[replace_all_2_1]='^1a$'
expected[replace_all_2_2]='^b2$'
expected[replace_all_2_3]='^3c$'
source 'test.sh'

0 comments on commit 8f32163

Please sign in to comment.