Hi,
When two hunks in a patch have the exact same context, and in the file that the patch applies to one of the two contexts has changed a bit (in such a way that hunk #1 would apply fine with fuzz 1), then *both* hunks mistakenly get applied to the place where the context hasn't changed. For an example, see the attached file and patch. Apply the patch with 'patch -p1 <goes-wrong.patch' and see the output: patching file testor.c Hunk #1 succeeded at 44 (offset 37 lines). It does not say anything about hunk #2 -- which is wrong, because after applying hunk #1 in the wrong place, the context for hunk #2 has changed, and it can only apply the second hunk with fuzz 2. Expected behavior: at the very least, 'patch' should mention that hunk #2 was applied with fuzz 2. And maybe patching should fail entirely, because when both hunks get applied to the same spot, also hunk #1 has in the end result factually been applied with fuzz 2. The ideal behavior would be that 'patch' tries to minimize the overall amount of fuzz. When it notices that applying hunk #1 with an offset of 37 lines results in a total fuzz of 2 (or 4), it should try to apply hunk #1 with fuzz 1. When it does that, it will see that hunk #2 applies cleanly, so the total amount of fuzz will be just 1, which is better than 2. So the fuzz 1 alternative should be chosen. (I could also imagine that patch would make use of the function name mentioned in the @@ line: applying a hunk outside of that function would count as fuzz 1.5, so that it becomes better to accept a little fuzz within a function than to accept a perfect match outside of that function.) Benno
/* Try to move up nrows softwrapped chunks from the given line and the * given column (leftedge). After moving, leftedge will be set to the * starting column of the current chunk. Return the number of chunks we * couldn't move up, which will be zero if we completely succeeded. */ int go_back_chunks(int nrows, filestruct **line, size_t *leftedge) { int i; #ifndef NANO_TINY if (ISSET(SOFTWRAP)) { /* Recede through the requested number of chunks. */ for (i = nrows; i > 0; i--) { size_t chunk = chunk_for(*leftedge, *line); *leftedge = 0; if (chunk >= i) return go_forward_chunks(chunk - i, line, leftedge); if (*line == openfile->fileage) break; i -= chunk; *line = (*line)->prev; *leftedge = HIGHEST_POSITIVE; } if (*leftedge == HIGHEST_POSITIVE) *leftedge = leftedge_for(*leftedge, *line); } else #endif for (i = nrows; i > 0 && (*line)->prev != NULL; i--) *line = (*line)->prev; return i; } /* Try to move down nrows softwrapped chunks from the given line and the * given column (leftedge). After moving, leftedge will be set to the * starting column of the current chunk. Return the number of chunks we * couldn't move down, which will be zero if we completely succeeded. */ int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge) { int i; /* This is the FIRST hunk, meant for go_back... */ if (xxx) yyy; /* This is the SECOND hunk, meant for go_forward... */ if (oops) not again; #ifndef NANO_TINY if (ISSET(SOFTWRAP)) { size_t current_leftedge = *leftedge; /* Advance through the requested number of chunks. */ for (i = nrows; i > 0; i--) { bool end_of_line = FALSE; current_leftedge = get_softwrap_breakpoint((*line)->data, current_leftedge, &end_of_line); if (!end_of_line) continue; if (*line == openfile->filebot) break; *line = (*line)->next; current_leftedge = 0; } /* Only change leftedge when we actually could move. */ if (i < nrows) *leftedge = current_leftedge; } else #endif for (i = nrows; i > 0 && (*line)->next != NULL; i--) *line = (*line)->next; return i; } /* Return TRUE if there are fewer than a screen's worth of lines between * the line at line number was_lineno (and column was_leftedge, if we're * in softwrap mode) and the line at current[current_x]. */ bool less_than_a_screenful(size_t was_lineno, size_t was_leftedge) { #ifndef NANO_TINY if (ISSET(SOFTWRAP)) { filestruct *line = openfile->current; size_t leftedge = leftedge_for(xplustabs(), openfile->current); int rows_left = go_back_chunks(editwinrows - 1, &line, &leftedge); return (rows_left > 0 || line->lineno < was_lineno || (line->lineno == was_lineno && leftedge <= was_leftedge)); } else #endif return (openfile->current->lineno - was_lineno < editwinrows); }
diff --git a/testor.c b/testor.c index d9bde426..7b309d73 100644 --- a/testor.c +++ b/testor.c @@ -7,6 +7,10 @@ int go_back_chunks(int nrows, filestruct **line, size_t *leftedge) { int i; + /* This is the FIRST hunk, meant for go_back... */ + if (xxx) + yyy; + #ifndef NANO_TINY if (ISSET(SOFTWRAP)) { size_t current_leftedge = *leftedge; @@ -44,6 +48,10 @@ int go_forward_chunks(int nrows, filestruct **line, size_t *leftedge) { int i; + /* This is the SECOND hunk, meant for go_forward... */ + if (oops) + not again; + #ifndef NANO_TINY if (ISSET(SOFTWRAP)) { size_t current_leftedge = *leftedge;