Skip to content

Commit 8f32163

Browse files
committed
add cmd_replace_all
1 parent 3e82f1c commit 8f32163

File tree

5 files changed

+120
-7
lines changed

5 files changed

+120
-7
lines changed

cmd.c

+60
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,66 @@ int cmd_replace(cmd_context_t *ctx) {
506506
return cursor_replace(ctx->cursor, 1, NULL, NULL);
507507
}
508508

509+
// Interactive search and replace on all buffers
510+
int cmd_replace_all(cmd_context_t *ctx) {
511+
bview_t *bview, *bview_orig;
512+
int num_bviews, do_replace_all, num_replacements, num_replacements_tmp;
513+
int cancelled, buffer_done_i, i, already_done;
514+
char *regex, *replacement;
515+
buffer_t **buffer_done;
516+
517+
bview_orig = ctx->bview;
518+
do_replace_all = 0;
519+
num_replacements = 0;
520+
cancelled = 0;
521+
regex = NULL;
522+
replacement = NULL;
523+
num_bviews = 0;
524+
CDL_COUNT2(ctx->editor->all_bviews, bview, num_bviews, all_next);
525+
buffer_done = calloc(num_bviews, sizeof(buffer_t *));
526+
buffer_done_i = 0;
527+
528+
do {
529+
editor_prompt(ctx->editor, "replace_all: Search regex?", NULL, &regex);
530+
if (!regex) break;
531+
editor_prompt(ctx->editor, "replace_all: Replacement string?", NULL, &replacement);
532+
if (!replacement) break;
533+
534+
CDL_FOREACH2(ctx->editor->all_bviews, bview, all_next) {
535+
if (!MLE_BVIEW_IS_EDIT(bview)) continue;
536+
537+
// Check if buffer in done list
538+
// TODO inefficient, could replace with hash
539+
for (i = 0, already_done = 0; i < buffer_done_i; i++) {
540+
if (buffer_done[i] == bview->buffer) {
541+
already_done = 1;
542+
break;
543+
}
544+
}
545+
if (already_done) continue;
546+
547+
// Search and replace on this bview
548+
editor_set_active(ctx->editor, bview);
549+
cursor_replace_ex(bview->active_cursor, 1, regex, replacement, "replace_all", &do_replace_all, &num_replacements_tmp, &cancelled);
550+
num_replacements += num_replacements_tmp;
551+
552+
// Add buffer to done list
553+
buffer_done[buffer_done_i++] = bview->buffer;
554+
if (cancelled) break;
555+
}
556+
} while (0);
557+
558+
editor_set_active(ctx->editor, bview_orig);
559+
560+
MLE_SET_INFO(ctx->editor, "replace_all: Replaced %d instance(s) in %d buffer(s)", num_replacements, buffer_done_i);
561+
562+
if (regex) free(regex);
563+
if (replacement) free(replacement);
564+
if (buffer_done) free(buffer_done);
565+
566+
return MLE_OK;
567+
}
568+
509569
// Repeat last cmd
510570
int cmd_repeat(cmd_context_t *ctx) {
511571
// This is a special case in _editor_loop

cursor.c

+24-7
Original file line numberDiff line numberDiff line change
@@ -275,6 +275,11 @@ int cursor_uncut_last(cursor_t *cursor) {
275275

276276
// Regex search and replace
277277
int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt_replacement) {
278+
return cursor_replace_ex(cursor, interactive, opt_regex, opt_replacement, NULL, NULL, NULL, NULL);
279+
}
280+
281+
// Regex search and replace (extended params)
282+
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) {
278283
char *regex;
279284
char *replacement;
280285
int wrapped;
@@ -295,9 +300,12 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
295300
PCRE2_SIZE pcre_ovector[30];
296301
str_t repl_backref = {0};
297302
int num_replacements;
303+
char *cmd_name;
298304

299305
if (!interactive && (!opt_regex || !opt_replacement)) {
300306
return MLE_ERR;
307+
} else if ((opt_regex && !opt_replacement) || (!opt_regex && opt_replacement)) {
308+
return MLE_ERR;
301309
}
302310

303311
regex = NULL;
@@ -309,19 +317,20 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
309317
search_mark = NULL;
310318
search_mark_end = NULL;
311319
anchored_before = 0;
312-
all = interactive ? 0 : 1;
320+
all = interactive ? (inout_all ? *inout_all : 0) : 1;
313321
num_replacements = 0;
314322
mark_set_pcre_capture(&pcre_rc, pcre_ovector, 30);
315323
orig_viewport_y = -1;
324+
cmd_name = opt_cmd_name ? opt_cmd_name : "replace";
316325

317326
do {
318-
if (!interactive) {
327+
if (!interactive || (opt_regex && opt_replacement)) {
319328
regex = strdup(opt_regex);
320329
replacement = strdup(opt_replacement);
321330
} else {
322-
editor_prompt(cursor->bview->editor, "replace: Search regex?", NULL, &regex);
331+
editor_prompt_fmt(cursor->bview->editor, NULL, &regex, "%s: Search regex?", cmd_name);
323332
if (!regex) break;
324-
editor_prompt(cursor->bview->editor, "replace: Replacement string?", NULL, &replacement);
333+
editor_prompt_fmt(cursor->bview->editor, NULL, &replacement, "%s: Replacement string?", cmd_name);
325334
if (!replacement) break;
326335
}
327336
orig_mark = buffer_add_mark(cursor->bview->buffer, NULL, 0);
@@ -360,14 +369,16 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
360369
buffer_add_srule(cursor->bview->buffer, highlight);
361370
bview_rectify_viewport(cursor->bview);
362371
bview_draw(cursor->bview);
363-
editor_prompt(cursor->bview->editor, "replace: OK to replace? (y=yes, n=no, a=all, C-c=stop)",
364-
&(editor_prompt_params_t) { .kmap = cursor->bview->editor->kmap_prompt_yna }, &yn
372+
editor_prompt_fmt(cursor->bview->editor,
373+
&(editor_prompt_params_t) { .kmap = cursor->bview->editor->kmap_prompt_yna }, &yn,
374+
"%s: OK to replace? (y=yes, n=no, a=all, C-c=stop)", cmd_name
365375
);
366376
buffer_remove_srule(cursor->bview->buffer, highlight);
367377
srule_destroy(highlight);
368378
bview_draw(cursor->bview);
369379
}
370380
if (!yn) {
381+
if (optret_cancelled) *optret_cancelled = 1;
371382
break;
372383
} else if (0 == strcmp(yn, MLE_PROMPT_YES) || 0 == strcmp(yn, MLE_PROMPT_ALL)) {
373384
str_append_replace_with_backrefs(&repl_backref, search_mark->bline->data, replacement, pcre_rc, pcre_ovector, 30);
@@ -404,7 +415,11 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
404415
if (search_mark_end) mark_destroy(search_mark_end);
405416

406417
if (interactive) {
407-
MLE_SET_INFO(cursor->bview->editor, "replace: Replaced %d instance(s)", num_replacements);
418+
if (optret_num_replacements) {
419+
*optret_num_replacements = num_replacements;
420+
} else {
421+
MLE_SET_INFO(cursor->bview->editor, "%s: Replaced %d instance(s)", cmd_name, num_replacements);
422+
}
408423
if (orig_viewport_y >= 0) {
409424
bview_set_viewport_y(cursor->bview, orig_viewport_y, 1);
410425
} else {
@@ -413,6 +428,8 @@ int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt
413428
bview_draw(cursor->bview);
414429
}
415430

431+
if (inout_all) *inout_all = all;
432+
416433
return MLE_OK;
417434
}
418435

editor.c

+17
Original file line numberDiff line numberDiff line change
@@ -310,6 +310,21 @@ int editor_prompt(editor_t *editor, char *prompt, editor_prompt_params_t *params
310310
return MLE_OK;
311311
}
312312

313+
// A printf version of editor_prompt
314+
int editor_prompt_fmt(editor_t *editor, editor_prompt_params_t *params, char **optret_answer, char *prompt_fmt, ...) {
315+
char prompt[512];
316+
va_list vl;
317+
int rv;
318+
319+
va_start(vl, prompt_fmt);
320+
rv = vsnprintf(prompt, sizeof(prompt), prompt_fmt, vl);
321+
va_end(vl);
322+
323+
if (rv < 0 || rv >= (int)sizeof(prompt)) return MLE_ERR;
324+
325+
return editor_prompt(editor, prompt, params, optret_answer);
326+
}
327+
313328
// Open dialog menu
314329
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) {
315330
bview_t *menu;
@@ -1729,6 +1744,7 @@ static void _editor_register_cmds(editor_t *editor) {
17291744
_editor_register_cmd_fn(editor, "cmd_remove_extra_cursors", cmd_remove_extra_cursors);
17301745
_editor_register_cmd_fn(editor, "cmd_repeat", cmd_repeat);
17311746
_editor_register_cmd_fn(editor, "cmd_replace", cmd_replace);
1747+
_editor_register_cmd_fn(editor, "cmd_replace_all", cmd_replace_all);
17321748
_editor_register_cmd_fn(editor, "cmd_rfind_word", cmd_rfind_word);
17331749
_editor_register_cmd_fn(editor, "cmd_rsearch", cmd_rsearch);
17341750
_editor_register_cmd_fn(editor, "cmd_save_as", cmd_save_as);
@@ -1825,6 +1841,7 @@ static void _editor_init_kmaps(editor_t *editor) {
18251841
MLE_KBINDING_DEF("cmd_isearch", "C-r"),
18261842
MLE_KBINDING_DEF("cmd_repeat", "f5"),
18271843
MLE_KBINDING_DEF("cmd_replace", "C-t"),
1844+
MLE_KBINDING_DEF("cmd_replace_all", "CM-t"),
18281845
MLE_KBINDING_DEF("cmd_cut", "C-k"),
18291846
MLE_KBINDING_DEF("cmd_copy", "M-k"),
18301847
MLE_KBINDING_DEF("cmd_uncut", "C-u"),

mle.h

+3
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,7 @@ int editor_init(editor_t *editor, int argc, char **argv);
423423
int editor_run(editor_t *editor);
424424
int editor_deinit(editor_t *editor);
425425
int editor_prompt(editor_t *editor, char *prompt, editor_prompt_params_t *params, char **optret_answer);
426+
int editor_prompt_fmt(editor_t *editor, editor_prompt_params_t *params, char **optret_answer, char *prompt_fmt, ...);
426427
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);
427428
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);
428429
int editor_close_bview(editor_t *editor, bview_t *bview, int *optret_num_closed);
@@ -477,6 +478,7 @@ int cursor_get_mark(cursor_t *cursor, mark_t **ret_mark);
477478
int cursor_get_anchor(cursor_t *cursor, mark_t **ret_anchor);
478479
int cursor_lift_anchor(cursor_t *cursor);
479480
int cursor_replace(cursor_t *cursor, int interactive, char *opt_regex, char *opt_replacement);
481+
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);
480482
int cursor_select_between(cursor_t *cursor, mark_t *a, mark_t *b, int use_srules);
481483
int cursor_select_by(cursor_t *cursor, const char *strat, int use_srules);
482484
int cursor_select_by_bracket(cursor_t *cursor, int use_srules);
@@ -564,6 +566,7 @@ int cmd_redraw(cmd_context_t *ctx);
564566
int cmd_remove_extra_cursors(cmd_context_t *ctx);
565567
int cmd_repeat(cmd_context_t *ctx);
566568
int cmd_replace(cmd_context_t *ctx);
569+
int cmd_replace_all(cmd_context_t *ctx);
567570
int cmd_rfind_word(cmd_context_t *ctx);
568571
int cmd_rsearch(cmd_context_t *ctx);
569572
int cmd_save_as(cmd_context_t *ctx);

tests/func/test_search_replace.sh

+16
Original file line numberDiff line numberDiff line change
@@ -89,3 +89,19 @@ declare -A expected
8989
expected[history_line]='^bview.0.cursor.0.mark.line_index=1$'
9090
expected[history_col ]='^bview.0.cursor.0.mark.col=0$'
9191
source 'test.sh'
92+
93+
# cmd_replace_all (all)
94+
macro='1 a C-n 2 b C-n 3 c CM-t ( \ d ) ( \ w ) enter $ 2 $ 1 enter a'
95+
declare -A expected
96+
expected[replace_all_1_1]='^a1$'
97+
expected[replace_all_1_2]='^b2$'
98+
expected[replace_all_1_3]='^c3$'
99+
source 'test.sh'
100+
101+
# cmd_replace_all (no, yes, cancel)
102+
macro='1 a C-n 2 b C-n 3 c CM-t ( \ d ) ( \ w ) enter $ 2 $ 1 enter n y C-c'
103+
declare -A expected
104+
expected[replace_all_2_1]='^1a$'
105+
expected[replace_all_2_2]='^b2$'
106+
expected[replace_all_2_3]='^3c$'
107+
source 'test.sh'

0 commit comments

Comments
 (0)