IDEA-136265 diff: do not paint borders for changed blocks

* paint line for empty ranges at the beginning of the file
* paint line to separate non-squashed changes (highlight split changes policy)
* move empty range highlighter into DiffDrawUtil.createHighlighter
This commit is contained in:
Aleksey Pivovarov
2016-07-08 15:35:41 +03:00
parent d4840b76ad
commit 95384fd370
8 changed files with 129 additions and 64 deletions
@@ -48,18 +48,18 @@ public class SimpleDiffChange {
private int[] myLineStartShifts = new int[2];
private int[] myLineEndShifts = new int[2];
// TODO: adjust color from inner fragments - configurable
public SimpleDiffChange(@NotNull SimpleDiffViewer viewer,
@NotNull LineFragment fragment) {
@NotNull LineFragment fragment,
@Nullable LineFragment previousFragment) {
myViewer = viewer;
myFragment = fragment;
myInnerFragments = fragment.getInnerFragments();
installHighlighter();
installHighlighter(previousFragment);
}
public void installHighlighter() {
public void installHighlighter(@Nullable LineFragment previousFragment) {
assert myHighlighters.isEmpty();
if (myInnerFragments != null) {
@@ -68,6 +68,8 @@ public class SimpleDiffChange {
else {
doInstallHighlighterSimple();
}
doInstallNonSquashedChangesSeparator(previousFragment);
doInstallActionHighlighters();
}
@@ -100,6 +102,11 @@ public class SimpleDiffChange {
}
}
private void doInstallNonSquashedChangesSeparator(@Nullable LineFragment previousFragment) {
createNonSquashedChangesSeparator(previousFragment, Side.LEFT);
createNonSquashedChangesSeparator(previousFragment, Side.RIGHT);
}
private void doInstallActionHighlighters() {
myOperations.add(createOperation(Side.LEFT));
myOperations.add(createOperation(Side.RIGHT));
@@ -113,7 +120,6 @@ public class SimpleDiffChange {
int endLine = side.getEndLine(myFragment);
myHighlighters.addAll(DiffDrawUtil.createHighlighter(editor, startLine, endLine, type, ignored));
myHighlighters.addAll(DiffDrawUtil.createLineMarker(editor, startLine, endLine, type, false));
}
private void createInlineHighlighter(@NotNull DiffFragment fragment, @NotNull Side side) {
@@ -129,6 +135,22 @@ public class SimpleDiffChange {
myHighlighters.addAll(DiffDrawUtil.createInlineHighlighter(editor, start, end, type));
}
private void createNonSquashedChangesSeparator(@Nullable LineFragment previousFragment, @NotNull Side side) {
if (previousFragment == null) return;
int startLine = side.getStartLine(myFragment);
int endLine = side.getEndLine(myFragment);
int prevStartLine = side.getStartLine(previousFragment);
int prevEndLine = side.getEndLine(previousFragment);
if (startLine == endLine) return;
if (prevStartLine == prevEndLine) return;
if (prevEndLine != startLine) return;
myHighlighters.addAll(DiffDrawUtil.createLineMarker(myViewer.getEditor(side), startLine, TextDiffType.MODIFIED));
}
public void updateGutterActions(boolean force) {
for (MyGutterOperation operation : myOperations) {
operation.update(force);
@@ -236,13 +236,17 @@ public class SimpleDiffViewer extends TwosideTextDiffViewer {
myPanel.addNotification(DiffNotifications.createEqualContents(equalCharsets, equalSeparators));
}
if (data.getFragments() != null) {
for (LineFragment fragment : data.getFragments()) {
myDiffChanges.add(new SimpleDiffChange(this, fragment));
List<LineFragment> fragments = data.getFragments();
if (fragments != null) {
for (int i = 0; i < fragments.size(); i++) {
LineFragment fragment = fragments.get(i);
LineFragment previousFragment = i != 0 ? fragments.get(i - 1) : null;
myDiffChanges.add(new SimpleDiffChange(this, fragment, previousFragment));
}
}
myFoldingModel.install(data.getFragments(), myRequest, getFoldingModelSettings());
myFoldingModel.install(fragments, myRequest, getFoldingModelSettings());
myInitialScrollHelper.onRediff();
@@ -131,13 +131,6 @@ public class SimpleOnesideDiffViewer extends OnesideTextDiffViewer {
TextDiffType type = getSide().select(TextDiffType.DELETED, TextDiffType.INSERTED);
myHighlighters.addAll(DiffDrawUtil.createHighlighter(getEditor(), 0, getLineCount(document), type, false));
int startLine = 0;
int endLine = getLineCount(document);
if (startLine != endLine) {
myHighlighters.addAll(DiffDrawUtil.createLineMarker(getEditor(), startLine, endLine, type, false));
}
}
myInitialScrollHelper.onRediff();
@@ -123,7 +123,6 @@ public abstract class ThreesideDiffChangeBase {
boolean ignored = !resolved && getInnerFragments() != null;
boolean shouldHideWithoutLineNumbers = side == ThreeSide.BASE && !isChange(Side.LEFT) && isChange(Side.RIGHT);
myHighlighters.addAll(DiffDrawUtil.createHighlighter(editor, startLine, endLine, type, ignored, resolved, shouldHideWithoutLineNumbers));
myHighlighters.addAll(DiffDrawUtil.createLineMarker(editor, startLine, endLine, type, resolved));
}
protected void createInnerHighlighter(@NotNull ThreeSide side) {
@@ -242,14 +242,28 @@ public class DiffDividerDrawUtil {
}
public void paint(Graphics2D g, int width, boolean paintBorder, boolean curve) {
// we need this shift, because editor background highlight is painted in range "Y(line) - 1 .. Y(line + 1) - 1"
int startY1 = myStart1 - 1;
int endY1 = myEnd1 - 1;
int startY2 = myStart2 - 1;
int endY2 = myEnd2 - 1;
int startY1;
int endY1;
int startY2;
int endY2;
if (endY1 - startY1 < 2) endY1 = startY1 + 1;
if (endY2 - startY2 < 2) endY2 = startY2 + 1;
if (myEnd1 - myStart1 < 2) {
startY1 = myStart1 - 1;
endY1 = myStart1;
}
else {
startY1 = myStart1;
endY1 = myEnd1 - 1;
}
if (myEnd2 - myStart2 < 2) {
startY2 = myStart2 - 1;
endY2 = myStart2;
}
else {
startY2 = myStart2;
endY2 = myEnd2 - 1;
}
Stroke oldStroke = g.getStroke();
if (myResolved) {
@@ -21,6 +21,8 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.editor.colors.EditorColors;
import com.intellij.openapi.editor.colors.EditorColorsManager;
import com.intellij.openapi.editor.colors.EditorColorsScheme;
import com.intellij.openapi.editor.ex.EditorEx;
import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
import com.intellij.openapi.editor.markup.*;
import com.intellij.openapi.util.BooleanGetter;
import com.intellij.openapi.util.TextRange;
@@ -233,6 +235,34 @@ public class DiffDrawUtil {
};
}
@NotNull
private static LineMarkerRenderer createFoldingGutterLineRenderer(@NotNull final TextDiffType type,
@NotNull final SeparatorPlacement placement,
final boolean doubleLine,
final boolean resolved) {
return new LineMarkerRendererEx() {
@Override
public void paint(Editor editor, Graphics g, Rectangle r) {
EditorGutterComponentEx gutter = ((EditorEx)editor).getGutterComponentEx();
Graphics2D g2 = (Graphics2D)g;
int x1 = gutter.getWhitespaceSeparatorOffset();
int x2 = gutter.getWidth();
int y = r.y;
if (placement == SeparatorPlacement.BOTTOM) y += editor.getLineHeight();
drawChunkBorderLine(g2, x1, x2, y - 1, type.getColor(editor), doubleLine, resolved);
}
@NotNull
@Override
public Position getPosition() {
return Position.CUSTOM;
}
};
}
//
// Highlighters
//
@@ -248,20 +278,14 @@ public class DiffDrawUtil {
List<RangeHighlighter> list = new ArrayList<>();
if (!inserted.isEmpty() && !deleted.isEmpty()) {
list.addAll(createLineMarker(editor, deleted.start, TextDiffType.DELETED, SeparatorPlacement.TOP));
list.addAll(createHighlighter(editor, deleted.start, deleted.end, TextDiffType.DELETED, ignored));
list.addAll(createHighlighter(editor, inserted.start, inserted.end, TextDiffType.INSERTED, ignored));
list.addAll(createLineMarker(editor, inserted.end - 1, TextDiffType.INSERTED, SeparatorPlacement.BOTTOM));
}
else if (!inserted.isEmpty()) {
list.addAll(createLineMarker(editor, inserted.start, TextDiffType.INSERTED, SeparatorPlacement.TOP));
list.addAll(createHighlighter(editor, inserted.start, inserted.end, TextDiffType.INSERTED, ignored));
list.addAll(createLineMarker(editor, inserted.end - 1, TextDiffType.INSERTED, SeparatorPlacement.BOTTOM));
}
else if (!deleted.isEmpty()) {
list.addAll(createLineMarker(editor, deleted.start, TextDiffType.DELETED, SeparatorPlacement.TOP));
list.addAll(createHighlighter(editor, deleted.start, deleted.end, TextDiffType.DELETED, ignored));
list.addAll(createLineMarker(editor, deleted.end - 1, TextDiffType.DELETED, SeparatorPlacement.BOTTOM));
}
if (innerFragments != null) {
@@ -301,31 +325,20 @@ public class DiffDrawUtil {
}
@NotNull
public static List<RangeHighlighter> createLineMarker(@NotNull final Editor editor, int line1, int line2,
@NotNull final TextDiffType type, final boolean resolved) {
if (line1 == line2) {
if (line1 == 0) return Collections.emptyList();
return createLineMarker(editor, line1 - 1, type, SeparatorPlacement.BOTTOM, true, resolved);
}
else {
return ContainerUtil.concat(
createLineMarker(editor, line1, type, SeparatorPlacement.TOP, false, resolved),
createLineMarker(editor, line2 - 1, type, SeparatorPlacement.BOTTOM, false, resolved)
);
}
}
@NotNull
public static List<RangeHighlighter> createLineMarker(@NotNull Editor editor, int line, @NotNull final TextDiffType type,
@NotNull final SeparatorPlacement placement) {
return new LineMarkerBuilder(editor, line, placement).withType(type).doneDefaultRenderer();
public static List<RangeHighlighter> createLineMarker(@NotNull final Editor editor, int line, @NotNull final TextDiffType type) {
if (line == 0) return Collections.emptyList();
return createLineMarker(editor, line - 1, type, SeparatorPlacement.BOTTOM, false, false, true);
}
@NotNull
private static List<RangeHighlighter> createLineMarker(@NotNull final Editor editor, int line, @NotNull final TextDiffType type,
@NotNull final SeparatorPlacement placement,
final boolean doubleLine, final boolean resolved) {
return new LineMarkerBuilder(editor, line, placement).withType(type).withResolved(resolved).doneDefaultRenderer(doubleLine);
boolean doubleLine, boolean resolved, boolean paintFoldingOutline) {
LineMarkerBuilder builder = new LineMarkerBuilder(editor, line, placement)
.withType(type).withResolved(resolved)
.withDefaultRenderer(doubleLine);
if (paintFoldingOutline) builder.withDefaultGutterRenderer(doubleLine);
return builder.done();
}
@NotNull
@@ -386,6 +399,8 @@ public class DiffDrawUtil {
@NotNull
public List<RangeHighlighter> done() {
List<RangeHighlighter> highlighters = new ArrayList<>();
boolean isEmptyRange = startLine == endLine;
boolean isLastLine = endLine == getLineCount(editor.getDocument());
@@ -398,16 +413,31 @@ public class DiffDrawUtil {
RangeHighlighter highlighter = editor.getMarkupModel()
.addRangeHighlighter(start, end, DEFAULT_LAYER, attributes, HighlighterTargetArea.LINES_IN_RANGE);
highlighters.add(highlighter);
highlighter.setLineMarkerRenderer(new DiffLineMarkerRenderer(highlighter, type, ignored, resolved,
hideWithoutLineNumbers, isEmptyRange, isLastLine));
if (stripeAttributes == null) return Collections.singletonList(highlighter);
if (isEmptyRange) {
if (startLine == 0) {
highlighters.addAll(createLineMarker(editor, 0, type, SeparatorPlacement.TOP, true, resolved, false));
}
else {
highlighters.addAll(createLineMarker(editor, startLine - 1, type, SeparatorPlacement.BOTTOM, true, resolved, false));
}
}
else if (resolved) {
highlighters.addAll(createLineMarker(editor, startLine, type, SeparatorPlacement.TOP, false, resolved, false));
highlighters.addAll(createLineMarker(editor, endLine - 1, type, SeparatorPlacement.BOTTOM, false, resolved, false));
}
RangeHighlighter stripeHighlighter = editor.getMarkupModel()
.addRangeHighlighter(start, end, STRIPE_LAYER, stripeAttributes, HighlighterTargetArea.LINES_IN_RANGE);
if (stripeAttributes != null) {
RangeHighlighter stripeHighlighter = editor.getMarkupModel()
.addRangeHighlighter(start, end, STRIPE_LAYER, stripeAttributes, HighlighterTargetArea.LINES_IN_RANGE);
highlighters.add(stripeHighlighter);
}
return ContainerUtil.list(highlighter, stripeHighlighter);
return highlighters;
}
}
@@ -445,6 +475,7 @@ public class DiffDrawUtil {
private boolean resolved = false;
@Nullable private TextDiffType type;
@Nullable private LineSeparatorRenderer renderer;
@Nullable private LineMarkerRenderer gutterRenderer;
private LineMarkerBuilder(@NotNull Editor editor, int line, @NotNull SeparatorPlacement placement) {
this.editor = editor;
@@ -471,15 +502,17 @@ public class DiffDrawUtil {
}
@NotNull
public List<RangeHighlighter> doneDefaultRenderer() {
return doneDefaultRenderer(false);
public LineMarkerBuilder withDefaultRenderer(boolean doubleLine) {
assert type != null;
this.renderer = createDiffLineRenderer(editor, type, doubleLine, resolved);
return this;
}
@NotNull
public List<RangeHighlighter> doneDefaultRenderer(boolean doubleLine) {
public LineMarkerBuilder withDefaultGutterRenderer(boolean doubleLine) {
assert type != null;
this.renderer = createDiffLineRenderer(editor, type, doubleLine, resolved);
return done();
this.gutterRenderer = createFoldingGutterLineRenderer(type, placement, doubleLine, resolved);
return this;
}
@NotNull
@@ -493,6 +526,7 @@ public class DiffDrawUtil {
highlighter.setLineSeparatorPlacement(placement);
highlighter.setLineSeparatorRenderer(renderer);
highlighter.setLineMarkerRenderer(gutterRenderer);
if (type == null || resolved) return Collections.singletonList(highlighter);
@@ -24,7 +24,7 @@ import org.jetbrains.annotations.NotNull;
import java.awt.*;
public class DiffLineMarkerRenderer implements LineMarkerRendererEx {
class DiffLineMarkerRenderer implements LineMarkerRendererEx {
@NotNull private final RangeHighlighter myHighlighter;
@NotNull private final TextDiffType myDiffType;
private final boolean myIgnoredFoldingOutline;
@@ -101,10 +101,10 @@ public class DiffLineMarkerRenderer implements LineMarkerRendererEx {
if (!myResolved) {
g2.setColor(ignoredBackgroundColor ? myDiffType.getIgnoredColor(editor) : color);
g2.fillRect(x1, y1, x2 - x1, y2 - y1);
} else {
DiffDrawUtil.drawChunkBorderLine(g2, x1, x2, y1 - 1, color, false, myResolved);
DiffDrawUtil.drawChunkBorderLine(g2, x1, x2, y2 - 1, color, false, myResolved);
}
DiffDrawUtil.drawChunkBorderLine(g2, x1, x2, y1 - 1, color, false, myResolved);
DiffDrawUtil.drawChunkBorderLine(g2, x1, x2, y2 - 1, color, false, myResolved);
}
else {
// range is empty - insertion or deletion
@@ -127,7 +127,6 @@ class ApplyPatchChange {
boolean resolved = isRangeApplied();
myHighlighters.addAll(DiffDrawUtil.createHighlighter(editor, startLine, endLine, type, false, resolved, false));
myHighlighters.addAll(DiffDrawUtil.createLineMarker(editor, startLine, endLine, type, resolved));
}
private void createStatusHighlighter() {