in plugin/src/software/aws/toolkits/eclipse/amazonq/inlineChat/InlineChatDiffManager.java [95:189]
private boolean computeDiffAndRenderOnEditor(final String newCode) throws Exception {
// Annotation model provides highlighting for the diff additions/deletions
IAnnotationModel annotationModel = task.getEditor().getDocumentProvider().getAnnotationModel(task.getEditor().getEditorInput());
var document = task.getEditor().getDocumentProvider().getDocument(task.getEditor().getEditorInput());
// Clear existing diff annotations prior to starting new diff
clearDiffAnnotations(annotationModel);
// Split original and new code into lines for diff comparison
String[] originalLines = (task.hasActiveSelection()) ? task.getOriginalCode().lines().toArray(String[]::new) : new String[0];
String[] newLines = newCode.lines().toArray(String[]::new);
// Diff generation --> returns Patch object which contains deltas for each line
Patch<String> patch = DiffUtils.diff(Arrays.asList(originalLines), Arrays.asList(newLines));
StringBuilder resultText = new StringBuilder();
currentDiffs.clear(); // Clear previous diffs
int currentPos = 0;
int currentLine = 0;
int deletedLines = 0;
int insertedLines = 0;
for (AbstractDelta<String> delta : patch.getDeltas()) {
// Count deletion and addition lines for telemetry
if (delta.getType() == DeltaType.DELETE || delta.getType() == DeltaType.CHANGE) {
deletedLines += delta.getSource().getLines().size();
}
if (delta.getType() == DeltaType.INSERT || delta.getType() == DeltaType.CHANGE) {
insertedLines += delta.getTarget().getLines().size();
}
// Continuously copy unchanged lines until we hit a diff
while (currentLine < delta.getSource().getPosition()) {
resultText.append(originalLines[currentLine]).append("\n");
currentPos += originalLines[currentLine].length() + 1;
currentLine++;
}
List<String> originalChangedLines = delta.getSource().getLines();
List<String> newChangedLines = delta.getTarget().getLines();
// Handle deleted lines and mark position
for (String line : originalChangedLines) {
resultText.append(line).append("\n");
currentDiffs.add(new TextDiff(task.getSelectionOffset() + currentPos, line.length(), true));
currentPos += line.length() + 1;
}
// Handle added lines and mark position
for (String line : newChangedLines) {
resultText.append(line).append("\n");
currentDiffs.add(new TextDiff(task.getSelectionOffset() + currentPos, line.length(), false));
currentPos += line.length() + 1;
}
currentLine = delta.getSource().getPosition() + delta.getSource().size();
}
// Loop through remaining unchanged lines
while (currentLine < originalLines.length) {
resultText.append(originalLines[currentLine]).append("\n");
currentPos += originalLines[currentLine].length() + 1;
currentLine++;
}
var originalEndsInNewLine = task.getOriginalCode().endsWith("\n");
var diffEndsInNewLine = resultText.length() > 0 && resultText.charAt(resultText.length() - 1) == '\n';
if (!originalEndsInNewLine && diffEndsInNewLine) {
resultText.setLength(resultText.length() - 1);
}
final String finalText = resultText.toString();
// Clear existing annotations in the affected range
clearAnnotationsInRange(annotationModel, task.getSelectionOffset(), task.getSelectionOffset() + task.getOriginalCode().length());
// Apply new diff text
document.replace(task.getSelectionOffset(), task.getPreviousDisplayLength(), finalText);
// Add all annotations after text modifications are complete
for (TextDiff diff : currentDiffs) {
Position position = new Position(diff.offset(), diff.length());
String annotationType = diff.isDeletion() ? annotationDeleted : annotationAdded;
String annotationText = diff.isDeletion() ? "Deleted Code" : "Added Code";
annotationModel.addAnnotation(new Annotation(annotationType, false, annotationText), position);
}
// Store rendered text length for proper clearing next iteration
task.setPreviousDisplayLength(finalText.length());
task.setPreviousPartialResponse(newCode);
task.setNumDeletedLines(deletedLines);
task.setNumAddedLines(insertedLines);
return true;
}