replacing: ignore the first match when the user said no

When the user answered No to a replacement prompt, skip the match
at the current position, so we don't stay stuck there.

Also, when replacing in the backward direction, or the match is
of length zero, skip the match at the current position, to not
get stuck.

This fixes https://savannah.gnu.org/bugs/?50126.
Reported-by: David Lawrence Ramsey <pooka109@gmail.com>

This also fixes https://savannah.gnu.org/bugs/?50137,
and refixes https://savannah.gnu.org/bugs/?48635,
and fixes https://savannah.gnu.org/bugs/?50144.
master
Benno Schulenberg 2017-01-24 22:37:37 +01:00
parent 64aa8757a8
commit ef7a7c5360
3 changed files with 18 additions and 12 deletions

View File

@ -533,7 +533,7 @@ void not_found_msg(const char *str);
void search_replace_abort(void);
int search_init(bool replacing, bool use_answer);
int findnextstr(const char *needle, bool whole_word_only, size_t *match_len,
const filestruct *begin, size_t begin_x);
bool skipone, const filestruct *begin, size_t begin_x);
void do_search(void);
#ifndef NANO_TINY
void do_findprevious(void);

View File

@ -232,7 +232,7 @@ int search_init(bool replacing, bool use_answer)
* found something, 0 when nothing, and -2 on cancel. When match_len is
* not NULL, set it to the length of the found string, if any. */
int findnextstr(const char *needle, bool whole_word_only, size_t *match_len,
const filestruct *begin, size_t begin_x)
bool skipone, const filestruct *begin, size_t begin_x)
{
size_t found_len = strlen(needle);
/* The length of a match -- will be recomputed for a regex. */
@ -278,11 +278,13 @@ int findnextstr(const char *needle, bool whole_word_only, size_t *match_len,
}
/* Search for the needle in the current line. */
found = strstrwrapper(line->data, needle, from);
if (!skipone)
found = strstrwrapper(line->data, needle, from);
/* Ignore the initial match at the starting position: continue
* searching from the next character, or invalidate the match. */
if (found == begin->data + begin_x && !came_full_circle) {
if (skipone || (found == begin->data + begin_x && !came_full_circle)) {
skipone = FALSE;
if (ISSET(BACKWARDS_SEARCH) && from != line->data) {
from = line->data + move_mbleft(line->data, from - line->data);
continue;
@ -460,7 +462,7 @@ void go_looking(void)
came_full_circle = FALSE;
didfind = findnextstr(last_search, FALSE, NULL,
didfind = findnextstr(last_search, FALSE, NULL, FALSE,
openfile->current, openfile->current_x);
/* If we found something, and we're back at the exact same spot
@ -576,6 +578,7 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
ssize_t numreplaced = -1;
size_t match_len;
bool replaceall = FALSE;
bool skipone = FALSE;
#ifndef NANO_TINY
bool old_mark_set = openfile->mark_set;
filestruct *top, *bot;
@ -605,7 +608,7 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
while (TRUE) {
int i = 0;
int result = findnextstr(needle, whole_word_only, &match_len,
int result = findnextstr(needle, whole_word_only, &match_len, skipone,
real_current, *real_current_x);
/* If nothing more was found, or the user aborted, stop looping. */
@ -656,6 +659,10 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
break;
else if (i == 2)
replaceall = TRUE;
/* When "No" or moving backwards, the search routine should
* first move one character further before continuing. */
skipone = (i == 0 || ISSET(BACKWARDS_SEARCH));
}
if (i == 1 || replaceall) { /* Yes, replace it. */
@ -701,13 +708,12 @@ ssize_t do_replace_loop(const char *needle, bool whole_word_only,
#ifdef HAVE_REGEX_H
/* Don't find the same zero-length or BOL match again. */
if (match_len == 0 || (*needle == '^' && ISSET(USE_REGEXP)))
match_len++;
skipone = TRUE;
#endif
/* Set the cursor at the last character of the replacement
* text, so that searching will continue /after/ it. Note
* that current_x might be set to (size_t)-1 here. */
/* When moving forward, put the cursor just after the replacement
* text, so that searching will continue there. */
if (!ISSET(BACKWARDS_SEARCH))
openfile->current_x += match_len + length_change - 1;
openfile->current_x += match_len + length_change;
/* Update the file size, and put the changed line into place. */
openfile->totsize += mbstrlen(copy) - mbstrlen(openfile->current->data);

View File

@ -2657,7 +2657,7 @@ bool do_int_spell_fix(const char *word)
}
/* Find the first whole occurrence of word. */
result = findnextstr(word, TRUE, NULL, NULL, 0);
result = findnextstr(word, TRUE, NULL, FALSE, NULL, 0);
/* If the word isn't found, alert the user; if it is, allow correction. */
if (result == 0) {