-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
rejected edits trailing whitespaces #4687
rejected edits trailing whitespaces #4687
Conversation
✅ Deploy Preview for continuedev canceled.
|
core/diff/util.ts
Outdated
//checks if two lines match exactly ignoring trailing whitespace differences | ||
//this prevents false mismatches in diff handling when trailing spaces are stripped | ||
|
||
return lineA.trimEnd() === lineB.trimEnd() && lineA !== ""; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This fixes up one case where we are comparing oldLines to newLines, but checking over the code, this isn't the only place where we might have issues:
- in
matchLine()
, after callinglinesMatchPerfectly()
, we make more references tooldLines[i]
that potentially might need changes. - In streamDiff(), we have:
if (oldLinesCopy[0] !== newLine) {
yield { type: "new", line: newLine };
} else {
isLineRemoval = true;
}
which looks suspicious, but I'm pretty sure can never actually be hit: if oldLinesCopy[0] === newLine
then isPerfectMatch
should have been true and the case will be "same"
not "old"
. Needs double checking.
But the takeaway for me here is that the test cases need updating to test different cases where lines differ only in trailing whitespace. From the continue/core
directory, you can run:
$ npm test diff/streamDiff.test.ts
to run streamDiff test cases. Add a test case to check the linesMatchPerfectly
case, add a test case case that exercises: // This is a way to fix indentation, but only for sufficiently long lines to avoid matching whitespace or short lines
when the indentation changes and there is a change in whitespace.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the review, I have made the following changes:
-Added a test case for oldLinesCopy[0] === newLine that confirmed it’s already handled as "same" or "old", so the else statement was unnecessary and removed.
-Trimmed oldLines throughout and added a test to ensure trailing whitespaces are correctly treated as "same", preventing incorrect diffs.
-Added a test to verify that indentation changes in long lines don’t cause unnecessary diffs.
f1a5f04
to
58d8f7c
Compare
core/diff/streamDiff.test.ts
Outdated
}); | ||
|
||
test("ignores indentation changes for sufficiently long lines", async () => { | ||
const oldLines = [" first item", " second arg", "third param", " fourth val "]; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would try to test this more comprehensively - to test that indentation changes on short lines are considered changes, until one line with length > 8 is encountered, then they are ignored, even for short lines.
Importantly, I'd also check here that the same behavior is seen when the old and new lines differ in trailing whitespace - that's the point of adding the check as part of this patch, after all.
Something like:
test.each([false, true])(
`ignores identation changes for sufficiently long lines",
async (trailingWhitespace) => {
[...]
if (trailingWhitespace)
oldLines = oldLines.map(line => line + " ");
[...]
});
I'm sure there's a more stylish way to do that.
// Don't match end bracket lines if too far away | ||
if (i > 4 && isEndBracket) { | ||
return { matchIndex: -1, isPerfectMatch: false, newLine }; | ||
} | ||
|
||
if (linesMatchPerfectly(newLine, oldLines[i])) { | ||
if (linesMatchPerfectly(newLine, oldLineTrimmed)) { | ||
return { matchIndex: i, isPerfectMatch: true, newLine }; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this probably should be oldLines[i] not newLine? The goal here should be that when we return same
- we actually have the old line, not a version that differs in trailing whitespace. First try to make a test case that fails, then change this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test cases I ran for this scenario passed. In streamDiff():
case "same":
yield { type, line: oldLinesCopy.shift()! };
break;
So, regardless of what matchLine() returns for newLine, the line that is actually output is the one removed from oldLinesCopy (which is the original old line with the trailing whitespaces). But I can change it to oldLine[i] to maintain logic and uniformity
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Turned out that this very much needed to be newLine - the calling code relies on this only being different from the passed in newline when the leading indentation changed. Sorry for the confusion!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
All this testing has only made the whitespace and indentation handling more robust!
core/diff/util.ts
Outdated
(permissiveAboutIndentation || newLine.trim().length > 8) | ||
) { | ||
return { | ||
matchIndex: i, | ||
isPerfectMatch: true, | ||
newLine: oldLines[i], | ||
newLine: oldLineTrimmed, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Similarly, I think this should be oldLines[i]?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll change that to oldLine[i] here as well
core/diff/streamDiff.ts
Outdated
@@ -63,8 +63,6 @@ export async function* streamDiff( | |||
|
|||
if (oldLinesCopy[0] !== newLine) { | |||
yield { type: "new", line: newLine }; | |||
} else { | |||
isLineRemoval = true; | |||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You should remove the if/else entirely and just leave the yield, then since isLineRemoval can never be set, it needs to be removed as well.
core/diff/streamDiff.test.ts
Outdated
@@ -223,6 +223,51 @@ describe("streamDiff(", () => { | |||
await expectDiff("fastapi-tabs-vs-spaces.py"); | |||
}); | |||
|
|||
|
|||
test(" condition where oldLinesCopy[0]=== newLine", async () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this was useful during development of your patch, but since this code ends up removed in your patches, I'd suggest removing the test case as well.
fbdda80
to
a8953c9
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a few more comments
core/edit/streamDiffLines.ts
Outdated
@@ -79,7 +79,7 @@ export async function* streamDiffLines( | |||
} | |||
|
|||
// Trim end of oldLines, otherwise we have trailing \r on every line for CRLF files | |||
oldLines = oldLines.map((line) => line.trimEnd()); | |||
oldLines = oldLines.map((line) => line); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This can just go away, along with the comment
core/diff/streamDiff.test.ts
Outdated
"short", | ||
"middle", | ||
"a long enough line", | ||
"indented short", |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"indented short".length is going to be > 8 - this needs to be "short2" or something to actually test that handlng.
core/diff/util.ts
Outdated
// This is a way to fix indentation, but only for sufficiently long lines to avoid matching whitespace or short lines | ||
if ( | ||
newLine.trimStart() === oldLines[i].trimStart() && | ||
newLine.trimStart() === oldLineTrimmed.trimStart() && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we can assume that newLine is trimmed at the end, so this should be newLine.trim()? [make sure the test case tests this - one line that is supposed to not reindented should have a trailing space on the new]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead, as discussed I created newLineTrimmed.
newLineTrimmed.trimStart() === oldLineTrimmed.trimStart()
f0be628
to
8ebcc0c
Compare
trailing whitespace was stripped before generating diffs, causing mismatches when rejecting a diff in the editor. this fix ensures that trailing whitespace differences do not interfere with accurate diff rejection.
8ebcc0c
to
4822926
Compare
since `oldLinesCopy[0] === newLine` should always be classified as `"same"` or `"old"` in the earlier block, the `else` statement (which sets `isLineRemoval = true`)feels redundant and never actually executed.
4822926
to
3ba5452
Compare
Looks good to me now! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for contributing @panyamkeerthana, and @owtaylor for the thorough review!
Description
Earlier trailing whitespace was stripped in streamDiffLines.ts before generating diffs, causing mismatches when rejecting a diff in the editor.
This fix updates linesMatchPerfectly to compare lines using trimEnd(), ensuring that trailing whitespace differences do not interfere with accurate diff rejection.
Screenshots
Granite-Code/granite-code#50