aboutsummaryrefslogtreecommitdiff
path: root/gerrit-prettify
diff options
context:
space:
mode:
Diffstat (limited to 'gerrit-prettify')
-rw-r--r--gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/EditList.java4
-rw-r--r--gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java197
-rw-r--r--gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java79
3 files changed, 155 insertions, 125 deletions
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/EditList.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/EditList.java
index a96e55e6..d41865a8 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/EditList.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/EditList.java
@@ -37,10 +37,6 @@ public class EditList {
return edits;
}
- public EditList getFullContext() {
- return new EditList(edits, 5000000, aSize, bSize);
- }
-
public Iterable<Hunk> getHunks() {
return new Iterable<Hunk>() {
public Iterator<Hunk> iterator() {
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java
index c00d90a7..f6966837 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/PrettyFormatter.java
@@ -20,27 +20,16 @@ import com.google.gwtexpui.safehtml.client.SafeHtmlBuilder;
import org.eclipse.jgit.diff.Edit;
import org.eclipse.jgit.diff.ReplaceEdit;
+import java.util.ArrayList;
import java.util.List;
public abstract class PrettyFormatter implements SparseHtmlFile {
public static abstract class EditFilter {
- final String get(SparseFileContent src, EditList.Hunk hunk) {
- return src.get(getCur(hunk));
- }
-
abstract String getStyleName();
- abstract int getCur(EditList.Hunk hunk);
-
abstract int getBegin(Edit edit);
abstract int getEnd(Edit edit);
-
- abstract boolean isModified(EditList.Hunk hunk);
-
- abstract void incSelf(EditList.Hunk hunk);
-
- abstract void incOther(EditList.Hunk hunk);
}
public static final EditFilter A = new EditFilter() {
@@ -50,11 +39,6 @@ public abstract class PrettyFormatter implements SparseHtmlFile {
}
@Override
- int getCur(EditList.Hunk hunk) {
- return hunk.getCurA();
- }
-
- @Override
int getBegin(Edit edit) {
return edit.getBeginA();
}
@@ -63,21 +47,6 @@ public abstract class PrettyFormatter implements SparseHtmlFile {
int getEnd(Edit edit) {
return edit.getEndA();
}
-
- @Override
- boolean isModified(EditList.Hunk hunk) {
- return hunk.isDeletedA();
- }
-
- @Override
- void incSelf(EditList.Hunk hunk) {
- hunk.incA();
- }
-
- @Override
- void incOther(EditList.Hunk hunk) {
- hunk.incB();
- }
};
public static final EditFilter B = new EditFilter() {
@@ -87,11 +56,6 @@ public abstract class PrettyFormatter implements SparseHtmlFile {
}
@Override
- int getCur(EditList.Hunk hunk) {
- return hunk.getCurB();
- }
-
- @Override
int getBegin(Edit edit) {
return edit.getBeginB();
}
@@ -100,26 +64,11 @@ public abstract class PrettyFormatter implements SparseHtmlFile {
int getEnd(Edit edit) {
return edit.getEndB();
}
-
- @Override
- boolean isModified(EditList.Hunk hunk) {
- return hunk.isInsertedB();
- }
-
- @Override
- void incSelf(EditList.Hunk hunk) {
- hunk.incB();
- }
-
- @Override
- void incOther(EditList.Hunk hunk) {
- hunk.incA();
- }
};
protected SparseFileContent content;
protected EditFilter side;
- protected EditList edits;
+ protected List<Edit> edits;
protected PrettySettings settings;
private int col;
@@ -144,7 +93,7 @@ public abstract class PrettyFormatter implements SparseHtmlFile {
side = f;
}
- public void setEditList(EditList all) {
+ public void setEditList(List<Edit> all) {
edits = all;
}
@@ -364,88 +313,106 @@ public abstract class PrettyFormatter implements SparseHtmlFile {
}
private SafeHtml colorLineEdits(SparseFileContent src) {
+ // Make a copy of the edits with a sentinel that is after all lines
+ // in the source. That simplifies our loop below because we'll never
+ // run off the end of the edit list.
+ //
+ List<Edit> edits = new ArrayList<Edit>(this.edits.size() + 1);
+ edits.addAll(this.edits);
+ edits.add(new Edit(src.size(), src.size()));
+
SafeHtmlBuilder buf = new SafeHtmlBuilder();
+ int curIdx = 0;
+ Edit curEdit = edits.get(curIdx);
+
ReplaceEdit lastReplace = null;
List<Edit> charEdits = null;
int lastPos = 0;
int lastIdx = 0;
- EditList hunkGenerator = edits;
- if (src.isWholeFile()) {
- hunkGenerator = hunkGenerator.getFullContext();
- }
+ for (int index = src.first(); index < src.size(); index = src.next(index)) {
+ int cmp = compare(index, curEdit);
+ while (0 < cmp) {
+ // The index is after the edit. Skip to the next edit.
+ //
+ curEdit = edits.get(curIdx++);
+ cmp = compare(index, curEdit);
+ }
- for (final EditList.Hunk hunk : hunkGenerator.getHunks()) {
- while (hunk.next()) {
- if (hunk.isContextLine()) {
- if (src.contains(side.getCur(hunk))) {
- // If side is B and src isn't the complete file we can't
- // add it to the buffer here. This can happen if the file
- // was really large and we chose not to syntax highlight.
- //
- buf.append(side.get(src, hunk));
- buf.append('\n');
+ if (cmp < 0) {
+ // index occurs before the edit. This is a line of context.
+ //
+ buf.append(src.get(index));
+ buf.append('\n');
+ continue;
+ }
+
+ // index occurs within the edit. The line is a modification.
+ //
+ if (curEdit instanceof ReplaceEdit) {
+ if (lastReplace != curEdit) {
+ lastReplace = (ReplaceEdit) curEdit;
+ charEdits = lastReplace.getInternalEdits();
+ lastPos = 0;
+ lastIdx = 0;
+ }
+
+ final String line = src.get(index) + "\n";
+ for (int c = 0; c < line.length();) {
+ if (charEdits.size() <= lastIdx) {
+ buf.append(line.substring(c));
+ break;
}
- hunk.incBoth();
- } else if (!side.isModified(hunk)) {
- side.incOther(hunk);
+ final Edit edit = charEdits.get(lastIdx);
+ final int b = side.getBegin(edit) - lastPos;
+ final int e = side.getEnd(edit) - lastPos;
- } else if (hunk.getCurEdit() instanceof ReplaceEdit) {
- if (lastReplace != hunk.getCurEdit()) {
- lastReplace = (ReplaceEdit) hunk.getCurEdit();
- charEdits = lastReplace.getInternalEdits();
- lastPos = 0;
- lastIdx = 0;
+ if (c < b) {
+ // There is text at the start of this line that is common
+ // with the other side. Copy it with no style around it.
+ //
+ final int n = Math.min(b, line.length());
+ buf.append(line.substring(c, n));
+ c = n;
}
- final String line = side.get(src, hunk) + "\n";
- for (int c = 0; c < line.length();) {
- if (charEdits.size() <= lastIdx) {
- buf.append(line.substring(c));
- break;
- }
-
- final Edit edit = charEdits.get(lastIdx);
- final int b = side.getBegin(edit) - lastPos;
- final int e = side.getEnd(edit) - lastPos;
-
- if (c < b) {
- // There is text at the start of this line that is common
- // with the other side. Copy it with no style around it.
- //
- final int n = Math.min(b, line.length());
- buf.append(line.substring(c, n));
- c = n;
- }
-
- if (c < e) {
- final int n = Math.min(e, line.length());
- buf.openSpan();
- buf.setStyleName(side.getStyleName());
- buf.append(line.substring(c, n));
- buf.closeSpan();
- c = n;
- }
-
- if (e <= c) {
- lastIdx++;
- }
+ if (c < e) {
+ final int n = Math.min(e, line.length());
+ buf.openSpan();
+ buf.setStyleName(side.getStyleName());
+ buf.append(line.substring(c, n));
+ buf.closeSpan();
+ c = n;
}
- lastPos += line.length();
- side.incSelf(hunk);
- } else {
- buf.append(side.get(src, hunk));
- buf.append('\n');
- side.incSelf(hunk);
+ if (e <= c) {
+ lastIdx++;
+ }
}
+ lastPos += line.length();
+
+ } else {
+ buf.append(src.get(index));
+ buf.append('\n');
}
}
return buf;
}
+ private int compare(int index, Edit edit) {
+ if (index < side.getBegin(edit)) {
+ return -1; // index occurs before the edit.
+
+ } else if (index < side.getEnd(edit)) {
+ return 0; // index occurs within the edit.
+
+ } else {
+ return 1; // index occurs after the edit.
+ }
+ }
+
private SafeHtml showTabAfterSpace(SafeHtml src) {
final String m = "( ( |<span[^>]*>|</span>)*\t)";
final String r = "<span class=\"wse\">$1</span>";
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
index 2db187f8..a88ebf7b 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseFileContent.java
@@ -14,6 +14,8 @@
package com.google.gerrit.prettify.common;
+import org.eclipse.jgit.diff.Edit;
+
import java.util.ArrayList;
import java.util.List;
@@ -78,6 +80,64 @@ public class SparseFileContent {
return getLine(idx) != null;
}
+ public int first() {
+ return ranges.isEmpty() ? size() : ranges.get(0).base;
+ }
+
+ public int next(final int idx) {
+ // Most requests are sequential in nature, fetching the next
+ // line from the current range, or the immediate next range.
+ //
+ int high = ranges.size();
+ if (currentRangeIdx < high) {
+ Range cur = ranges.get(currentRangeIdx);
+ if (cur.contains(idx + 1)) {
+ return idx + 1;
+ }
+
+ if (++currentRangeIdx < high) {
+ // Its not plus one, its the base of the next range.
+ //
+ return ranges.get(currentRangeIdx).base;
+ }
+ }
+
+ // Binary search for the current value, since we know its a sorted list.
+ //
+ int low = 0;
+ do {
+ final int mid = (low + high) / 2;
+ final Range cur = ranges.get(mid);
+
+ if (cur.contains(idx)) {
+ if (cur.contains(idx + 1)) {
+ // Trivial plus one case above failed due to wrong currentRangeIdx.
+ // Reset the cache so we don't miss in the future.
+ //
+ currentRangeIdx = mid;
+ return idx + 1;
+ }
+
+ if (mid + 1 < ranges.size()) {
+ // Its the base of the next range.
+ currentRangeIdx = mid + 1;
+ return ranges.get(currentRangeIdx).base;
+ }
+
+ // No more lines in the file.
+ //
+ return size();
+ }
+
+ if (idx < cur.base)
+ high = mid;
+ else
+ low = mid + 1;
+ } while (low < high);
+
+ return size();
+ }
+
public int mapIndexToLine(int arrayIndex) {
final int origIndex = arrayIndex;
for (Range r : ranges) {
@@ -155,19 +215,26 @@ public class SparseFileContent {
return b.toString();
}
- public SparseFileContent completeWithContext(SparseFileContent a,
- EditList editList) {
+ public SparseFileContent apply(SparseFileContent a, List<Edit> edits) {
+ EditList list = new EditList(edits, size, a.size(), size);
ArrayList<String> lines = new ArrayList<String>(size);
- for (final EditList.Hunk hunk : editList.getFullContext().getHunks()) {
+ for (final EditList.Hunk hunk : list.getHunks()) {
while (hunk.next()) {
if (hunk.isContextLine()) {
- lines.add(a.get(hunk.getCurA()));
+ if (contains(hunk.getCurB())) {
+ lines.add(get(hunk.getCurB()));
+ } else {
+ lines.add(a.get(hunk.getCurA()));
+ }
hunk.incBoth();
+ continue;
+ }
- } else if (hunk.isDeletedA()) {
+ if (hunk.isDeletedA()) {
hunk.incA();
+ }
- } else if (hunk.isInsertedB()) {
+ if (hunk.isInsertedB()) {
lines.add(get(hunk.getCurB()));
hunk.incB();
}