{"thread":{"id":"19153","subject":"[JGIT PATCH 0/6] Diff processing utilities","startedAt":"2009-05-02T02:08:41Z","lastAt":"2009-05-04T15:10:00Z","messageCount":15,"participants":["Shawn O. Pearce","Robin Rosenberg","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"112861","messageId":"1241230127-28279-1-git-send-email-spearce@spearce.org","threadId":"19153","inReplyTo":null,"subject":"[JGIT PATCH 0/6] Diff processing utilities","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-02T02:08:41Z","receivedAt":"2009-05-02T02:08:41Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Back in late 2008 Dscho started writing some basic diff routines\nfor JGit.  That work got partially shelved when he had to move onto\nmore important day-job topics.  This series is starting to revive\nsome portions of his work, and bring it into JGit.\n\nIn particular I want at least this much merged, so I can use it\nin Gerrit Code Review to massage an existing patch file before I\ndisplay it.  Currently most of that logic is within Gerrit, and\nI'd much rather push it down into JGit where anyone can reuse it.\n\nTo be clear, this series *does not* contain a way to create a diff.\nDscho wrote much more code which is not yet ready for inclusion.\n\nAfter applying this series we have an EditList describing what\nhappened in an existing patch we parsed with the existing Patch\nclass, and a DiffFormatter which can be used to reflow a patch\nscript if the repository has both the pre and post image objects.\n\nThe formatter part is really only useful if the repository created\nthe patch script, or received the objects over a git native object\ntransport, like Gerrit Code Review does with SSH.\n\nDscho, can you give us yea-or-nay for SBO lines for the patches\nI've attributed to you?\n\n\nJohannes E. Schindelin (3):\n  Add diff.Edit to describe an edit region within a file\n  Add diff.RawText to index a file content for later compares\n  Add diff.DiffFormatter to create Git style unified patch scripts\n\nShawn O. Pearce (3):\n  Add set to IntList\n  Add diff.EditList to provide for a list of Edit instances\n  Teach FileHeader, HunkHeader how to create an EditList\n\n .../spearce/jgit/patch/testEditList_Types.patch    |   24 +++\n .../tst/org/spearce/jgit/diff/EditListTest.java    |  121 +++++++++++++\n .../tst/org/spearce/jgit/diff/EditTest.java        |  139 ++++++++++++++\n .../tst/org/spearce/jgit/diff/RawTextTest.java     |   93 ++++++++++\n .../tst/org/spearce/jgit/patch/EditListTest.java   |   95 ++++++++++\n .../tst/org/spearce/jgit/util/IntListTest.java     |   21 +++\n .../src/org/spearce/jgit/diff/DiffFormatter.java   |  187 +++++++++++++++++++\n .../src/org/spearce/jgit/diff/Edit.java            |  189 ++++++++++++++++++++\n .../src/org/spearce/jgit/diff/EditList.java        |   93 ++++++++++\n .../src/org/spearce/jgit/diff/RawText.java         |  172 ++++++++++++++++++\n .../src/org/spearce/jgit/diff/Sequence.java        |   78 ++++++++\n .../src/org/spearce/jgit/patch/FileHeader.java     |    9 +\n .../src/org/spearce/jgit/patch/HunkHeader.java     |   48 +++++\n .../src/org/spearce/jgit/util/IntList.java         |   17 ++\n 14 files changed, 1286 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/patch/testEditList_Types.patch\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditListTest.java\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditTest.java\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/diff/RawTextTest.java\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/EditListTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/Edit.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/EditList.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/Sequence.java\n"},{"id":"112862","messageId":"1241230127-28279-2-git-send-email-spearce@spearce.org","threadId":"19153","inReplyTo":"1241230127-28279-1-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 1/6] Add set to IntList","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-02T02:08:42Z","receivedAt":"2009-05-02T02:08:42Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Some applications may wish to modify an int list.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../tst/org/spearce/jgit/util/IntListTest.java     |   21 ++++++++++++++++++++\n .../src/org/spearce/jgit/util/IntList.java         |   17 ++++++++++++++++\n 2 files changed, 38 insertions(+), 0 deletions(-)\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java\nindex c470d55..ce0d7af 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java\n@@ -144,6 +144,27 @@ public void testClear() {\n \t\t}\n \t}\n \n+\tpublic void testSet() {\n+\t\tfinal IntList i = new IntList();\n+\t\ti.add(1);\n+\t\tassertEquals(1, i.size());\n+\t\tassertEquals(1, i.get(0));\n+\t\t\n+\t\ti.set(0, 5);\n+\t\tassertEquals(5, i.get(0));\n+\t\t\n+\t\ttry {\n+\t\t\ti.set(5, 5);\n+\t\t\tfail(\"accepted set of 5 beyond end of list\");\n+\t\t} catch (ArrayIndexOutOfBoundsException e){\n+\t\t\tassertTrue(true);\n+\t\t}\n+\n+\t\ti.set(1, 2);\n+\t\tassertEquals(2, i.size());\n+\t\tassertEquals(2, i.get(1));\n+\t}\n+\n \tpublic void testToString() {\n \t\tfinal IntList i = new IntList();\n \t\ti.add(1);\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java b/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java\nindex 0a84793..9d86a5c 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java\n@@ -94,6 +94,23 @@ public void add(final int n) {\n \t}\n \n \t/**\n+\t * Assign an entry in the list.\n+\t * \n+\t * @param index\n+\t *            index to set, must be in the range [0, {@link #size()}).\n+\t * @param n\n+\t *            value to store at the position.\n+\t */\n+\tpublic void set(final int index, final int n) {\n+\t\tif (count < index)\n+\t\t\tthrow new ArrayIndexOutOfBoundsException(index);\n+\t\telse if (count == index)\n+\t\t\tadd(n);\n+\t\telse\n+\t\t\tentries[index] = n;\n+\t}\n+\t\n+\t/**\n \t * Pad the list with entries.\n \t *\n \t * @param toIndex\n-- \n1.6.3.rc3.212.g8c698\n"},{"id":"112863","messageId":"1241230127-28279-3-git-send-email-spearce@spearce.org","threadId":"19153","inReplyTo":"1241230127-28279-2-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 2/6] Add diff.Edit to describe an edit region within a file","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-02T02:08:43Z","receivedAt":"2009-05-02T02:08:43Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"From: Johannes E. Schindelin <johannes.schindelin@gmx.de>\n\nThis type represents a difference region detected between two files.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../tst/org/spearce/jgit/diff/EditTest.java        |  139 ++++++++++++++\n .../src/org/spearce/jgit/diff/Edit.java            |  189 ++++++++++++++++++++\n 2 files changed, 328 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/Edit.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditTest.java\nnew file mode 100644\nindex 0000000..8f9b0e3\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditTest.java\n@@ -0,0 +1,139 @@\n+/*\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import junit.framework.TestCase;\n+\n+public class EditTest extends TestCase {\n+\tpublic void testCreate() {\n+\t\tfinal Edit e = new Edit(1, 2, 3, 4);\n+\t\tassertEquals(1, e.getBeginA());\n+\t\tassertEquals(2, e.getEndA());\n+\t\tassertEquals(3, e.getBeginB());\n+\t\tassertEquals(4, e.getEndB());\n+\t}\n+\n+\tpublic void testCreateEmpty() {\n+\t\tfinal Edit e = new Edit(1, 3);\n+\t\tassertEquals(1, e.getBeginA());\n+\t\tassertEquals(1, e.getEndA());\n+\t\tassertEquals(3, e.getBeginB());\n+\t\tassertEquals(3, e.getEndB());\n+\t}\n+\n+\tpublic void testSwap() {\n+\t\tfinal Edit e = new Edit(1, 2, 3, 4);\n+\t\te.swap();\n+\t\tassertEquals(3, e.getBeginA());\n+\t\tassertEquals(4, e.getEndA());\n+\t\tassertEquals(1, e.getBeginB());\n+\t\tassertEquals(2, e.getEndB());\n+\t}\n+\n+\tpublic void testType_Insert() {\n+\t\tfinal Edit e = new Edit(1, 1, 1, 2);\n+\t\tassertSame(Edit.Type.INSERT, e.getType());\n+\t}\n+\n+\tpublic void testType_Delete() {\n+\t\tfinal Edit e = new Edit(1, 2, 1, 1);\n+\t\tassertSame(Edit.Type.DELETE, e.getType());\n+\t}\n+\n+\tpublic void testType_Replace() {\n+\t\tfinal Edit e = new Edit(1, 2, 1, 4);\n+\t\tassertSame(Edit.Type.REPLACE, e.getType());\n+\t}\n+\n+\tpublic void testType_Empty() {\n+\t\tassertSame(Edit.Type.EMPTY, new Edit(1, 1, 2, 2).getType());\n+\t\tassertSame(Edit.Type.EMPTY, new Edit(1, 2).getType());\n+\t}\n+\n+\tpublic void testToString() {\n+\t\tfinal Edit e = new Edit(1, 2, 1, 4);\n+\t\tassertEquals(\"REPLACE(1-2,1-4)\", e.toString());\n+\t}\n+\n+\tpublic void testEquals1() {\n+\t\tfinal Edit e1 = new Edit(1, 2, 3, 4);\n+\t\tfinal Edit e2 = new Edit(1, 2, 3, 4);\n+\n+\t\tassertTrue(e1.equals(e1));\n+\t\tassertTrue(e1.equals(e2));\n+\t\tassertTrue(e2.equals(e1));\n+\t\tassertEquals(e1.hashCode(), e2.hashCode());\n+\t\tassertFalse(e1.equals(\"\"));\n+\t}\n+\n+\tpublic void testNotEquals1() {\n+\t\tassertFalse(new Edit(1, 2, 3, 4).equals(new Edit(0, 2, 3, 4)));\n+\t}\n+\n+\tpublic void testNotEquals2() {\n+\t\tassertFalse(new Edit(1, 2, 3, 4).equals(new Edit(1, 0, 3, 4)));\n+\t}\n+\n+\tpublic void testNotEquals3() {\n+\t\tassertFalse(new Edit(1, 2, 3, 4).equals(new Edit(1, 2, 0, 4)));\n+\t}\n+\n+\tpublic void testNotEquals4() {\n+\t\tassertFalse(new Edit(1, 2, 3, 4).equals(new Edit(1, 2, 3, 0)));\n+\t}\n+\n+\tpublic void testExtendA() {\n+\t\tfinal Edit e = new Edit(1, 2, 1, 1);\n+\n+\t\te.extendA();\n+\t\tassertEquals(new Edit(1, 3, 1, 1), e);\n+\n+\t\te.extendA();\n+\t\tassertEquals(new Edit(1, 4, 1, 1), e);\n+\t}\n+\n+\tpublic void testExtendB() {\n+\t\tfinal Edit e = new Edit(1, 2, 1, 1);\n+\n+\t\te.extendB();\n+\t\tassertEquals(new Edit(1, 2, 1, 2), e);\n+\n+\t\te.extendB();\n+\t\tassertEquals(new Edit(1, 2, 1, 3), e);\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/Edit.java b/org.spearce.jgit/src/org/spearce/jgit/diff/Edit.java\nnew file mode 100644\nindex 0000000..460e2c4\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/Edit.java\n@@ -0,0 +1,189 @@\n+/*\n+ * Copyright (C) 2008, Johannes E. Schindelin <johannes.schindelin@gmx.de>\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+/**\n+ * A modified region detected between two versions of roughly the same content.\n+ * <p>\n+ * An edit covers the modified region only. It does not cover a common region.\n+ * <p>\n+ * Regions should be specified using 0 based notation, so add 1 to the start and\n+ * end marks for line numbers in a file.\n+ * <p>\n+ * An edit where <code>beginA == endA && beginB < endB</code> is an insert edit,\n+ * that is sequence B inserted the elements in region\n+ * <code>[beginB, endB)</code> at <code>beginA</code>.\n+ * <p>\n+ * An edit where <code>beginA < endA && beginB == endB</code> is a delete edit,\n+ * that is sequence B has removed the elements between\n+ * <code>[beginA, endA)</code>.\n+ * <p>\n+ * An edit where <code>beginA < endA && beginB < endB</code> is a replace edit,\n+ * that is sequence B has replaced the range of elements between\n+ * <code>[beginA, endA)</code> with those found in <code>[beginB, endB)</code>.\n+ */\n+public class Edit {\n+\t/** Type of edit */\n+\tpublic static enum Type {\n+\t\t/** Sequence B has inserted the region. */\n+\t\tINSERT,\n+\n+\t\t/** Sequence B has removed the region. */\n+\t\tDELETE,\n+\n+\t\t/** Sequence B has replaced the region with different content. */\n+\t\tREPLACE,\n+\n+\t\t/** Sequence A and B have zero length, describing nothing. */\n+\t\tEMPTY;\n+\t}\n+\n+\tint beginA;\n+\n+\tint endA;\n+\n+\tint beginB;\n+\n+\tint endB;\n+\n+\t/**\n+\t * Create a new empty edit.\n+\t * \n+\t * @param as\n+\t *            beginA: start and end of region in sequence A; 0 based.\n+\t * @param bs\n+\t *            beginB: start and end of region in sequence B; 0 based.\n+\t */\n+\tpublic Edit(final int as, final int bs) {\n+\t\tthis(as, as, bs, bs);\n+\t}\n+\n+\t/**\n+\t * Create a new edit.\n+\t * \n+\t * @param as\n+\t *            beginA: start of region in sequence A; 0 based.\n+\t * @param ae\n+\t *            endA: end of region in sequence A; must be >= as.\n+\t * @param bs\n+\t *            beginB: start of region in sequence B; 0 based.\n+\t * @param be\n+\t *            endB: end of region in sequence B; must be >= bs.\n+\t */\n+\tpublic Edit(final int as, final int ae, final int bs, final int be) {\n+\t\tbeginA = as;\n+\t\tendA = ae;\n+\n+\t\tbeginB = bs;\n+\t\tendB = be;\n+\t}\n+\n+\t/** @return the type of this region */\n+\tpublic final Type getType() {\n+\t\tif (beginA == endA && beginB < endB)\n+\t\t\treturn Type.INSERT;\n+\t\tif (beginA < endA && beginB == endB)\n+\t\t\treturn Type.DELETE;\n+\t\tif (beginA == endA && beginB == endB)\n+\t\t\treturn Type.EMPTY;\n+\t\treturn Type.REPLACE;\n+\t}\n+\n+\t/** @return start point in sequence A. */\n+\tpublic final int getBeginA() {\n+\t\treturn beginA;\n+\t}\n+\n+\t/** @return end point in sequence A. */\n+\tpublic final int getEndA() {\n+\t\treturn endA;\n+\t}\n+\n+\t/** @return start point in sequence B. */\n+\tpublic final int getBeginB() {\n+\t\treturn beginB;\n+\t}\n+\n+\t/** @return end point in sequence B. */\n+\tpublic final int getEndB() {\n+\t\treturn endB;\n+\t}\n+\n+\t/** Increase {@link #getEndA()} by 1. */\n+\tpublic void extendA() {\n+\t\tendA++;\n+\t}\n+\n+\t/** Increase {@link #getEndB()} by 1. */\n+\tpublic void extendB() {\n+\t\tendB++;\n+\t}\n+\n+\t/** Swap A and B, so the edit goes the other direction. */\n+\tpublic void swap() {\n+\t\tfinal int sBegin = beginA;\n+\t\tfinal int sEnd = endA;\n+\n+\t\tbeginA = beginB;\n+\t\tendA = endB;\n+\n+\t\tbeginB = sBegin;\n+\t\tendB = sEnd;\n+\t}\n+\n+\t@Override\n+\tpublic int hashCode() {\n+\t\treturn beginA ^ endA;\n+\t}\n+\n+\t@Override\n+\tpublic boolean equals(final Object o) {\n+\t\tif (o instanceof Edit) {\n+\t\t\tfinal Edit e = (Edit) o;\n+\t\t\treturn this.beginA == e.beginA && this.endA == e.endA\n+\t\t\t\t\t&& this.beginB == e.beginB && this.endB == e.endB;\n+\t\t}\n+\t\treturn false;\n+\t}\n+\n+\t@Override\n+\tpublic String toString() {\n+\t\tfinal Type t = getType();\n+\t\treturn t + \"(\" + beginA + \"-\" + endA + \",\" + beginB + \"-\" + endB + \")\";\n+\t}\n+}\n-- \n1.6.3.rc3.212.g8c698\n"},{"id":"112864","messageId":"1241230127-28279-4-git-send-email-spearce@spearce.org","threadId":"19153","inReplyTo":"1241230127-28279-3-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 3/6] Add diff.EditList to provide for a list of Edit instances","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-02T02:08:44Z","receivedAt":"2009-05-02T02:08:44Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Often a file difference involves more than one modified region, in\nwhich case we need more than one Edit instance to describe the full\nchange that was made.\n\nList<Edit> could be used with any generic List implementation, but\nwe may want to offer additional API functionality that is Edit list\nspecific, so I'm creating a specialized List implementation for it.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../tst/org/spearce/jgit/diff/EditListTest.java    |  121 ++++++++++++++++++++\n .../src/org/spearce/jgit/diff/EditList.java        |   93 +++++++++++++++\n 2 files changed, 214 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditListTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/EditList.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditListTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditListTest.java\nnew file mode 100644\nindex 0000000..54d5007\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/EditListTest.java\n@@ -0,0 +1,121 @@\n+/*\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import java.util.Iterator;\n+\n+import junit.framework.TestCase;\n+\n+public class EditListTest extends TestCase {\n+\tpublic void testEmpty() {\n+\t\tfinal EditList l = new EditList();\n+\t\tassertEquals(0, l.size());\n+\t\tassertTrue(l.isEmpty());\n+\t\tassertEquals(\"EditList[]\", l.toString());\n+\n+\t\tassertTrue(l.equals(l));\n+\t\tassertTrue(l.equals(new EditList()));\n+\t\tassertFalse(l.equals(\"\"));\n+\t\tassertEquals(l.hashCode(), new EditList().hashCode());\n+\t}\n+\n+\tpublic void testAddOne() {\n+\t\tfinal Edit e = new Edit(1, 2, 1, 1);\n+\t\tfinal EditList l = new EditList();\n+\t\tl.add(e);\n+\t\tassertEquals(1, l.size());\n+\t\tassertFalse(l.isEmpty());\n+\t\tassertSame(e, l.get(0));\n+\t\tassertSame(e, l.iterator().next());\n+\n+\t\tassertTrue(l.equals(l));\n+\t\tassertFalse(l.equals(new EditList()));\n+\n+\t\tfinal EditList l2 = new EditList();\n+\t\tl2.add(e);\n+\t\tassertTrue(l.equals(l2));\n+\t\tassertTrue(l2.equals(l));\n+\t\tassertEquals(l.hashCode(), l2.hashCode());\n+\t}\n+\n+\tpublic void testAddTwo() {\n+\t\tfinal Edit e1 = new Edit(1, 2, 1, 1);\n+\t\tfinal Edit e2 = new Edit(8, 8, 8, 12);\n+\t\tfinal EditList l = new EditList();\n+\t\tl.add(e1);\n+\t\tl.add(e2);\n+\t\tassertEquals(2, l.size());\n+\t\tassertSame(e1, l.get(0));\n+\t\tassertSame(e2, l.get(1));\n+\n+\t\tfinal Iterator<Edit> i = l.iterator();\n+\t\tassertSame(e1, i.next());\n+\t\tassertSame(e2, i.next());\n+\n+\t\tassertTrue(l.equals(l));\n+\t\tassertFalse(l.equals(new EditList()));\n+\n+\t\tfinal EditList l2 = new EditList();\n+\t\tl2.add(e1);\n+\t\tl2.add(e2);\n+\t\tassertTrue(l.equals(l2));\n+\t\tassertTrue(l2.equals(l));\n+\t\tassertEquals(l.hashCode(), l2.hashCode());\n+\t}\n+\n+\tpublic void testSet() {\n+\t\tfinal Edit e1 = new Edit(1, 2, 1, 1);\n+\t\tfinal Edit e2 = new Edit(3, 4, 3, 3);\n+\t\tfinal EditList l = new EditList();\n+\t\tl.add(e1);\n+\t\tassertSame(e1, l.get(0));\n+\t\tassertSame(e1, l.set(0, e2));\n+\t\tassertSame(e2, l.get(0));\n+\t}\n+\n+\tpublic void testRemove() {\n+\t\tfinal Edit e1 = new Edit(1, 2, 1, 1);\n+\t\tfinal Edit e2 = new Edit(8, 8, 8, 12);\n+\t\tfinal EditList l = new EditList();\n+\t\tl.add(e1);\n+\t\tl.add(e2);\n+\t\tl.remove(e1);\n+\t\tassertEquals(1, l.size());\n+\t\tassertSame(e2, l.get(0));\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/EditList.java b/org.spearce.jgit/src/org/spearce/jgit/diff/EditList.java\nnew file mode 100644\nindex 0000000..0ccf366\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/EditList.java\n@@ -0,0 +1,93 @@\n+/*\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import java.util.AbstractList;\n+import java.util.ArrayList;\n+\n+/** Specialized list of {@link Edit}s in a document. */\n+public class EditList extends AbstractList<Edit> {\n+\tprivate final ArrayList<Edit> container;\n+\n+\t/** Create a new, empty edit list. */\n+\tpublic EditList() {\n+\t\tcontainer = new ArrayList<Edit>();\n+\t}\n+\n+\t@Override\n+\tpublic int size() {\n+\t\treturn container.size();\n+\t}\n+\n+\t@Override\n+\tpublic Edit get(final int index) {\n+\t\treturn container.get(index);\n+\t}\n+\n+\t@Override\n+\tpublic Edit set(final int index, final Edit element) {\n+\t\treturn container.set(index, element);\n+\t}\n+\n+\t@Override\n+\tpublic void add(final int index, final Edit element) {\n+\t\tcontainer.add(index, element);\n+\t}\n+\n+\t@Override\n+\tpublic Edit remove(final int index) {\n+\t\treturn container.remove(index);\n+\t}\n+\n+\t@Override\n+\tpublic int hashCode() {\n+\t\treturn container.hashCode();\n+\t}\n+\n+\t@Override\n+\tpublic boolean equals(final Object o) {\n+\t\tif (o instanceof EditList)\n+\t\t\treturn container.equals(((EditList) o).container);\n+\t\treturn false;\n+\t}\n+\n+\t@Override\n+\tpublic String toString() {\n+\t\treturn \"EditList\" + container.toString();\n+\t}\n+}\n-- \n1.6.3.rc3.212.g8c698\n"},{"id":"112866","messageId":"1241230127-28279-5-git-send-email-spearce@spearce.org","threadId":"19153","inReplyTo":"1241230127-28279-4-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 4/6] Add diff.RawText to index a file content for later compares","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-02T02:08:45Z","receivedAt":"2009-05-02T02:08:45Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"From: Johannes E. Schindelin <johannes.schindelin@gmx.de>\n\nThe RawText class converts a byte[] into an indexed map of file\nlines, assuming the source content is a UNIX formatted text file.\nThis fits in line with Git's usage of libxdiff, where typically\nthe file content is treated as a UNIX formatted text file, unless\nbinary content was previously detected in the file stream.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../tst/org/spearce/jgit/diff/RawTextTest.java     |   93 +++++++++++\n .../src/org/spearce/jgit/diff/RawText.java         |  172 ++++++++++++++++++++\n .../src/org/spearce/jgit/diff/Sequence.java        |   78 +++++++++\n 3 files changed, 343 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/diff/RawTextTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/Sequence.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/diff/RawTextTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/RawTextTest.java\nnew file mode 100644\nindex 0000000..a7c621e\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/RawTextTest.java\n@@ -0,0 +1,93 @@\n+/*\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import java.io.ByteArrayOutputStream;\n+import java.io.IOException;\n+\n+import junit.framework.TestCase;\n+\n+import org.spearce.jgit.lib.Constants;\n+import org.spearce.jgit.util.RawParseUtils;\n+\n+public class RawTextTest extends TestCase {\n+\tpublic void testEmpty() {\n+\t\tfinal RawText r = new RawText(new byte[0]);\n+\t\tassertEquals(0, r.size());\n+\t}\n+\n+\tpublic void testEquals() {\n+\t\tfinal RawText a = new RawText(Constants.encodeASCII(\"foo-a\\nfoo-b\\n\"));\n+\t\tfinal RawText b = new RawText(Constants.encodeASCII(\"foo-b\\nfoo-c\\n\"));\n+\n+\t\tassertEquals(2, a.size());\n+\t\tassertEquals(2, b.size());\n+\n+\t\t// foo-a != foo-b\n+\t\tassertFalse(a.equals(0, b, 0));\n+\t\tassertFalse(b.equals(0, a, 0));\n+\n+\t\t// foo-b == foo-b\n+\t\tassertTrue(a.equals(1, b, 0));\n+\t\tassertTrue(b.equals(0, a, 1));\n+\t}\n+\n+\tpublic void testWriteLine1() throws IOException {\n+\t\tfinal RawText a = new RawText(Constants.encodeASCII(\"foo-a\\nfoo-b\\n\"));\n+\t\tfinal ByteArrayOutputStream o = new ByteArrayOutputStream();\n+\t\ta.writeLine(o, 0);\n+\t\tfinal byte[] r = o.toByteArray();\n+\t\tassertEquals(\"foo-a\", RawParseUtils.decode(r));\n+\t}\n+\n+\tpublic void testWriteLine2() throws IOException {\n+\t\tfinal RawText a = new RawText(Constants.encodeASCII(\"foo-a\\nfoo-b\"));\n+\t\tfinal ByteArrayOutputStream o = new ByteArrayOutputStream();\n+\t\ta.writeLine(o, 1);\n+\t\tfinal byte[] r = o.toByteArray();\n+\t\tassertEquals(\"foo-b\", RawParseUtils.decode(r));\n+\t}\n+\n+\tpublic void testWriteLine3() throws IOException {\n+\t\tfinal RawText a = new RawText(Constants.encodeASCII(\"a\\n\\nb\\n\"));\n+\t\tfinal ByteArrayOutputStream o = new ByteArrayOutputStream();\n+\t\ta.writeLine(o, 1);\n+\t\tfinal byte[] r = o.toByteArray();\n+\t\tassertEquals(\"\", RawParseUtils.decode(r));\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java b/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\nnew file mode 100644\nindex 0000000..1d10082\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\n@@ -0,0 +1,172 @@\n+/*\n+ * Copyright (C) 2008, Johannes E. Schindelin <johannes.schindelin@gmx.de>\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import java.io.IOException;\n+import java.io.OutputStream;\n+\n+import org.spearce.jgit.util.IntList;\n+import org.spearce.jgit.util.RawParseUtils;\n+\n+/**\n+ * A Sequence supporting UNIX formatted text in byte[] format.\n+ * <p>\n+ * Elements of the sequence are the lines of the file, as delimited by the UNIX\n+ * newline character ('\\n'). The file content is treated as 8 bit binary text,\n+ * with no assumptions or requirements on character encoding.\n+ * <p>\n+ * Note that the first line of the file is element 0, as defined by the Sequence\n+ * interface API. Traditionally in a text editor a patch file the first line is\n+ * line number 1. Callers may need to subtract 1 prior to invoking methods if\n+ * they are converting from \"line number\" to \"element index\".\n+ */\n+public class RawText implements Sequence {\n+\t/** The file content for this sequence. */\n+\tprotected final byte[] content;\n+\n+\t/** Map of line number to starting position within {@link #content}. */\n+\tprotected final IntList lines;\n+\n+\t/** Hash code for each line, for fast equality elimination. */\n+\tprotected final IntList hashes;\n+\n+\t/**\n+\t * Create a new sequence from an existing content byte array.\n+\t * <p>\n+\t * The entire array (indexes 0 through length-1) is used as the content.\n+\t * \n+\t * @param input\n+\t *            the content array. The array is never modified, so passing\n+\t *            through cached arrays is safe.\n+\t */\n+\tpublic RawText(final byte[] input) {\n+\t\tcontent = input;\n+\t\tlines = RawParseUtils.lineMap(content, 0, content.length);\n+\t\thashes = computeHashes();\n+\t}\n+\n+\tpublic int size() {\n+\t\t// The line map is always 2 entries larger than the number of lines in\n+\t\t// the file. Index 0 is padded out/unused. The last index is the total\n+\t\t// length of the buffer, and acts as a sentinel.\n+\t\t//\n+\t\treturn lines.size() - 2;\n+\t}\n+\n+\tpublic boolean equals(final int i, final Sequence other, final int j) {\n+\t\treturn equals(this, i + 1, (RawText) other, j + 1);\n+\t}\n+\n+\tprivate static boolean equals(final RawText a, final int ai,\n+\t\t\tfinal RawText b, final int bi) {\n+\t\tif (a.hashes.get(ai) != b.hashes.get(bi))\n+\t\t\treturn false;\n+\n+\t\tint as = a.lines.get(ai);\n+\t\tint bs = b.lines.get(bi);\n+\t\tfinal int ae = a.lines.get(ai + 1);\n+\t\tfinal int be = b.lines.get(bi + 1);\n+\n+\t\tif (ae - as != be - bs)\n+\t\t\treturn false;\n+\n+\t\twhile (as < ae) {\n+\t\t\tif (a.content[as++] != b.content[bs++])\n+\t\t\t\treturn false;\n+\t\t}\n+\t\treturn true;\n+\t}\n+\n+\t/**\n+\t * Write a specific line to the output stream, without its trailing LF.\n+\t * <p>\n+\t * The specified line is copied as-is, with no character encoding\n+\t * translation performed.\n+\t * <p>\n+\t * If the specified line ends with an LF ('\\n'), the LF is <b>not</b>\n+\t * copied. It is up to the caller to write the LF, if desired, between\n+\t * output lines.\n+\t * \n+\t * @param out\n+\t *            stream to copy the line data onto.\n+\t * @param i\n+\t *            index of the line to extract. Note this is 0-based, so line\n+\t *            number 1 is actually index 0.\n+\t * @throws IOException\n+\t *             the stream write operation failed.\n+\t */\n+\tpublic void writeLine(final OutputStream out, final int i)\n+\t\t\tthrows IOException {\n+\t\tfinal int start = lines.get(i + 1);\n+\t\tint end = lines.get(i + 2);\n+\t\tif (content[end - 1] == '\\n')\n+\t\t\tend--;\n+\t\tout.write(content, start, end - start);\n+\t}\n+\n+\tprivate IntList computeHashes() {\n+\t\tfinal IntList r = new IntList(lines.size());\n+\t\tr.add(0);\n+\t\tfor (int lno = 1; lno < lines.size() - 1; lno++) {\n+\t\t\tfinal int ptr = lines.get(lno);\n+\t\t\tfinal int end = lines.get(lno + 1);\n+\t\t\tr.add(hashLine(content, ptr, end));\n+\t\t}\n+\t\tr.add(0);\n+\t\treturn r;\n+\t}\n+\n+\t/**\n+\t * Compute a hash code for a single line.\n+\t * \n+\t * @param raw\n+\t *            the raw file content.\n+\t * @param ptr\n+\t *            first byte of the content line to hash.\n+\t * @param end\n+\t *            1 past the last byte of the content line.\n+\t * @return hash code for the region <code>[ptr, end)</code> of raw.\n+\t */\n+\tprotected int hashLine(final byte[] raw, int ptr, final int end) {\n+\t\tint hash = 5381;\n+\t\tfor (; ptr < end; ptr++)\n+\t\t\thash = (hash << 5) ^ (raw[ptr] & 0xff);\n+\t\treturn hash;\n+\t}\n+}\n\\ No newline at end of file\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/Sequence.java b/org.spearce.jgit/src/org/spearce/jgit/diff/Sequence.java\nnew file mode 100644\nindex 0000000..8e754e0\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/Sequence.java\n@@ -0,0 +1,78 @@\n+/*\n+ * Copyright (C) 2008, Johannes E. Schindelin <johannes.schindelin@gmx.de>\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+/**\n+ * Arbitrary sequence of elements with fast comparison support.\n+ * <p>\n+ * A sequence of elements is defined to contain elements in the index range\n+ * <code>[0, {@link #size()})</code>, like a standard Java List implementation.\n+ * Unlike a List, the members of the sequence are not directly obtainable, but\n+ * element equality can be tested if two Sequences are the same implementation.\n+ * <p>\n+ * An implementation may chose to implement the equals semantic as necessary,\n+ * including fuzzy matching rules such as ignoring insignificant sub-elements,\n+ * e.g. ignoring whitespace differences in text.\n+ * <p>\n+ * Implementations of Sequence are primarily intended for use in content\n+ * difference detection algorithms, to produce an {@link EditList} of\n+ * {@link Edit} instances describing how two Sequence instances differ.\n+ */\n+public interface Sequence {\n+\t/** @return total number of items in the sequence. */\n+\tpublic int size();\n+\n+\t/**\n+\t * Determine if the i-th member is equal to the j-th member.\n+\t * <p>\n+\t * Implementations must ensure <code>equals(thisIdx,other,otherIdx)</code>\n+\t * returns the same as <code>other.equals(otherIdx,this,thisIdx)</code>.\n+\t * \n+\t * @param thisIdx\n+\t *            index within <code>this</code> sequence; must be in the range\n+\t *            <code>[ 0, this.size() )</code>.\n+\t * @param other\n+\t *            another sequence; must be the same implementation class, that\n+\t *            is <code>this.getClass() == other.getClass()</code>.\n+\t * @param otherIdx\n+\t *            index within <code>other</code> sequence; must be in the range\n+\t *            <code>[ 0, other.size() )</code>.\n+\t * @return true if the elements are equal; false if they are not equal.\n+\t */\n+\tpublic boolean equals(int thisIdx, Sequence other, int otherIdx);\n+}\n\\ No newline at end of file\n-- \n1.6.3.rc3.212.g8c698\n"},{"id":"112867","messageId":"1241230127-28279-6-git-send-email-spearce@spearce.org","threadId":"19153","inReplyTo":"1241230127-28279-5-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 5/6] Teach FileHeader, HunkHeader how to create an EditList","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-02T02:08:46Z","receivedAt":"2009-05-02T02:08:46Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"The EditList type along with its member Edit instances can be very\nuseful when mining a patch for information about the change it is\ntrying to represent to the content.  This can be useful to create a\nmodified version of the patch, such as with larger or smaller number\nof context lines.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../spearce/jgit/patch/testEditList_Types.patch    |   24 +++++\n .../tst/org/spearce/jgit/patch/EditListTest.java   |   95 ++++++++++++++++++++\n .../src/org/spearce/jgit/patch/FileHeader.java     |    9 ++\n .../src/org/spearce/jgit/patch/HunkHeader.java     |   48 ++++++++++\n 4 files changed, 176 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/patch/testEditList_Types.patch\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/patch/EditListTest.java\n\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/patch/testEditList_Types.patch b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/patch/testEditList_Types.patch\nnew file mode 100644\nindex 0000000..e5363eb\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/patch/testEditList_Types.patch\n@@ -0,0 +1,24 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -2,2 +2,3 @@ a\n+ b\n++c\n+ d\n+@@ -16,4 +17,2 @@ p\n+ q\n+-r\n+-s\n+ t\n+@@ -22,4 +21,8 @@ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/patch/EditListTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/EditListTest.java\nnew file mode 100644\nindex 0000000..452f661\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/patch/EditListTest.java\n@@ -0,0 +1,95 @@\n+/*\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.patch;\n+\n+import java.io.IOException;\n+import java.io.InputStream;\n+\n+import junit.framework.TestCase;\n+\n+import org.spearce.jgit.diff.Edit;\n+import org.spearce.jgit.diff.EditList;\n+\n+public class EditListTest extends TestCase {\n+\tpublic void testHunkHeader() throws IOException {\n+\t\tfinal Patch p = parseTestPatchFile(\"testGetText_BothISO88591.patch\");\n+\t\tfinal FileHeader fh = p.getFiles().get(0);\n+\n+\t\tfinal EditList list0 = fh.getHunks().get(0).toEditList();\n+\t\tassertEquals(1, list0.size());\n+\t\tassertEquals(new Edit(4 - 1, 5 - 1, 4 - 1, 5 - 1), list0.get(0));\n+\n+\t\tfinal EditList list1 = fh.getHunks().get(1).toEditList();\n+\t\tassertEquals(1, list1.size());\n+\t\tassertEquals(new Edit(16 - 1, 17 - 1, 16 - 1, 17 - 1), list1.get(0));\n+\t}\n+\n+\tpublic void testFileHeader() throws IOException {\n+\t\tfinal Patch p = parseTestPatchFile(\"testGetText_BothISO88591.patch\");\n+\t\tfinal FileHeader fh = p.getFiles().get(0);\n+\t\tfinal EditList e = fh.toEditList();\n+\t\tassertEquals(2, e.size());\n+\t\tassertEquals(new Edit(4 - 1, 5 - 1, 4 - 1, 5 - 1), e.get(0));\n+\t\tassertEquals(new Edit(16 - 1, 17 - 1, 16 - 1, 17 - 1), e.get(1));\n+\t}\n+\n+\tpublic void testTypes() throws IOException {\n+\t\tfinal Patch p = parseTestPatchFile(\"testEditList_Types.patch\");\n+\t\tfinal FileHeader fh = p.getFiles().get(0);\n+\t\tfinal EditList e = fh.toEditList();\n+\t\tassertEquals(3, e.size());\n+\t\tassertEquals(new Edit(3 - 1, 3 - 1, 3 - 1, 4 - 1), e.get(0));\n+\t\tassertEquals(new Edit(17 - 1, 19 - 1, 18 - 1, 18 - 1), e.get(1));\n+\t\tassertEquals(new Edit(23 - 1, 25 - 1, 22 - 1, 28 - 1), e.get(2));\n+\t}\n+\n+\tprivate Patch parseTestPatchFile(final String patchFile) throws IOException {\n+\t\tfinal InputStream in = getClass().getResourceAsStream(patchFile);\n+\t\tif (in == null) {\n+\t\t\tfail(\"No \" + patchFile + \" test vector\");\n+\t\t\treturn null; // Never happens\n+\t\t}\n+\t\ttry {\n+\t\t\tfinal Patch p = new Patch();\n+\t\t\tp.parse(in);\n+\t\t\treturn p;\n+\t\t} finally {\n+\t\t\tin.close();\n+\t\t}\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java\nindex 7d341d8..c64f742 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/FileHeader.java\n@@ -52,6 +52,7 @@\n import java.util.Collections;\n import java.util.List;\n \n+import org.spearce.jgit.diff.EditList;\n import org.spearce.jgit.lib.AbbreviatedObjectId;\n import org.spearce.jgit.lib.Constants;\n import org.spearce.jgit.lib.FileMode;\n@@ -423,6 +424,14 @@ public BinaryHunk getReverseBinaryHunk() {\n \t\treturn reverseBinaryHunk;\n \t}\n \n+\t/** @return a list describing the content edits performed on this file. */\n+\tpublic EditList toEditList() {\n+\t\tfinal EditList r = new EditList();\n+\t\tfor (final HunkHeader hunk : hunks)\n+\t\t\tr.addAll(hunk.toEditList());\n+\t\treturn r;\n+\t}\n+\n \t/**\n \t * Parse a \"diff --git\" or \"diff --cc\" line.\n \t *\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java b/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java\nindex e9c55e3..af128ab 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/patch/HunkHeader.java\n@@ -44,6 +44,8 @@\n import java.io.IOException;\n import java.io.OutputStream;\n \n+import org.spearce.jgit.diff.Edit;\n+import org.spearce.jgit.diff.EditList;\n import org.spearce.jgit.lib.AbbreviatedObjectId;\n import org.spearce.jgit.util.MutableInteger;\n \n@@ -161,6 +163,52 @@ public int getLinesContext() {\n \t\treturn nContext;\n \t}\n \n+\t/** @return a list describing the content edits performed within the hunk. */\n+\tpublic EditList toEditList() {\n+\t\tfinal EditList r = new EditList();\n+\t\tfinal byte[] buf = file.buf;\n+\t\tint c = nextLF(buf, startOffset);\n+\t\tint oLine = old.startLine;\n+\t\tint nLine = newStartLine;\n+\t\tEdit in = null;\n+\n+\t\tSCAN: for (; c < endOffset; c = nextLF(buf, c)) {\n+\t\t\tswitch (buf[c]) {\n+\t\t\tcase ' ':\n+\t\t\tcase '\\n':\n+\t\t\t\tin = null;\n+\t\t\t\toLine++;\n+\t\t\t\tnLine++;\n+\t\t\t\tcontinue;\n+\n+\t\t\tcase '-':\n+\t\t\t\tif (in == null) {\n+\t\t\t\t\tin = new Edit(oLine - 1, nLine - 1);\n+\t\t\t\t\tr.add(in);\n+\t\t\t\t}\n+\t\t\t\toLine++;\n+\t\t\t\tin.extendA();\n+\t\t\t\tcontinue;\n+\n+\t\t\tcase '+':\n+\t\t\t\tif (in == null) {\n+\t\t\t\t\tin = new Edit(oLine - 1, nLine - 1);\n+\t\t\t\t\tr.add(in);\n+\t\t\t\t}\n+\t\t\t\tnLine++;\n+\t\t\t\tin.extendB();\n+\t\t\t\tcontinue;\n+\n+\t\t\tcase '\\\\': // Matches \"\\ No newline at end of file\"\n+\t\t\t\tcontinue;\n+\n+\t\t\tdefault:\n+\t\t\t\tbreak SCAN;\n+\t\t\t}\n+\t\t}\n+\t\treturn r;\n+\t}\n+\n \tvoid parseHeader() {\n \t\t// Parse \"@@ -236,9 +236,9 @@ protected boolean\"\n \t\t//\n-- \n1.6.3.rc3.212.g8c698\n"},{"id":"112865","messageId":"1241230127-28279-7-git-send-email-spearce@spearce.org","threadId":"19153","inReplyTo":"1241230127-28279-6-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 6/6] Add diff.DiffFormatter to create Git style unified patch scripts","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-02T02:08:47Z","receivedAt":"2009-05-02T02:08:47Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"From: Johannes E. Schindelin <johannes.schindelin@gmx.de>\n\nCurrently the formatter can only copy an existing FileHeader, one\nthat has been parsed from an existing patch script.  This makes\nit only useful for increasing or decreasing the number of lines\nof context, assuming we already have both the old and new contet\nimages to match.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../src/org/spearce/jgit/diff/DiffFormatter.java   |  187 ++++++++++++++++++++\n 1 files changed, 187 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\n\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java b/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\nnew file mode 100644\nindex 0000000..aa0f4a6\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\n@@ -0,0 +1,187 @@\n+/*\n+ * Copyright (C) 2008, Johannes E. Schindelin <johannes.schindelin@gmx.de>\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import static org.spearce.jgit.lib.Constants.encodeASCII;\n+\n+import java.io.IOException;\n+import java.io.OutputStream;\n+import java.util.List;\n+\n+import org.spearce.jgit.patch.FileHeader;\n+\n+/**\n+ * Format an {@link EditList} as a Git style unified patch script.\n+ */\n+public class DiffFormatter {\n+\tprivate int context;\n+\n+\t/** Create a new formatter with a default level of context. */\n+\tpublic DiffFormatter() {\n+\t\tsetContext(3);\n+\t}\n+\n+\t/**\n+\t * Change the number of lines of context to display.\n+\t * \n+\t * @param lineCount\n+\t *            number of lines of context to see before the first\n+\t *            modification and after the last modification within a hunk of\n+\t *            the modified file.\n+\t */\n+\tpublic void setContext(final int lineCount) {\n+\t\tif (lineCount < 0)\n+\t\t\tthrow new IllegalArgumentException(\"context must be >= 0\");\n+\t\tcontext = lineCount;\n+\t}\n+\n+\t/**\n+\t * Format a patch script, reusing a previously parsed FileHeader.\n+\t * <p>\n+\t * This formatter is primarily useful for editing an existing patch script\n+\t * to increase or reduce the number of lines of context within the script.\n+\t * All header lines are reused as-is from the supplied FileHeader.\n+\t * \n+\t * @param out\n+\t *            stream to write the patch script out to.\n+\t * @param head\n+\t *            existing file header containing the header lines to copy.\n+\t * @param a\n+\t *            text source for the pre-image version of the content. This\n+\t *            must match the content of {@link FileHeader#getOldId()}.\n+\t * @param b\n+\t *            text source for the post-image version of the content. This\n+\t *            must match the content of {@link FileHeader#getNewId()}.\n+\t * @throws IOException\n+\t *             writing to the supplied stream failed.\n+\t */\n+\tpublic void format(final OutputStream out, final FileHeader head,\n+\t\t\tfinal RawText a, final RawText b)\n+\t\t\tthrows IOException {\n+\t\t// Reuse the existing FileHeader as-is by blindly copying its\n+\t\t// header lines, but avoiding its hunks. Instead we recreate\n+\t\t// the hunks from the text instances we have been supplied.\n+\t\t//\n+\t\tfinal int start = head.getStartOffset();\n+\t\tint end = head.getEndOffset();\n+\t\tif (!head.getHunks().isEmpty())\n+\t\t\tend = head.getHunks().get(0).getStartOffset();\n+\t\tout.write(head.getBuffer(), start, end - start);\n+\n+\t\tformatEdits(out, a, b, head.toEditList());\n+\t}\n+\n+\tprivate void formatEdits(final OutputStream out, final RawText a,\n+\t\t\tfinal RawText b, final EditList edits) throws IOException {\n+\t\tfor (int curIdx = 0; curIdx < edits.size();) {\n+\t\t\tEdit curEdit = edits.get(curIdx);\n+\t\t\tfinal int endIdx = findCombinedEnd(edits, curIdx);\n+\t\t\tfinal Edit endEdit = edits.get(endIdx);\n+\n+\t\t\tint aCur = Math.max(0, curEdit.getBeginA() - context);\n+\t\t\tint bCur = Math.max(0, curEdit.getBeginB() - context);\n+\t\t\tfinal int aEnd = Math.min(a.size(), endEdit.getEndA() + context);\n+\t\t\tfinal int bEnd = Math.min(b.size(), endEdit.getEndB() + context);\n+\n+\t\t\tout.write('@');\n+\t\t\tout.write('@');\n+\t\t\twriteLineGroup(out, '-', aCur + 1, aEnd - aCur);\n+\t\t\twriteLineGroup(out, '+', bCur + 1, bEnd - bCur);\n+\t\t\tout.write(' ');\n+\t\t\tout.write('@');\n+\t\t\tout.write('@');\n+\t\t\tout.write('\\n');\n+\n+\t\t\twhile (aCur < aEnd || bCur < bEnd) {\n+\t\t\t\tif (aCur < curEdit.getBeginA() || endIdx + 1 < curIdx) {\n+\t\t\t\t\tout.write(' ');\n+\t\t\t\t\ta.writeLine(out, aCur);\n+\t\t\t\t\tout.write('\\n');\n+\t\t\t\t\taCur++;\n+\t\t\t\t\tbCur++;\n+\n+\t\t\t\t} else if (aCur < curEdit.getEndA()) {\n+\t\t\t\t\tout.write('-');\n+\t\t\t\t\ta.writeLine(out, aCur);\n+\t\t\t\t\tout.write('\\n');\n+\t\t\t\t\taCur++;\n+\n+\t\t\t\t} else if (bCur < curEdit.getEndB()) {\n+\t\t\t\t\tout.write('+');\n+\t\t\t\t\tb.writeLine(out, bCur);\n+\t\t\t\t\tout.write('\\n');\n+\t\t\t\t\tbCur++;\n+\t\t\t\t}\n+\n+\t\t\t\tif (!in(curEdit, aCur, bCur) && ++curIdx < edits.size())\n+\t\t\t\t\tcurEdit = edits.get(curIdx);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tprivate static void writeLineGroup(final OutputStream out,\n+\t\t\tfinal char prefix, final int begin, final int end)\n+\t\t\tthrows IOException {\n+\t\tout.write(' ');\n+\t\tout.write(prefix);\n+\t\tout.write(encodeASCII(begin));\n+\t\tout.write(',');\n+\t\tout.write(encodeASCII(end));\n+\t}\n+\n+\tprivate int findCombinedEnd(final List<Edit> edits, final int i) {\n+\t\tint end = i + 1;\n+\t\twhile (end < edits.size()\n+\t\t\t\t&& (combineA(edits, end) || combineB(edits, end)))\n+\t\t\tend++;\n+\t\treturn end - 1;\n+\t}\n+\n+\tprivate boolean combineA(final List<Edit> e, final int i) {\n+\t\treturn e.get(i).getBeginA() - e.get(i - 1).getEndA() <= 2 * context;\n+\t}\n+\n+\tprivate boolean combineB(final List<Edit> e, final int i) {\n+\t\treturn e.get(i).getBeginB() - e.get(i - 1).getEndB() <= 2 * context;\n+\t}\n+\n+\tprivate static boolean in(final Edit edit, final int a, final int b) {\n+\t\treturn a < edit.getEndA() && b < edit.getEndB();\n+\t}\n+}\n-- \n1.6.3.rc3.212.g8c698\n"},{"id":"112893","messageId":"20090503000329.GM23604@spearce.org","threadId":"19153","inReplyTo":"1241230127-28279-7-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH v2 6/6] Add diff.DiffFormatter to create Git style unified patch scripts","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-03T00:03:29Z","receivedAt":"2009-05-03T00:03:29Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"From: Johannes E. Schindelin <johannes.schindelin@gmx.de>\n\nCurrently the formatter can only copy an existing FileHeader, one\nthat has been parsed from an existing patch script.  This makes\nit only useful for increasing or decreasing the number of lines\nof context, assuming we already have both the old and new content\nimages to match.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n\n Replacement fixes a lot of bugs, and includes a bunch of test\n cases that helped me find and fix those bugs in the first place. :-)\n\n There's a quirk about setContext(0) differing in JGit and CGit,\n see the thread I just posted a short while ago.\n\n .../tst-rsrc/org/spearce/jgit/diff/E.patch         |    6 +\n .../tst-rsrc/org/spearce/jgit/diff/E_PostImage     |    1 +\n .../tst-rsrc/org/spearce/jgit/diff/X.patch         |   24 ++\n .../tst-rsrc/org/spearce/jgit/diff/X_PostImage     |   28 +++\n .../tst-rsrc/org/spearce/jgit/diff/X_PreImage      |   25 +++\n .../tst-rsrc/org/spearce/jgit/diff/Y.patch         |    8 +\n .../tst-rsrc/org/spearce/jgit/diff/Y_PostImage     |    1 +\n .../tst-rsrc/org/spearce/jgit/diff/Y_PreImage      |    1 +\n .../tst-rsrc/org/spearce/jgit/diff/Z.patch         |    8 +\n .../tst-rsrc/org/spearce/jgit/diff/Z_PostImage     |    1 +\n .../tst-rsrc/org/spearce/jgit/diff/Z_PreImage      |    1 +\n .../org/spearce/jgit/diff/testContext1.out         |   24 ++\n .../org/spearce/jgit/diff/testContext10.out        |   37 ++++\n .../org/spearce/jgit/diff/testContext100.out       |   37 ++++\n .../org/spearce/jgit/diff/testContext3.out         |   30 +++\n .../org/spearce/jgit/diff/testContext5.out         |   34 +++\n .../spearce/jgit/diff/DiffFormatterReflowTest.java |  170 +++++++++++++++\n .../src/org/spearce/jgit/diff/DiffFormatter.java   |  220 ++++++++++++++++++++\n .../src/org/spearce/jgit/diff/RawText.java         |   12 +\n 19 files changed, 668 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E.patch\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PostImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PreImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X.patch\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PostImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PreImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y.patch\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PostImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PreImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z.patch\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PostImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PreImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext1.out\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext10.out\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext100.out\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext3.out\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext5.out\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/diff/DiffFormatterReflowTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\n\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E.patch b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E.patch\nnew file mode 100644\nindex 0000000..9b8fa98\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E.patch\n@@ -0,0 +1,6 @@\n+diff --git a/E b/E\n+index e69de29..7898192 100644\n+--- a/E\n++++ b/E\n+@@ -0,0 +1 @@\n++a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PostImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PostImage\nnew file mode 100644\nindex 0000000..7898192\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PostImage\n@@ -0,0 +1 @@\n+a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PreImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PreImage\nnew file mode 100644\nindex 0000000..e69de29\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X.patch b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X.patch\nnew file mode 100644\nindex 0000000..e5363eb\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X.patch\n@@ -0,0 +1,24 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -2,2 +2,3 @@ a\n+ b\n++c\n+ d\n+@@ -16,4 +17,2 @@ p\n+ q\n+-r\n+-s\n+ t\n+@@ -22,4 +21,8 @@ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PostImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PostImage\nnew file mode 100644\nindex 0000000..2d44096\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PostImage\n@@ -0,0 +1,28 @@\n+a\n+b\n+c\n+d\n+e\n+f\n+g\n+h\n+i\n+j\n+k\n+l\n+m\n+n\n+o\n+p\n+q\n+t\n+u\n+v\n+w\n+0\n+1\n+2\n+3\n+4\n+5\n+z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PreImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PreImage\nnew file mode 100644\nindex 0000000..a3648a1\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PreImage\n@@ -0,0 +1,25 @@\n+a\n+b\n+d\n+e\n+f\n+g\n+h\n+i\n+j\n+k\n+l\n+m\n+n\n+o\n+p\n+q\n+r\n+s\n+t\n+u\n+v\n+w\n+x\n+y\n+z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y.patch b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y.patch\nnew file mode 100644\nindex 0000000..a2c9a0b\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y.patch\n@@ -0,0 +1,8 @@\n+diff --git a/Y b/Y\n+index 2e65efe..7898192 100644\n+--- a/Y\n++++ b/Y\n+@@ -1 +1 @@\n+-a\n+\\ No newline at end of file\n++a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PostImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PostImage\nnew file mode 100644\nindex 0000000..7898192\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PostImage\n@@ -0,0 +1 @@\n+a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PreImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PreImage\nnew file mode 100644\nindex 0000000..2e65efe\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PreImage\n@@ -0,0 +1 @@\n+a\n\\ No newline at end of file\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z.patch b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z.patch\nnew file mode 100644\nindex 0000000..35a06d6\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z.patch\n@@ -0,0 +1,8 @@\n+diff --git a/Z b/Z\n+index 7898192..2e65efe 100644\n+--- a/Z\n++++ b/Z\n+@@ -1 +1 @@\n+-a\n++a\n+\\ No newline at end of file\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PostImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PostImage\nnew file mode 100644\nindex 0000000..2e65efe\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PostImage\n@@ -0,0 +1 @@\n+a\n\\ No newline at end of file\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PreImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PreImage\nnew file mode 100644\nindex 0000000..7898192\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PreImage\n@@ -0,0 +1 @@\n+a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext1.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext1.out\nnew file mode 100644\nindex 0000000..d0d847d\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext1.out\n@@ -0,0 +1,24 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -2,2 +2,3 @@\n+ b\n++c\n+ d\n+@@ -16,4 +17,2 @@\n+ q\n+-r\n+-s\n+ t\n+@@ -22,4 +21,8 @@\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext10.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext10.out\nnew file mode 100644\nindex 0000000..1d4f242\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext10.out\n@@ -0,0 +1,37 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -1,25 +1,28 @@\n+ a\n+ b\n++c\n+ d\n+ e\n+ f\n+ g\n+ h\n+ i\n+ j\n+ k\n+ l\n+ m\n+ n\n+ o\n+ p\n+ q\n+-r\n+-s\n+ t\n+ u\n+ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext100.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext100.out\nnew file mode 100644\nindex 0000000..1d4f242\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext100.out\n@@ -0,0 +1,37 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -1,25 +1,28 @@\n+ a\n+ b\n++c\n+ d\n+ e\n+ f\n+ g\n+ h\n+ i\n+ j\n+ k\n+ l\n+ m\n+ n\n+ o\n+ p\n+ q\n+-r\n+-s\n+ t\n+ u\n+ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext3.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext3.out\nnew file mode 100644\nindex 0000000..2564016\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext3.out\n@@ -0,0 +1,30 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -1,5 +1,6 @@\n+ a\n+ b\n++c\n+ d\n+ e\n+ f\n+@@ -14,12 +15,14 @@\n+ o\n+ p\n+ q\n+-r\n+-s\n+ t\n+ u\n+ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext5.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext5.out\nnew file mode 100644\nindex 0000000..3073c5f\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext5.out\n@@ -0,0 +1,34 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -1,7 +1,8 @@\n+ a\n+ b\n++c\n+ d\n+ e\n+ f\n+ g\n+ h\n+@@ -12,14 +13,16 @@\n+ m\n+ n\n+ o\n+ p\n+ q\n+-r\n+-s\n+ t\n+ u\n+ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/diff/DiffFormatterReflowTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/DiffFormatterReflowTest.java\nnew file mode 100644\nindex 0000000..f47282c\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/DiffFormatterReflowTest.java\n@@ -0,0 +1,170 @@\n+/*\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import java.io.ByteArrayOutputStream;\n+import java.io.IOException;\n+import java.io.InputStream;\n+\n+import junit.framework.TestCase;\n+\n+import org.spearce.jgit.patch.FileHeader;\n+import org.spearce.jgit.patch.Patch;\n+import org.spearce.jgit.util.RawParseUtils;\n+\n+public class DiffFormatterReflowTest extends TestCase {\n+\tprivate RawText a;\n+\n+\tprivate RawText b;\n+\n+\tprivate FileHeader file;\n+\n+\tprivate ByteArrayOutputStream out;\n+\n+\tprivate DiffFormatter fmt;\n+\n+\tprotected void setUp() throws Exception {\n+\t\tsuper.setUp();\n+\t\tout = new ByteArrayOutputStream();\n+\t\tfmt = new DiffFormatter();\n+\t}\n+\n+\tpublic void testNegativeContextFails() throws IOException {\n+\t\tinit(\"X\");\n+\t\ttry {\n+\t\t\tfmt.setContext(-1);\n+\t\t\tfail(\"accepted negative context\");\n+\t\t} catch (IllegalArgumentException e) {\n+\t\t\t// pass\n+\t\t}\n+\t}\n+\n+\tpublic void testContext1() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(1);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testContext3() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(3);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testContext5() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(5);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testContext10() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(10);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testContext100() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(100);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testEmpty1() throws IOException {\n+\t\tinit(\"E\");\n+\t\tassertFormatted(\"E.patch\");\n+\t}\n+\n+\tpublic void testNoNewLine1() throws IOException {\n+\t\tinit(\"Y\");\n+\t\tassertFormatted(\"Y.patch\");\n+\t}\n+\n+\tpublic void testNoNewLine2() throws IOException {\n+\t\tinit(\"Z\");\n+\t\tassertFormatted(\"Z.patch\");\n+\t}\n+\n+\tprivate void init(final String name) throws IOException {\n+\t\ta = new RawText(readFile(name + \"_PreImage\"));\n+\t\tb = new RawText(readFile(name + \"_PostImage\"));\n+\t\tfile = parseTestPatchFile(name + \".patch\").getFiles().get(0);\n+\t}\n+\n+\tprivate void assertFormatted() throws IOException {\n+\t\tassertFormatted(getName() + \".out\");\n+\t}\n+\n+\tprivate void assertFormatted(final String name) throws IOException {\n+\t\tfmt.format(out, file, a, b);\n+\t\tfinal String exp = RawParseUtils.decode(readFile(name));\n+\t\tassertEquals(exp, RawParseUtils.decode(out.toByteArray()));\n+\t}\n+\n+\tprivate byte[] readFile(final String patchFile) throws IOException {\n+\t\tfinal InputStream in = getClass().getResourceAsStream(patchFile);\n+\t\tif (in == null) {\n+\t\t\tfail(\"No \" + patchFile + \" test vector\");\n+\t\t\treturn null; // Never happens\n+\t\t}\n+\t\ttry {\n+\t\t\tfinal byte[] buf = new byte[1024];\n+\t\t\tfinal ByteArrayOutputStream temp = new ByteArrayOutputStream();\n+\t\t\tint n;\n+\t\t\twhile ((n = in.read(buf)) > 0)\n+\t\t\t\ttemp.write(buf, 0, n);\n+\t\t\treturn temp.toByteArray();\n+\t\t} finally {\n+\t\t\tin.close();\n+\t\t}\n+\t}\n+\n+\tprivate Patch parseTestPatchFile(final String patchFile) throws IOException {\n+\t\tfinal InputStream in = getClass().getResourceAsStream(patchFile);\n+\t\tif (in == null) {\n+\t\t\tfail(\"No \" + patchFile + \" test vector\");\n+\t\t\treturn null; // Never happens\n+\t\t}\n+\t\ttry {\n+\t\t\tfinal Patch p = new Patch();\n+\t\t\tp.parse(in);\n+\t\t\treturn p;\n+\t\t} finally {\n+\t\t\tin.close();\n+\t\t}\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java b/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\nnew file mode 100644\nindex 0000000..97db9a2\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\n@@ -0,0 +1,220 @@\n+/*\n+ * Copyright (C) 2008, Johannes E. Schindelin <johannes.schindelin@gmx.de>\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import static org.spearce.jgit.lib.Constants.encodeASCII;\n+\n+import java.io.IOException;\n+import java.io.OutputStream;\n+import java.util.List;\n+\n+import org.spearce.jgit.patch.FileHeader;\n+\n+/**\n+ * Format an {@link EditList} as a Git style unified patch script.\n+ */\n+public class DiffFormatter {\n+\tprivate static final byte[] noNewLine = encodeASCII(\"\\\\ No newline at end of file\\n\");\n+\n+\tprivate int context;\n+\n+\t/** Create a new formatter with a default level of context. */\n+\tpublic DiffFormatter() {\n+\t\tsetContext(3);\n+\t}\n+\n+\t/**\n+\t * Change the number of lines of context to display.\n+\t * \n+\t * @param lineCount\n+\t *            number of lines of context to see before the first\n+\t *            modification and after the last modification within a hunk of\n+\t *            the modified file.\n+\t */\n+\tpublic void setContext(final int lineCount) {\n+\t\tif (lineCount < 0)\n+\t\t\tthrow new IllegalArgumentException(\"context must be >= 0\");\n+\t\tcontext = lineCount;\n+\t}\n+\n+\t/**\n+\t * Format a patch script, reusing a previously parsed FileHeader.\n+\t * <p>\n+\t * This formatter is primarily useful for editing an existing patch script\n+\t * to increase or reduce the number of lines of context within the script.\n+\t * All header lines are reused as-is from the supplied FileHeader.\n+\t * \n+\t * @param out\n+\t *            stream to write the patch script out to.\n+\t * @param head\n+\t *            existing file header containing the header lines to copy.\n+\t * @param a\n+\t *            text source for the pre-image version of the content. This\n+\t *            must match the content of {@link FileHeader#getOldId()}.\n+\t * @param b\n+\t *            text source for the post-image version of the content. This\n+\t *            must match the content of {@link FileHeader#getNewId()}.\n+\t * @throws IOException\n+\t *             writing to the supplied stream failed.\n+\t */\n+\tpublic void format(final OutputStream out, final FileHeader head,\n+\t\t\tfinal RawText a, final RawText b) throws IOException {\n+\t\t// Reuse the existing FileHeader as-is by blindly copying its\n+\t\t// header lines, but avoiding its hunks. Instead we recreate\n+\t\t// the hunks from the text instances we have been supplied.\n+\t\t//\n+\t\tfinal int start = head.getStartOffset();\n+\t\tint end = head.getEndOffset();\n+\t\tif (!head.getHunks().isEmpty())\n+\t\t\tend = head.getHunks().get(0).getStartOffset();\n+\t\tout.write(head.getBuffer(), start, end - start);\n+\n+\t\tformatEdits(out, a, b, head.toEditList());\n+\t}\n+\n+\tprivate void formatEdits(final OutputStream out, final RawText a,\n+\t\t\tfinal RawText b, final EditList edits) throws IOException {\n+\t\tfor (int curIdx = 0; curIdx < edits.size();) {\n+\t\t\tEdit curEdit = edits.get(curIdx);\n+\t\t\tfinal int endIdx = findCombinedEnd(edits, curIdx);\n+\t\t\tfinal Edit endEdit = edits.get(endIdx);\n+\n+\t\t\tint aCur = Math.max(0, curEdit.getBeginA() - context);\n+\t\t\tint bCur = Math.max(0, curEdit.getBeginB() - context);\n+\t\t\tfinal int aEnd = Math.min(a.size(), endEdit.getEndA() + context);\n+\t\t\tfinal int bEnd = Math.min(b.size(), endEdit.getEndB() + context);\n+\n+\t\t\twriteHunkHeader(out, aCur, aEnd, bCur, bEnd, curIdx == 0);\n+\n+\t\t\twhile (aCur < aEnd || bCur < bEnd) {\n+\t\t\t\tif (aCur < curEdit.getBeginA() || endIdx + 1 < curIdx) {\n+\t\t\t\t\twriteLine(out, ' ', a, aCur);\n+\t\t\t\t\taCur++;\n+\t\t\t\t\tbCur++;\n+\n+\t\t\t\t} else if (aCur < curEdit.getEndA()) {\n+\t\t\t\t\twriteLine(out, '-', a, aCur++);\n+\n+\t\t\t\t} else if (bCur < curEdit.getEndB()) {\n+\t\t\t\t\twriteLine(out, '+', b, bCur++);\n+\t\t\t\t}\n+\n+\t\t\t\tif (end(curEdit, aCur, bCur) && ++curIdx < edits.size())\n+\t\t\t\t\tcurEdit = edits.get(curIdx);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tprivate void writeHunkHeader(final OutputStream out, final int aCur,\n+\t\t\tfinal int aEnd, final int bCur, final int bEnd,\n+\t\t\tfinal boolean firstHunk) throws IOException {\n+\t\tout.write('@');\n+\t\tout.write('@');\n+\t\tif (firstHunk) {\n+\t\t\twriteFirstLineGroup(out, '-', aCur + 1, aEnd - aCur);\n+\t\t\twriteFirstLineGroup(out, '+', bCur + 1, bEnd - bCur);\n+\t\t} else {\n+\t\t\twriteAnyLineGroup(out, '-', aCur + 1, aEnd - aCur);\n+\t\t\twriteAnyLineGroup(out, '+', bCur + 1, bEnd - bCur);\n+\t\t}\n+\t\tout.write(' ');\n+\t\tout.write('@');\n+\t\tout.write('@');\n+\t\tout.write('\\n');\n+\t}\n+\n+\tprivate static void writeFirstLineGroup(final OutputStream out,\n+\t\t\tfinal char prefix, final int begin, final int cnt)\n+\t\t\tthrows IOException {\n+\t\tif (begin == 1 && cnt == 0) {\n+\t\t\tout.write(' ');\n+\t\t\tout.write(prefix);\n+\t\t\tout.write('0');\n+\t\t\tout.write(',');\n+\t\t\tout.write('0');\n+\n+\t\t} else if (cnt == 1) {\n+\t\t\tout.write(' ');\n+\t\t\tout.write(prefix);\n+\t\t\tout.write(encodeASCII(begin));\n+\n+\t\t} else {\n+\t\t\twriteAnyLineGroup(out, prefix, begin, cnt);\n+\t\t}\n+\t}\n+\n+\tprivate static void writeAnyLineGroup(final OutputStream out,\n+\t\t\tfinal char prefix, final int begin, final int cnt)\n+\t\t\tthrows IOException {\n+\t\tout.write(' ');\n+\t\tout.write(prefix);\n+\t\tout.write(encodeASCII(begin));\n+\t\tout.write(',');\n+\t\tout.write(encodeASCII(cnt));\n+\t}\n+\n+\tprivate static void writeLine(final OutputStream out, final char prefix,\n+\t\t\tfinal RawText text, final int cur) throws IOException {\n+\t\tout.write(prefix);\n+\t\ttext.writeLine(out, cur);\n+\t\tout.write('\\n');\n+\t\tif (cur + 1 == text.size() && text.isMissingNewlineAtEnd())\n+\t\t\tout.write(noNewLine);\n+\t}\n+\n+\tprivate int findCombinedEnd(final List<Edit> edits, final int i) {\n+\t\tint end = i + 1;\n+\t\twhile (end < edits.size()\n+\t\t\t\t&& (combineA(edits, end) || combineB(edits, end)))\n+\t\t\tend++;\n+\t\treturn end - 1;\n+\t}\n+\n+\tprivate boolean combineA(final List<Edit> e, final int i) {\n+\t\treturn e.get(i).getBeginA() - e.get(i - 1).getEndA() <= 2 * context;\n+\t}\n+\n+\tprivate boolean combineB(final List<Edit> e, final int i) {\n+\t\treturn e.get(i).getBeginB() - e.get(i - 1).getEndB() <= 2 * context;\n+\t}\n+\n+\tprivate static boolean end(final Edit edit, final int a, final int b) {\n+\t\treturn edit.getEndA() <= a && edit.getEndB() <= b;\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java b/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\nindex 1d10082..e10ee46 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\n@@ -140,6 +140,18 @@ public void writeLine(final OutputStream out, final int i)\n \t\tout.write(content, start, end - start);\n \t}\n \n+\t/**\n+\t * Determine if the file ends with a LF ('\\n').\n+\t * \n+\t * @return true if the last line has an LF; false otherwise.\n+\t */\n+\tpublic boolean isMissingNewlineAtEnd() {\n+\t\tfinal int end = lines.get(lines.size() - 1);\n+\t\tif (end == 0)\n+\t\t\treturn true;\n+\t\treturn content[end - 1] != '\\n';\n+\t}\n+\n \tprivate IntList computeHashes() {\n \t\tfinal IntList r = new IntList(lines.size());\n \t\tr.add(0);\n-- \n1.6.3.rc4.190.g4648\n"},{"id":"112898","messageId":"20090503002938.GQ23604@spearce.org","threadId":"19153","inReplyTo":"20090503000329.GM23604@spearce.org","subject":"[JGIT PATCH v3 6/6] Add diff.DiffFormatter to create Git style unified patch scripts","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-03T00:29:38Z","receivedAt":"2009-05-03T00:29:38Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"From: Johannes E. Schindelin <johannes.schindelin@gmx.de>\n\nCurrently the formatter can only copy an existing FileHeader, one\nthat has been parsed from an existing patch script.  This makes\nit only useful for increasing or decreasing the number of lines\nof context, assuming we already have both the old and new content\nimages to match.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n  \"Shawn O. Pearce\" <spearce@spearce.org> wrote:\n  >  There's a quirk about setContext(0) differing in JGit and CGit,\n  >  see the thread I just posted a short while ago.\n\n  v3 fixes this issue, thanks to Junio's comments.\n\n  This includes 7/6, which now passes, and makes 8/6 obsolete.\n\n .../tst-rsrc/org/spearce/jgit/diff/E.patch         |    6 +\n .../tst-rsrc/org/spearce/jgit/diff/E_PostImage     |    1 +\n .../tst-rsrc/org/spearce/jgit/diff/X.patch         |   24 +++\n .../tst-rsrc/org/spearce/jgit/diff/X_PostImage     |   28 +++\n .../tst-rsrc/org/spearce/jgit/diff/X_PreImage      |   25 +++\n .../tst-rsrc/org/spearce/jgit/diff/Y.patch         |    8 +\n .../tst-rsrc/org/spearce/jgit/diff/Y_PostImage     |    1 +\n .../tst-rsrc/org/spearce/jgit/diff/Y_PreImage      |    1 +\n .../tst-rsrc/org/spearce/jgit/diff/Z.patch         |    8 +\n .../tst-rsrc/org/spearce/jgit/diff/Z_PostImage     |    1 +\n .../tst-rsrc/org/spearce/jgit/diff/Z_PreImage      |    1 +\n .../org/spearce/jgit/diff/testContext0.out         |   18 ++\n .../org/spearce/jgit/diff/testContext1.out         |   24 +++\n .../org/spearce/jgit/diff/testContext10.out        |   37 ++++\n .../org/spearce/jgit/diff/testContext100.out       |   37 ++++\n .../org/spearce/jgit/diff/testContext3.out         |   30 +++\n .../org/spearce/jgit/diff/testContext5.out         |   34 +++\n .../spearce/jgit/diff/DiffFormatterReflowTest.java |  176 ++++++++++++++++\n .../src/org/spearce/jgit/diff/DiffFormatter.java   |  214 ++++++++++++++++++++\n .../src/org/spearce/jgit/diff/RawText.java         |   12 +\n 20 files changed, 686 insertions(+), 0 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E.patch\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PostImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PreImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X.patch\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PostImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PreImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y.patch\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PostImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PreImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z.patch\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PostImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PreImage\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext0.out\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext1.out\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext10.out\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext100.out\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext3.out\n create mode 100644 org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext5.out\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/diff/DiffFormatterReflowTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\n\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E.patch b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E.patch\nnew file mode 100644\nindex 0000000..9b8fa98\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E.patch\n@@ -0,0 +1,6 @@\n+diff --git a/E b/E\n+index e69de29..7898192 100644\n+--- a/E\n++++ b/E\n+@@ -0,0 +1 @@\n++a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PostImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PostImage\nnew file mode 100644\nindex 0000000..7898192\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PostImage\n@@ -0,0 +1 @@\n+a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PreImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/E_PreImage\nnew file mode 100644\nindex 0000000..e69de29\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X.patch b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X.patch\nnew file mode 100644\nindex 0000000..e5363eb\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X.patch\n@@ -0,0 +1,24 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -2,2 +2,3 @@ a\n+ b\n++c\n+ d\n+@@ -16,4 +17,2 @@ p\n+ q\n+-r\n+-s\n+ t\n+@@ -22,4 +21,8 @@ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PostImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PostImage\nnew file mode 100644\nindex 0000000..2d44096\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PostImage\n@@ -0,0 +1,28 @@\n+a\n+b\n+c\n+d\n+e\n+f\n+g\n+h\n+i\n+j\n+k\n+l\n+m\n+n\n+o\n+p\n+q\n+t\n+u\n+v\n+w\n+0\n+1\n+2\n+3\n+4\n+5\n+z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PreImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PreImage\nnew file mode 100644\nindex 0000000..a3648a1\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/X_PreImage\n@@ -0,0 +1,25 @@\n+a\n+b\n+d\n+e\n+f\n+g\n+h\n+i\n+j\n+k\n+l\n+m\n+n\n+o\n+p\n+q\n+r\n+s\n+t\n+u\n+v\n+w\n+x\n+y\n+z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y.patch b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y.patch\nnew file mode 100644\nindex 0000000..a2c9a0b\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y.patch\n@@ -0,0 +1,8 @@\n+diff --git a/Y b/Y\n+index 2e65efe..7898192 100644\n+--- a/Y\n++++ b/Y\n+@@ -1 +1 @@\n+-a\n+\\ No newline at end of file\n++a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PostImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PostImage\nnew file mode 100644\nindex 0000000..7898192\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PostImage\n@@ -0,0 +1 @@\n+a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PreImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PreImage\nnew file mode 100644\nindex 0000000..2e65efe\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Y_PreImage\n@@ -0,0 +1 @@\n+a\n\\ No newline at end of file\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z.patch b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z.patch\nnew file mode 100644\nindex 0000000..35a06d6\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z.patch\n@@ -0,0 +1,8 @@\n+diff --git a/Z b/Z\n+index 7898192..2e65efe 100644\n+--- a/Z\n++++ b/Z\n+@@ -1 +1 @@\n+-a\n++a\n+\\ No newline at end of file\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PostImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PostImage\nnew file mode 100644\nindex 0000000..2e65efe\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PostImage\n@@ -0,0 +1 @@\n+a\n\\ No newline at end of file\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PreImage b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PreImage\nnew file mode 100644\nindex 0000000..7898192\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/Z_PreImage\n@@ -0,0 +1 @@\n+a\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext0.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext0.out\nnew file mode 100644\nindex 0000000..d36e3fa\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext0.out\n@@ -0,0 +1,18 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -2,0 +3 @@\n++c\n+@@ -17,2 +17,0 @@\n+-r\n+-s\n+@@ -23,2 +22,6 @@\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext1.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext1.out\nnew file mode 100644\nindex 0000000..d0d847d\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext1.out\n@@ -0,0 +1,24 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -2,2 +2,3 @@\n+ b\n++c\n+ d\n+@@ -16,4 +17,2 @@\n+ q\n+-r\n+-s\n+ t\n+@@ -22,4 +21,8 @@\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext10.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext10.out\nnew file mode 100644\nindex 0000000..1d4f242\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext10.out\n@@ -0,0 +1,37 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -1,25 +1,28 @@\n+ a\n+ b\n++c\n+ d\n+ e\n+ f\n+ g\n+ h\n+ i\n+ j\n+ k\n+ l\n+ m\n+ n\n+ o\n+ p\n+ q\n+-r\n+-s\n+ t\n+ u\n+ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext100.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext100.out\nnew file mode 100644\nindex 0000000..1d4f242\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext100.out\n@@ -0,0 +1,37 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -1,25 +1,28 @@\n+ a\n+ b\n++c\n+ d\n+ e\n+ f\n+ g\n+ h\n+ i\n+ j\n+ k\n+ l\n+ m\n+ n\n+ o\n+ p\n+ q\n+-r\n+-s\n+ t\n+ u\n+ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext3.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext3.out\nnew file mode 100644\nindex 0000000..2564016\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext3.out\n@@ -0,0 +1,30 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -1,5 +1,6 @@\n+ a\n+ b\n++c\n+ d\n+ e\n+ f\n+@@ -14,12 +15,14 @@\n+ o\n+ p\n+ q\n+-r\n+-s\n+ t\n+ u\n+ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext5.out b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext5.out\nnew file mode 100644\nindex 0000000..3073c5f\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst-rsrc/org/spearce/jgit/diff/testContext5.out\n@@ -0,0 +1,34 @@\n+diff --git a/X b/X\n+index a3648a1..2d44096 100644\n+--- a/X\n++++ b/X\n+@@ -1,7 +1,8 @@\n+ a\n+ b\n++c\n+ d\n+ e\n+ f\n+ g\n+ h\n+@@ -12,14 +13,16 @@\n+ m\n+ n\n+ o\n+ p\n+ q\n+-r\n+-s\n+ t\n+ u\n+ v\n+ w\n+-x\n+-y\n++0\n++1\n++2\n++3\n++4\n++5\n+ z\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/diff/DiffFormatterReflowTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/DiffFormatterReflowTest.java\nnew file mode 100644\nindex 0000000..5d2ee40\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/diff/DiffFormatterReflowTest.java\n@@ -0,0 +1,176 @@\n+/*\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import java.io.ByteArrayOutputStream;\n+import java.io.IOException;\n+import java.io.InputStream;\n+\n+import junit.framework.TestCase;\n+\n+import org.spearce.jgit.patch.FileHeader;\n+import org.spearce.jgit.patch.Patch;\n+import org.spearce.jgit.util.RawParseUtils;\n+\n+public class DiffFormatterReflowTest extends TestCase {\n+\tprivate RawText a;\n+\n+\tprivate RawText b;\n+\n+\tprivate FileHeader file;\n+\n+\tprivate ByteArrayOutputStream out;\n+\n+\tprivate DiffFormatter fmt;\n+\n+\tprotected void setUp() throws Exception {\n+\t\tsuper.setUp();\n+\t\tout = new ByteArrayOutputStream();\n+\t\tfmt = new DiffFormatter();\n+\t}\n+\n+\tpublic void testNegativeContextFails() throws IOException {\n+\t\tinit(\"X\");\n+\t\ttry {\n+\t\t\tfmt.setContext(-1);\n+\t\t\tfail(\"accepted negative context\");\n+\t\t} catch (IllegalArgumentException e) {\n+\t\t\t// pass\n+\t\t}\n+\t}\n+\n+\tpublic void testContext0() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(0);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testContext1() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(1);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testContext3() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(3);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testContext5() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(5);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testContext10() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(10);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testContext100() throws IOException {\n+\t\tinit(\"X\");\n+\t\tfmt.setContext(100);\n+\t\tassertFormatted();\n+\t}\n+\n+\tpublic void testEmpty1() throws IOException {\n+\t\tinit(\"E\");\n+\t\tassertFormatted(\"E.patch\");\n+\t}\n+\n+\tpublic void testNoNewLine1() throws IOException {\n+\t\tinit(\"Y\");\n+\t\tassertFormatted(\"Y.patch\");\n+\t}\n+\n+\tpublic void testNoNewLine2() throws IOException {\n+\t\tinit(\"Z\");\n+\t\tassertFormatted(\"Z.patch\");\n+\t}\n+\n+\tprivate void init(final String name) throws IOException {\n+\t\ta = new RawText(readFile(name + \"_PreImage\"));\n+\t\tb = new RawText(readFile(name + \"_PostImage\"));\n+\t\tfile = parseTestPatchFile(name + \".patch\").getFiles().get(0);\n+\t}\n+\n+\tprivate void assertFormatted() throws IOException {\n+\t\tassertFormatted(getName() + \".out\");\n+\t}\n+\n+\tprivate void assertFormatted(final String name) throws IOException {\n+\t\tfmt.format(out, file, a, b);\n+\t\tfinal String exp = RawParseUtils.decode(readFile(name));\n+\t\tassertEquals(exp, RawParseUtils.decode(out.toByteArray()));\n+\t}\n+\n+\tprivate byte[] readFile(final String patchFile) throws IOException {\n+\t\tfinal InputStream in = getClass().getResourceAsStream(patchFile);\n+\t\tif (in == null) {\n+\t\t\tfail(\"No \" + patchFile + \" test vector\");\n+\t\t\treturn null; // Never happens\n+\t\t}\n+\t\ttry {\n+\t\t\tfinal byte[] buf = new byte[1024];\n+\t\t\tfinal ByteArrayOutputStream temp = new ByteArrayOutputStream();\n+\t\t\tint n;\n+\t\t\twhile ((n = in.read(buf)) > 0)\n+\t\t\t\ttemp.write(buf, 0, n);\n+\t\t\treturn temp.toByteArray();\n+\t\t} finally {\n+\t\t\tin.close();\n+\t\t}\n+\t}\n+\n+\tprivate Patch parseTestPatchFile(final String patchFile) throws IOException {\n+\t\tfinal InputStream in = getClass().getResourceAsStream(patchFile);\n+\t\tif (in == null) {\n+\t\t\tfail(\"No \" + patchFile + \" test vector\");\n+\t\t\treturn null; // Never happens\n+\t\t}\n+\t\ttry {\n+\t\t\tfinal Patch p = new Patch();\n+\t\t\tp.parse(in);\n+\t\t\treturn p;\n+\t\t} finally {\n+\t\t\tin.close();\n+\t\t}\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java b/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\nnew file mode 100644\nindex 0000000..9a81901\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/DiffFormatter.java\n@@ -0,0 +1,214 @@\n+/*\n+ * Copyright (C) 2008, Johannes E. Schindelin <johannes.schindelin@gmx.de>\n+ * Copyright (C) 2009, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.diff;\n+\n+import static org.spearce.jgit.lib.Constants.encodeASCII;\n+\n+import java.io.IOException;\n+import java.io.OutputStream;\n+import java.util.List;\n+\n+import org.spearce.jgit.patch.FileHeader;\n+\n+/**\n+ * Format an {@link EditList} as a Git style unified patch script.\n+ */\n+public class DiffFormatter {\n+\tprivate static final byte[] noNewLine = encodeASCII(\"\\\\ No newline at end of file\\n\");\n+\n+\tprivate int context;\n+\n+\t/** Create a new formatter with a default level of context. */\n+\tpublic DiffFormatter() {\n+\t\tsetContext(3);\n+\t}\n+\n+\t/**\n+\t * Change the number of lines of context to display.\n+\t * \n+\t * @param lineCount\n+\t *            number of lines of context to see before the first\n+\t *            modification and after the last modification within a hunk of\n+\t *            the modified file.\n+\t */\n+\tpublic void setContext(final int lineCount) {\n+\t\tif (lineCount < 0)\n+\t\t\tthrow new IllegalArgumentException(\"context must be >= 0\");\n+\t\tcontext = lineCount;\n+\t}\n+\n+\t/**\n+\t * Format a patch script, reusing a previously parsed FileHeader.\n+\t * <p>\n+\t * This formatter is primarily useful for editing an existing patch script\n+\t * to increase or reduce the number of lines of context within the script.\n+\t * All header lines are reused as-is from the supplied FileHeader.\n+\t * \n+\t * @param out\n+\t *            stream to write the patch script out to.\n+\t * @param head\n+\t *            existing file header containing the header lines to copy.\n+\t * @param a\n+\t *            text source for the pre-image version of the content. This\n+\t *            must match the content of {@link FileHeader#getOldId()}.\n+\t * @param b\n+\t *            text source for the post-image version of the content. This\n+\t *            must match the content of {@link FileHeader#getNewId()}.\n+\t * @throws IOException\n+\t *             writing to the supplied stream failed.\n+\t */\n+\tpublic void format(final OutputStream out, final FileHeader head,\n+\t\t\tfinal RawText a, final RawText b) throws IOException {\n+\t\t// Reuse the existing FileHeader as-is by blindly copying its\n+\t\t// header lines, but avoiding its hunks. Instead we recreate\n+\t\t// the hunks from the text instances we have been supplied.\n+\t\t//\n+\t\tfinal int start = head.getStartOffset();\n+\t\tint end = head.getEndOffset();\n+\t\tif (!head.getHunks().isEmpty())\n+\t\t\tend = head.getHunks().get(0).getStartOffset();\n+\t\tout.write(head.getBuffer(), start, end - start);\n+\n+\t\tformatEdits(out, a, b, head.toEditList());\n+\t}\n+\n+\tprivate void formatEdits(final OutputStream out, final RawText a,\n+\t\t\tfinal RawText b, final EditList edits) throws IOException {\n+\t\tfor (int curIdx = 0; curIdx < edits.size();) {\n+\t\t\tEdit curEdit = edits.get(curIdx);\n+\t\t\tfinal int endIdx = findCombinedEnd(edits, curIdx);\n+\t\t\tfinal Edit endEdit = edits.get(endIdx);\n+\n+\t\t\tint aCur = Math.max(0, curEdit.getBeginA() - context);\n+\t\t\tint bCur = Math.max(0, curEdit.getBeginB() - context);\n+\t\t\tfinal int aEnd = Math.min(a.size(), endEdit.getEndA() + context);\n+\t\t\tfinal int bEnd = Math.min(b.size(), endEdit.getEndB() + context);\n+\n+\t\t\twriteHunkHeader(out, aCur, aEnd, bCur, bEnd);\n+\n+\t\t\twhile (aCur < aEnd || bCur < bEnd) {\n+\t\t\t\tif (aCur < curEdit.getBeginA() || endIdx + 1 < curIdx) {\n+\t\t\t\t\twriteLine(out, ' ', a, aCur);\n+\t\t\t\t\taCur++;\n+\t\t\t\t\tbCur++;\n+\n+\t\t\t\t} else if (aCur < curEdit.getEndA()) {\n+\t\t\t\t\twriteLine(out, '-', a, aCur++);\n+\n+\t\t\t\t} else if (bCur < curEdit.getEndB()) {\n+\t\t\t\t\twriteLine(out, '+', b, bCur++);\n+\t\t\t\t}\n+\n+\t\t\t\tif (end(curEdit, aCur, bCur) && ++curIdx < edits.size())\n+\t\t\t\t\tcurEdit = edits.get(curIdx);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tprivate void writeHunkHeader(final OutputStream out, int aCur, int aEnd,\n+\t\t\tint bCur, int bEnd) throws IOException {\n+\t\tout.write('@');\n+\t\tout.write('@');\n+\t\twriteRange(out, '-', aCur + 1, aEnd - aCur);\n+\t\twriteRange(out, '+', bCur + 1, bEnd - bCur);\n+\t\tout.write(' ');\n+\t\tout.write('@');\n+\t\tout.write('@');\n+\t\tout.write('\\n');\n+\t}\n+\n+\tprivate static void writeRange(final OutputStream out, final char prefix,\n+\t\t\tfinal int begin, final int cnt) throws IOException {\n+\t\tout.write(' ');\n+\t\tout.write(prefix);\n+\t\tswitch (cnt) {\n+\t\tcase 0:\n+\t\t\t// If the range is empty, its beginning number must be the\n+\t\t\t// line just before the range, or 0 if the range is at the\n+\t\t\t// start of the file stream. Here, begin is always 1 based,\n+\t\t\t// so an empty file would produce \"0,0\".\n+\t\t\t//\n+\t\t\tout.write(encodeASCII(begin - 1));\n+\t\t\tout.write(',');\n+\t\t\tout.write('0');\n+\t\t\tbreak;\n+\n+\t\tcase 1:\n+\t\t\t// If the range is exactly one line, produce only the number.\n+\t\t\t//\n+\t\t\tout.write(encodeASCII(begin));\n+\t\t\tbreak;\n+\n+\t\tdefault:\n+\t\t\tout.write(encodeASCII(begin));\n+\t\t\tout.write(',');\n+\t\t\tout.write(encodeASCII(cnt));\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\n+\tprivate static void writeLine(final OutputStream out, final char prefix,\n+\t\t\tfinal RawText text, final int cur) throws IOException {\n+\t\tout.write(prefix);\n+\t\ttext.writeLine(out, cur);\n+\t\tout.write('\\n');\n+\t\tif (cur + 1 == text.size() && text.isMissingNewlineAtEnd())\n+\t\t\tout.write(noNewLine);\n+\t}\n+\n+\tprivate int findCombinedEnd(final List<Edit> edits, final int i) {\n+\t\tint end = i + 1;\n+\t\twhile (end < edits.size()\n+\t\t\t\t&& (combineA(edits, end) || combineB(edits, end)))\n+\t\t\tend++;\n+\t\treturn end - 1;\n+\t}\n+\n+\tprivate boolean combineA(final List<Edit> e, final int i) {\n+\t\treturn e.get(i).getBeginA() - e.get(i - 1).getEndA() <= 2 * context;\n+\t}\n+\n+\tprivate boolean combineB(final List<Edit> e, final int i) {\n+\t\treturn e.get(i).getBeginB() - e.get(i - 1).getEndB() <= 2 * context;\n+\t}\n+\n+\tprivate static boolean end(final Edit edit, final int a, final int b) {\n+\t\treturn edit.getEndA() <= a && edit.getEndB() <= b;\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java b/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\nindex 1d10082..e10ee46 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/diff/RawText.java\n@@ -140,6 +140,18 @@ public void writeLine(final OutputStream out, final int i)\n \t\tout.write(content, start, end - start);\n \t}\n \n+\t/**\n+\t * Determine if the file ends with a LF ('\\n').\n+\t * \n+\t * @return true if the last line has an LF; false otherwise.\n+\t */\n+\tpublic boolean isMissingNewlineAtEnd() {\n+\t\tfinal int end = lines.get(lines.size() - 1);\n+\t\tif (end == 0)\n+\t\t\treturn true;\n+\t\treturn content[end - 1] != '\\n';\n+\t}\n+\n \tprivate IntList computeHashes() {\n \t\tfinal IntList r = new IntList(lines.size());\n \t\tr.add(0);\n-- \n1.6.3.rc4.190.g4648\n"},{"id":"112908","messageId":"200905030907.02287.robin.rosenberg.lists@dewire.com","threadId":"19153","inReplyTo":"1241230127-28279-2-git-send-email-spearce@spearce.org","subject":"Re: [JGIT PATCH 1/6] Add set to IntList","fromName":"Robin Rosenberg","fromEmail":"robin.rosenberg.lists@dewire.com","sentAt":"2009-05-03T07:07:01Z","receivedAt":"2009-05-03T07:07:01Z","isPatch":true,"sender":{"key":"robin.rosenberg@dewire.com","avatar":"https://avatars.githubusercontent.com/u/46357?v=4"},"body":"lördag 02 maj 2009 04:08:42 skrev \"Shawn O. Pearce\" <spearce@spearce.org>:\n> Some applications may wish to modify an int list.\n> \n> Signed-off-by: Shawn O. Pearce <spearce@spearce.org>\n> ---\n>  .../tst/org/spearce/jgit/util/IntListTest.java     |   21 ++++++++++++++++++++\n>  .../src/org/spearce/jgit/util/IntList.java         |   17 ++++++++++++++++\n>  2 files changed, 38 insertions(+), 0 deletions(-)\n> \n> diff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java\n> index c470d55..ce0d7af 100644\n> --- a/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java\n> +++ b/org.spearce.jgit.test/tst/org/spearce/jgit/util/IntListTest.java\n> @@ -144,6 +144,27 @@ public void testClear() {\n>  \t\t}\n>  \t}\n>  \n> +\tpublic void testSet() {\n> +\t\tfinal IntList i = new IntList();\n> +\t\ti.add(1);\n> +\t\tassertEquals(1, i.size());\n> +\t\tassertEquals(1, i.get(0));\n> +\t\t\n> +\t\ti.set(0, 5);\n> +\t\tassertEquals(5, i.get(0));\n> +\t\t\n> +\t\ttry {\n> +\t\t\ti.set(5, 5);\n> +\t\t\tfail(\"accepted set of 5 beyond end of list\");\n> +\t\t} catch (ArrayIndexOutOfBoundsException e){\n> +\t\t\tassertTrue(true);\n> +\t\t}\n> +\n> +\t\ti.set(1, 2);\nOh, you grow the array here. Not obvious.\n\n> +\t\tassertEquals(2, i.size());\n> +\t\tassertEquals(2, i.get(1));\n> +\t}\n> +\n>  \tpublic void testToString() {\n>  \t\tfinal IntList i = new IntList();\n>  \t\ti.add(1);\n> diff --git a/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java b/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java\n> index 0a84793..9d86a5c 100644\n> --- a/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java\n> +++ b/org.spearce.jgit/src/org/spearce/jgit/util/IntList.java\n> @@ -94,6 +94,23 @@ public void add(final int n) {\n>  \t}\n>  \n>  \t/**\n> +\t * Assign an entry in the list.\n> +\t * \n> +\t * @param index\n> +\t *            index to set, must be in the range [0, {@link #size()}).\n> +\t * @param n\n> +\t *            value to store at the position.\n> +\t */\n> +\tpublic void set(final int index, final int n) {\n> +\t\tif (count < index)\n> +\t\t\tthrow new ArrayIndexOutOfBoundsException(index);\n> +\t\telse if (count == index)\n> +\t\t\tadd(n);\n\nThe interface is quite obscure here. One the one hand it checks for assignment\noutside the set but it does grow the array when only one entry is missing. The\nreader of the code won't see that easily. A different name and reflection of the\nbehaviour in the javadoc is needed. The class javadoc says \"A more efficient \nList<Integer> using a primitive integer array.\" and I know of no java.util.List's \nthat expand implicitly.\n\n-- robin\n"},{"id":"112919","messageId":"alpine.DEB.1.00.0905031623060.18521@pacific.mpi-cbg.de","threadId":"19153","inReplyTo":"1241230127-28279-1-git-send-email-spearce@spearce.org","subject":"Re: [JGIT PATCH 0/6] Diff processing utilities","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-05-03T14:24:52Z","receivedAt":"2009-05-03T14:24:52Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Fri, 1 May 2009, Shawn O. Pearce wrote:\n\n> To be clear, this series *does not* contain a way to create a diff. \n> Dscho wrote much more code which is not yet ready for inclusion.\n\nIndeed.  I'm on it.\n\n> Dscho, can you give us yea-or-nay for SBO lines for the patches\n> I've attributed to you?\n\nYays!\n\n(I had only time to look over them once, but as I am working on the diff \nstuff again, I think I'll be able to find bugs on the go ;-)\n\nMany thanks to you and Robin for finding bugs early!\n\nCiao,\nDscho\n"},{"id":"112983","messageId":"20090504142231.GS23604@spearce.org","threadId":"19153","inReplyTo":"200905030907.02287.robin.rosenberg.lists@dewire.com","subject":"Re: [JGIT PATCH 1/6] Add set to IntList","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-04T14:22:31Z","receivedAt":"2009-05-04T14:22:31Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:\n> l?rdag 02 maj 2009 04:08:42 skrev \"Shawn O. Pearce\" <spearce@spearce.org>:\n> > Some applications may wish to modify an int list.\n\nOK, as it turns out, this is used by code which Dscho wrote but I\nhaven't packaged up as patches yet.  And I don't think that even uses\nthe weird set(size(), ...) expands the list rules I implemented.\nSo drop this patch for now from the series and I'll respin it at\na later date.\n\n> >  .../tst/org/spearce/jgit/util/IntListTest.java     |   21 ++++++++++++++++++++\n> >  .../src/org/spearce/jgit/util/IntList.java         |   17 ++++++++++++++++\n> >  2 files changed, 38 insertions(+), 0 deletions(-)\n\n-- \nShawn.\n"},{"id":"112987","messageId":"alpine.DEB.1.00.0905041649570.5553@intel-tinevez-2-302","threadId":"19153","inReplyTo":"20090504142231.GS23604@spearce.org","subject":"Re: [JGIT PATCH 1/6] Add set to IntList","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-05-04T14:50:41Z","receivedAt":"2009-05-04T14:50:41Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 4 May 2009, Shawn O. Pearce wrote:\n\n> Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:\n> > l?rdag 02 maj 2009 04:08:42 skrev \"Shawn O. Pearce\" <spearce@spearce.org>:\n> > > Some applications may wish to modify an int list.\n> \n> OK, as it turns out, this is used by code which Dscho wrote but I \n> haven't packaged up as patches yet.  And I don't think that even uses \n> the weird set(size(), ...) expands the list rules I implemented. So drop \n> this patch for now from the series and I'll respin it at a later date.\n\nIndeed, my code only needs add(int i), which should expand the array on \ndemand (i.e. after a clear(), it should _not_ blindly resize the array).\n\nCiao,\nDscho\n"},{"id":"112989","messageId":"20090504145506.GV23604@spearce.org","threadId":"19153","inReplyTo":"alpine.DEB.1.00.0905041649570.5553@intel-tinevez-2-302","subject":"Re: [JGIT PATCH 1/6] Add set to IntList","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2009-05-04T14:55:06Z","receivedAt":"2009-05-04T14:55:06Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> On Mon, 4 May 2009, Shawn O. Pearce wrote:\n> \n> > Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:\n> > > l?rdag 02 maj 2009 04:08:42 skrev \"Shawn O. Pearce\" <spearce@spearce.org>:\n> > > > Some applications may wish to modify an int list.\n> > \n> > OK, as it turns out, this is used by code which Dscho wrote but I \n> > haven't packaged up as patches yet.  And I don't think that even uses \n> > the weird set(size(), ...) expands the list rules I implemented. So drop \n> > this patch for now from the series and I'll respin it at a later date.\n> \n> Indeed, my code only needs add(int i), which should expand the array on \n> demand (i.e. after a clear(), it should _not_ blindly resize the array).\n\nReally?  When I was starting to bring your code in and moved from\nIntArray to IntList I had compile errors on set calls, so I added\nit to IntList.\n\nHuh.  Well, add(int) is already there, and clear() resets the size\nto 0 but doesn't resize the internal array, so future adds up to\nthe prior capacity are free.\n\n-- \nShawn.\n"},{"id":"112990","messageId":"alpine.DEB.1.00.0905041709100.5553@intel-tinevez-2-302","threadId":"19153","inReplyTo":"20090504145506.GV23604@spearce.org","subject":"Re: [JGIT PATCH 1/6] Add set to IntList","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2009-05-04T15:10:00Z","receivedAt":"2009-05-04T15:10:00Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Mon, 4 May 2009, Shawn O. Pearce wrote:\n\n> Johannes Schindelin <Johannes.Schindelin@gmx.de> wrote:\n> > On Mon, 4 May 2009, Shawn O. Pearce wrote:\n> > \n> > > Robin Rosenberg <robin.rosenberg.lists@dewire.com> wrote:\n> > > > l?rdag 02 maj 2009 04:08:42 skrev \"Shawn O. Pearce\" \n> > > > <spearce@spearce.org>:\n> > > > > Some applications may wish to modify an int list.\n> > > \n> > > OK, as it turns out, this is used by code which Dscho wrote but I \n> > > haven't packaged up as patches yet.  And I don't think that even uses \n> > > the weird set(size(), ...) expands the list rules I implemented. So drop \n> > > this patch for now from the series and I'll respin it at a later date.\n> > \n> > Indeed, my code only needs add(int i), which should expand the array on \n> > demand (i.e. after a clear(), it should _not_ blindly resize the array).\n> \n> Really?  When I was starting to bring your code in and moved from \n> IntArray to IntList I had compile errors on set calls, so I added it to \n> IntList.\n\nWell, in the code you have, that might be true, but as I promised, I \npicked up work on it again.  And my new version only needs add() ;-)\n\n> Huh.  Well, add(int) is already there, and clear() resets the size\n> to 0 but doesn't resize the internal array, so future adds up to\n> the prior capacity are free.\n\nExactly as it should be!\n\nThanks,\nDscho\n"}]}