From 27e3836c26d61419880be117e3a6131a034c3d44 Mon Sep 17 00:00:00 2001 From: Kevin Sawicki Date: Sat, 23 Apr 2011 10:25:28 -0700 Subject: Add diff formatter that generates a list of style ranges This class will be used for a general purpose diff viewer available as a tab in the commit viewer. Bug: 343000 Change-Id: Ic2eb3e178f5a049154bd5744da3010fa791a9933 Signed-off-by: Kevin Sawicki Signed-off-by: Chris Aniszczyk --- .../test/commit/DiffStyleRangeFormatterTest.java | 79 ++++++++ .../internal/commit/DiffStyleRangeFormatter.java | 208 +++++++++++++++++++++ 2 files changed, 287 insertions(+) create mode 100644 org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/commit/DiffStyleRangeFormatterTest.java create mode 100644 org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffStyleRangeFormatter.java diff --git a/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/commit/DiffStyleRangeFormatterTest.java b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/commit/DiffStyleRangeFormatterTest.java new file mode 100644 index 0000000000..64cc3ba8d2 --- /dev/null +++ b/org.eclipse.egit.ui.test/src/org/eclipse/egit/ui/test/commit/DiffStyleRangeFormatterTest.java @@ -0,0 +1,79 @@ +/******************************************************************************* + * Copyright (c) 2011 GitHub Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Kevin Sawicki (GitHub Inc.) - initial API and implementation + *******************************************************************************/ +package org.eclipse.egit.ui.test.commit; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import java.io.File; + +import org.eclipse.egit.core.Activator; +import org.eclipse.egit.ui.common.LocalRepositoryTestCase; +import org.eclipse.egit.ui.internal.commit.DiffStyleRangeFormatter; +import org.eclipse.egit.ui.internal.commit.DiffStyleRangeFormatter.DiffStyleRange; +import org.eclipse.jface.text.Document; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jgit.lib.Constants; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.jgit.revwalk.RevCommit; +import org.eclipse.jgit.revwalk.RevWalk; +import org.junit.BeforeClass; +import org.junit.Test; + +/** + * Unit tests for {@link DiffStyleRangeFormatter} + */ +public class DiffStyleRangeFormatterTest extends LocalRepositoryTestCase { + + private static Repository repository; + + private static RevCommit commit; + + @BeforeClass + public static void setup() throws Exception { + File repoFile = createProjectAndCommitToRepository(); + assertNotNull(repoFile); + repository = Activator.getDefault().getRepositoryCache() + .lookupRepository(repoFile); + assertNotNull(repository); + + RevWalk walk = new RevWalk(repository); + try { + commit = walk.parseCommit(repository.resolve(Constants.HEAD)); + assertNotNull(commit); + walk.parseBody(commit.getParent(0)); + } finally { + walk.release(); + } + } + + @Test + public void testRanges() throws Exception { + IDocument document = new Document(); + DiffStyleRangeFormatter formatter = new DiffStyleRangeFormatter( + document); + formatter.setRepository(repository); + formatter.format(commit.getTree(), commit.getParent(0).getTree()); + assertTrue(document.getLength() > 0); + DiffStyleRange[] ranges = formatter.getRanges(); + assertNotNull(ranges); + assertTrue(ranges.length > 0); + for (DiffStyleRange range : ranges) { + assertNotNull(range); + assertNotNull(range.diffType); + assertTrue(range.start >= 0); + assertTrue(range.length >= 0); + assertTrue(range.start < document.getLength()); + } + + } + +} diff --git a/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffStyleRangeFormatter.java b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffStyleRangeFormatter.java new file mode 100644 index 0000000000..98559e1e86 --- /dev/null +++ b/org.eclipse.egit.ui/src/org/eclipse/egit/ui/internal/commit/DiffStyleRangeFormatter.java @@ -0,0 +1,208 @@ +/******************************************************************************* + * Copyright (c) 2011 GitHub Inc. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Kevin Sawicki (GitHub Inc.) - initial API and implementation + *******************************************************************************/ +package org.eclipse.egit.ui.internal.commit; + +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.List; + +import org.eclipse.egit.ui.internal.CompareUtils; +import org.eclipse.egit.ui.internal.commit.DiffStyleRangeFormatter.DiffStyleRange.Type; +import org.eclipse.egit.ui.internal.history.FileDiff; +import org.eclipse.jface.text.BadLocationException; +import org.eclipse.jface.text.IDocument; +import org.eclipse.jgit.diff.DiffFormatter; +import org.eclipse.jgit.diff.RawText; +import org.eclipse.jgit.lib.Repository; +import org.eclipse.swt.custom.StyleRange; +import org.eclipse.swt.graphics.Color; + +/** + * Diff style range formatter class that builds up a list of + * {@link DiffStyleRange} instances as each {@link FileDiff} is being written to + * an {@link IDocument}. + */ +public class DiffStyleRangeFormatter extends DiffFormatter { + + /** + * Diff style range + */ + public static class DiffStyleRange extends StyleRange { + + /** + * Diff type + */ + public enum Type { + + /** + * Added line + */ + ADD, + + /** + * Removed line + */ + REMOVE, + + /** + * Hunk line + */ + HUNK, + + /** + * Other line + */ + OTHER, + + } + + /** + * Diff type + */ + public Type diffType = Type.OTHER; + + /** + * Line background + */ + public Color lineBackground = null; + + public boolean similarTo(StyleRange style) { + return super.similarTo(style) && style instanceof DiffStyleRange + && diffType == ((DiffStyleRange) style).diffType; + } + } + + private static class DocumentOutputStream extends OutputStream { + + private String charset; + + private IDocument document; + + private int offset; + + public DocumentOutputStream(IDocument document, int offset) { + this.document = document; + this.offset = offset; + } + + private void write(String content) throws IOException { + try { + this.document.replace(this.offset, 0, content); + this.offset += content.length(); + } catch (BadLocationException e) { + throw new IOException(e); + } + } + + public void write(byte[] b, int off, int len) throws IOException { + if (charset == null) + write(new String(b, off, len)); + else + write(new String(b, off, len, charset)); + } + + public void write(byte[] b) throws IOException { + write(b, 0, b.length); + } + + public void write(int b) throws IOException { + write(new byte[] { (byte) b }); + } + } + + private DocumentOutputStream stream; + + private List ranges = new ArrayList(); + + /** + * @param document + * @param offset + */ + public DiffStyleRangeFormatter(IDocument document, int offset) { + super(new DocumentOutputStream(document, offset)); + this.stream = (DocumentOutputStream) getOutputStream(); + } + + /** + * @param document + */ + public DiffStyleRangeFormatter(IDocument document) { + this(document, document.getLength()); + } + + /** + * Write diff + * + * @param repository + * @param diff + * @return this formatter + * @throws IOException + */ + public DiffStyleRangeFormatter write(Repository repository, FileDiff diff) + throws IOException { + this.stream.charset = CompareUtils.getResourceEncoding(repository, + diff.getPath()); + diff.outputDiff(null, repository, this, true); + flush(); + return this; + } + + /** + * Get diff style ranges + * + * @return non-null but possibly empty array + */ + public DiffStyleRange[] getRanges() { + return this.ranges.toArray(new DiffStyleRange[this.ranges.size()]); + } + + /** + * Create and add diff style range + * + * @param type + * @return added range + */ + protected DiffStyleRange addRange(Type type) { + DiffStyleRange range = new DiffStyleRange(); + range.start = stream.offset; + range.diffType = type; + ranges.add(range); + return range; + } + + /** + * @see org.eclipse.jgit.diff.DiffFormatter#writeHunkHeader(int, int, int, + * int) + */ + protected void writeHunkHeader(int aStartLine, int aEndLine, + int bStartLine, int bEndLine) throws IOException { + DiffStyleRange range = addRange(Type.HUNK); + super.writeHunkHeader(aStartLine, aEndLine, bStartLine, bEndLine); + range.length = stream.offset - range.start; + } + + /** + * @see org.eclipse.jgit.diff.DiffFormatter#writeLine(char, + * org.eclipse.jgit.diff.RawText, int) + */ + protected void writeLine(char prefix, RawText text, int cur) + throws IOException { + if (prefix == ' ') + super.writeLine(prefix, text, cur); + else { + DiffStyleRange range = addRange(prefix == '+' ? Type.ADD + : Type.REMOVE); + super.writeLine(prefix, text, cur); + range.length = stream.offset - range.start; + } + } +} -- cgit v1.2.3