aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/core-commands.c2
-rw-r--r--src/search.c53
-rw-r--r--src/search.h1
-rw-r--r--tests/testsuite.at7
4 files changed, 60 insertions, 3 deletions
diff --git a/src/core-commands.c b/src/core-commands.c
index d2abe79..4f3ed94 100644
--- a/src/core-commands.c
+++ b/src/core-commands.c
@@ -1037,6 +1037,8 @@ teco_state_fcommand_input(teco_machine_main_t *ctx, gunichar chr, GError **error
.modifier_at = TRUE, .modifier_colon = 2},
['R'] = {&teco_state_replace_default,
.modifier_at = TRUE, .modifier_colon = 2},
+ ['N'] = {&teco_state_replace_default_all,
+ .modifier_at = TRUE, .modifier_colon = 1},
['G'] = {&teco_state_changedir,
.modifier_at = TRUE},
diff --git a/src/search.c b/src/search.c
index 7fcf10e..b02e178 100644
--- a/src/search.c
+++ b/src/search.c
@@ -1000,9 +1000,12 @@ teco_state_search_all_initial(teco_machine_main_t *ctx, GError **error)
static teco_state_t *
teco_state_search_all_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
{
- if (ctx->flags.mode <= TECO_MODE_NORMAL &&
- (!teco_state_search_done(ctx, str, error) ||
- !teco_ed_hook(TECO_ED_HOOK_EDIT, error)))
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
+ return &teco_state_start;
+
+ const teco_buffer_t *curbuf = teco_ring_current;
+ if (!teco_state_search_done(ctx, str, error) ||
+ (teco_ring_current != curbuf && !teco_ed_hook(TECO_ED_HOOK_EDIT, error)))
return NULL;
return &teco_state_start;
@@ -1354,3 +1357,47 @@ teco_state_replace_default_done(teco_machine_main_t *ctx, const teco_string_t *s
TECO_DEFINE_STATE_SEARCH(teco_state_replace_default,
.expectstring.last = FALSE
);
+
+static teco_state_t *
+teco_state_replace_default_all_done(teco_machine_main_t *ctx, const teco_string_t *str, GError **error)
+{
+ if (ctx->flags.mode > TECO_MODE_NORMAL)
+ return &teco_state_replace_default_ignore;
+
+ const teco_buffer_t *curbuf = teco_ring_current;
+ teco_state_t *state = teco_state_replace_default_done(ctx, str, error);
+ if (!state || (curbuf != teco_ring_current && !teco_ed_hook(TECO_ED_HOOK_EDIT, error)))
+ return NULL;
+
+ return state;
+}
+
+/*$ FN
+ * [n]FN[pattern]$[string]$ -- Search and replace with default over buffer-boundaries
+ * -FN[pattern]$[string]$
+ * from,toFN[pattern]$[string]$
+ * [n]:FN[pattern]$[string]$ -> Success|Failure
+ * -:FN[pattern]$[string]$ -> Success|Failure
+ * from,to:FN[pattern]$[string]$ -> Success|Failure
+ * [n]::FN[pattern]$[string]$ -> Success|Failure
+ * -::FN[pattern]$[string]$ -> Success|Failure
+ * from,to::FN[pattern]$[string]$ -> Success|Failure
+ *
+ * The \fBFN\fP command is similar to the \fBFR\fP command
+ * but will continue to search for occurrences of <pattern> when the
+ * end or beginning of the current buffer is reached.
+ * It searches for <pattern> just like the search over buffer-boundaries
+ * command (\fBN\fP) and replaces the occurrence with <string>
+ * similar to what \fBFR\fP does.
+ * If <string> is empty the string in the global replacement
+ * register is implied instead.
+ *
+ * \fBFN\fP also differs from \fBFR\fP in the interpretation of two arguments.
+ * Using two arguments the search will be bounded between the
+ * buffer with number <from>, up to the buffer with number
+ * <to>.
+ */
+TECO_DEFINE_STATE_SEARCH(teco_state_replace_default_all,
+ .expectstring.last = FALSE,
+ .initial_cb = (teco_state_initial_cb_t)teco_state_search_all_initial
+);
diff --git a/src/search.h b/src/search.h
index 621fdd1..222ca6c 100644
--- a/src/search.h
+++ b/src/search.h
@@ -28,3 +28,4 @@ TECO_DECLARE_STATE(teco_state_search_kill);
TECO_DECLARE_STATE(teco_state_search_delete);
TECO_DECLARE_STATE(teco_state_replace);
TECO_DECLARE_STATE(teco_state_replace_default);
+TECO_DECLARE_STATE(teco_state_replace_default_all);
diff --git a/tests/testsuite.at b/tests/testsuite.at
index fd93aa4..8155ce4 100644
--- a/tests/testsuite.at
+++ b/tests/testsuite.at
@@ -203,6 +203,13 @@ TE_CHECK([[-^X @^Um{^X} Mm-0"N(0/0)']], 0, ignore, ignore)
TE_CHECK([[@I/XYZ/ J ::@S/X/"F(0/0)' H::@S/Z/"S(0/0)']], 0, ignore, ignore)
AT_CLEANUP
+AT_SETUP([Searches over buffer boundaries])
+TE_CHECK([[@I/XYZ/J @EB/foo/ @I/XZY/J @:N/Z/"F(0/0)' Q*-2"N(0/0)'
+ @:N//"F(0/0)' Q*-1"N(0/0)']], 0, ignore, ignore)
+TE_CHECK([[@I/XYZ/J @EB/foo/ @I/XZY/J @:FN/Z/0/"F(0/0)' Q*-2"N(0/0)'
+ @:FN///"F(0/0)' Q*-1"N(0/0)']], 0, ignore, ignore)
+AT_CLEANUP
+
AT_SETUP([Search and insertion ranges])
TE_CHECK([[@I/XXYYZZ/^SC ."N(0/0)' C @S/YY/^YU1U0 Q0-2"N(0/0)' Q1-4"N(0/0)']], 0, ignore, ignore)
TE_CHECK([[@I/XXYYZZ/J @S/XX^E[^EMY]/ 1^YXa :Qa-2"N(0/0)']], 0, ignore, ignore)