// Copyright (C) 2009 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package com.google.gerrit.prettify.common; import org.eclipse.jgit.diff.Edit; import java.util.Iterator; import java.util.List; public class EditList { private final List<Edit> edits; private final int context; private final int aSize; private final int bSize; public EditList(final List<Edit> edits, final int contextLines, final int aSize, final int bSize) { this.edits = edits; this.context = contextLines; this.aSize = aSize; this.bSize = bSize; } public List<Edit> getEdits() { return edits; } public Iterable<Hunk> getHunks() { return new Iterable<Hunk>() { public Iterator<Hunk> iterator() { return new Iterator<Hunk>() { private int curIdx; public boolean hasNext() { return curIdx < edits.size(); } public Hunk next() { final int c = curIdx; final int e = findCombinedEnd(c); curIdx = e + 1; return new Hunk(c, e); } public void remove() { throw new UnsupportedOperationException(); } }; } }; } private int findCombinedEnd(final int i) { int end = i + 1; while (end < edits.size() && (combineA(end) || combineB(end))) end++; return end - 1; } private boolean combineA(final int i) { final Edit s = edits.get(i); final Edit e = edits.get(i - 1); // + 1 to prevent '... skipping 1 common line ...' messages. return s.getBeginA() - e.getEndA() <= 2 * context + 1; } private boolean combineB(final int i) { final int s = edits.get(i).getBeginB(); final int e = edits.get(i - 1).getEndB(); // + 1 to prevent '... skipping 1 common line ...' messages. return s - e <= 2 * context + 1; } public class Hunk { private int curIdx; private Edit curEdit; private final int endIdx; private final Edit endEdit; private int aCur; private int bCur; private final int aEnd; private final int bEnd; private Hunk(final int ci, final int ei) { curIdx = ci; endIdx = ei; curEdit = edits.get(curIdx); endEdit = edits.get(endIdx); aCur = Math.max(0, curEdit.getBeginA() - context); bCur = Math.max(0, curEdit.getBeginB() - context); aEnd = Math.min(aSize, endEdit.getEndA() + context); bEnd = Math.min(bSize, endEdit.getEndB() + context); } public int getCurA() { return aCur; } public int getCurB() { return bCur; } public Edit getCurEdit() { return curEdit; } public int getEndA() { return aEnd; } public int getEndB() { return bEnd; } public void incA() { aCur++; } public void incB() { bCur++; } public void incBoth() { incA(); incB(); } public boolean isStartOfFile() { return aCur == 0 && bCur == 0; } public boolean isContextLine() { return !isModifiedLine(); } public boolean isDeletedA() { return curEdit.getBeginA() <= aCur && aCur < curEdit.getEndA(); } public boolean isInsertedB() { return curEdit.getBeginB() <= bCur && bCur < curEdit.getEndB(); } public boolean isModifiedLine() { return isDeletedA() || isInsertedB(); } public boolean next() { if (!in(curEdit)) { if (curIdx < endIdx) { curEdit = edits.get(++curIdx); } } return aCur < aEnd || bCur < bEnd; } private boolean in(final Edit edit) { return aCur < edit.getEndA() || bCur < edit.getEndB(); } } }