Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -229,15 +229,7 @@ private void createLineHeaderCodeMinings(List<UnifiedDiff> diffs, List<ICodeMini
continue;
}
try {
ICodeMining mining;
if (diff.leftStart == doc.getLength()) {
mining = new UnifiedDiffFooterCodeMining(doc, this, null, diff, tabWidth,
this.deletionBackgroundColor);
} else {
mining = new UnifiedDiffLineHeaderCodeMining(new Position(diff.leftStart, 1), this, diff,
tabWidth, this.detailedDiffColor, this.deletionBackgroundColor, tv);
}
minings.add(mining);
minings.add(createMining(doc, diff, diff.leftStart, tabWidth, tv));
} catch (BadLocationException e) {
error(e);
}
Expand All @@ -247,15 +239,7 @@ private void createLineHeaderCodeMinings(List<UnifiedDiff> diffs, List<ICodeMini
continue;
}
try {
ICodeMining mining;
if (diff.leftStart == doc.getLength()) {
mining = new UnifiedDiffFooterCodeMining(doc, this, null, diff, tabWidth,
this.deletionBackgroundColor);
} else {
mining = new UnifiedDiffLineHeaderCodeMining(new Position(diff.leftStart + diff.leftLength, 1),
this, diff, tabWidth, this.detailedDiffColor, this.deletionBackgroundColor, tv);
}
minings.add(mining);
minings.add(createMining(doc, diff, diff.leftStart + diff.leftLength, tabWidth, tv));
} catch (BadLocationException e) {
error(e);
}
Expand All @@ -264,22 +248,37 @@ private void createLineHeaderCodeMinings(List<UnifiedDiff> diffs, List<ICodeMini
continue;
}
try {
ICodeMining mining;
if (diff.leftStart == doc.getLength()) {
mining = new UnifiedDiffFooterCodeMining(doc, this, null, diff, tabWidth,
this.deletionBackgroundColor);
} else {
mining = new UnifiedDiffLineHeaderCodeMining(new Position(diff.leftStart, 1), this, diff,
tabWidth, this.detailedDiffColor, this.deletionBackgroundColor, tv);
}
minings.add(mining);
minings.add(createMining(doc, diff, diff.leftStart, tabWidth, tv));
} catch (BadLocationException e) {
error(e);
}
}
}
}

/**
* A line header mining reserves its height as the vertical indent of its line,
* so the viewer can scroll over it. A footer mining reserves nothing and is
* therefore only used where no line start is available: behind the last,
* non-empty line of the document.
*/
private ICodeMining createMining(IDocument doc, UnifiedDiff diff, int offset, int tabWidth, ITextViewer tv)
throws BadLocationException {
int end = doc.getLength();
if (offset >= end && !startsLine(doc, end)) {
return new UnifiedDiffFooterCodeMining(doc, this, null, diff, tabWidth, this.deletionBackgroundColor);
}
// a position must not reach beyond the document, otherwise the annotation model
// silently drops it
int start = Math.min(offset, end);
return new UnifiedDiffLineHeaderCodeMining(new Position(start, start < end ? 1 : 0), this, diff, tabWidth,
this.detailedDiffColor, this.deletionBackgroundColor, tv);
}

private static boolean startsLine(IDocument doc, int offset) throws BadLocationException {
return doc.getLineOffset(doc.getLineOfOffset(offset)) == offset;
}

static class UnifiedDiffFooterCodeMining extends DocumentFooterCodeMining {
private final String unifiedDiffLabel;
private final Color deletionBackgroundColor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,25 @@ public void testWhitespaceOnlyChangeIsReportedWhenNotIgnored() {
"with ignoreWhiteSpace(false) the changed indentation is a diff");
}

/**
* A diff at the very end of the document is shown as a code mining. Only a line
* header mining reserves its height in the text widget, so an emptied file must
* not fall back to a footer mining: the removed content would be unreachable
* because the viewer would have nothing to scroll over.
*/
@Test
public void testRemovingTheWholeContentStaysScrollable() {
setEditorContent("");
String removed = "a removed line\n".repeat(200);

assertTrue(UnifiedDiff.create(editor, removed, UnifiedDiffMode.OVERLAY_READ_ONLY_MODE).open().isOK());

StyledText widget = viewer().getTextWidget();
int reserved = waitForVerticalIndent(widget);
assertTrue(reserved >= 200 * widget.getLineHeight(),
"the 200 removed lines must reserve scrollable space, but only " + reserved + " pixels were reserved");
}

/**
* Opening a second diff on the same editor must replace the first one instead
* of stacking annotations and diffs on top of each other.
Expand Down Expand Up @@ -410,6 +429,20 @@ private static int countAnnotations(IAnnotationModel model, String type) {
return annotations(model, type).size();
}

/**
* The vertical indent of a line is only applied while the code mining is
* painted, and the minings themselves are resolved asynchronously.
*/
private static int waitForVerticalIndent(StyledText widget) {
long deadline = System.currentTimeMillis() + 10_000;
int indent = 0;
while (indent == 0 && System.currentTimeMillis() < deadline) {
forcePaintCycle(widget);
indent = widget.getLineVerticalIndent(0);
}
return indent;
}

private static void forcePaintCycle(StyledText tw) {
if (tw == null || tw.isDisposed()) {
return;
Expand Down
Loading