Cleanup CSS for side-by-side view when there are character differences

We no longer have gaps, but instead have a nice contiguous
coloring region.  The visual difference is night-and-day.

Change-Id: I3e80a5860e62472713424dece49a018d584b3b65
Signed-off-by: Shawn O. Pearce <sop@google.com>
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
index 3aedaa2..0ce7356 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/gerrit.css
@@ -28,6 +28,9 @@
 @external .gwt-RadioButton;
 
 @external .smallHeading;
+@external .wdi;
+@external .wdd;
+@external .wdc;
 
 @def black #000000;
 @def white #ffffff;
@@ -514,10 +517,9 @@
   border-spacing: 0;
 }
 .patchContentTable td {
+  padding: 0;
   font-size: 8pt;
   font-family: mono-font;
-  border-top: 1px solid transparent;
-  border-bottom: 1px solid transparent;
 }
 
 .patchContentTable .iconCell {
@@ -570,40 +572,56 @@
   text-align: center;
 }
 
-.patchContentTable .lineNumber {
+.lineNumber {
   padding-left: 0.2em;
   white-space: pre;
   width: 3.5em;
   text-align: right;
   border-right: thin solid #b0bdcc;
   padding-right: 0.2em;
+  background: white;
+  border-bottom: 1px solid white;
 }
-
-.patchContentTable .noLineLineNumber {
+.noLineLineNumber {
   font-family: mono-font;
   width: 3.5em;
   padding-left: 0.2em;
   padding-right: 0.2em;
+  background: white;
+  border-bottom: 1px solid white;
 }
 
-.patchContentTable .fileLine {
+.fileLine {
   padding-left: 0.2em;
   white-space: pre;
   padding-right: 0.2em;
 }
-
 .fileLineNone {
   background: #eeeeee;
+  border-bottom: 1px solid #eeeeee;
 }
-.fileLineDELETE {
+.fileLineDELETE,
+.fileLineDELETE .wdc {
   background: #ffeeee;
+  border-bottom: 1px solid #ffeeee;
 }
 .fileLineCONTEXT {
+  background: white;
+  border-bottom: 1px solid white;
 }
-.fileLineINSERT {
+.fileLineINSERT,
+.fileLineINSERT .wdc {
   background: #ddffdd;
+  border-bottom: 1px solid #ddffdd;
+}
+.patchContentTable .wdd {
+  border-bottom: 1px solid #FAA;
+}
+.patchContentTable .wdi {
+  border-bottom: 1px solid #9F9;
 }
 
+.patchContentTable .skipLine .iconCell,
 .patchContentTable .skipLine {
   font-family: norm-font;
   text-align: center;
@@ -614,14 +632,17 @@
   display: inline;
 }
 
-.patchContentTable .activeRow {
+.patchContentTable .activeRow .iconCell,
+.patchContentTable .activeRow .lineNumber {
   background: #ffffcc;
 }
-.patchContentTable .activeRow td.iconCell,
-.patchContentTable .activeRow td.lineNumber,
-.patchContentTable .activeRow td.fileLine,
-.patchContentTable .activeRow td.diffText {
-  border-top: 1px solid blue;
+.patchContentTable .activeRow .iconCell,
+.patchContentTable .activeRow .lineNumber,
+.patchContentTable .activeRow .fileLine,
+.patchContentTable .activeRow .diffText,
+.patchContentTable .activeRow .wdc,
+.patchContentTable .activeRow .wdd,
+.patchContentTable .activeRow .wdi  {
   border-bottom: 1px solid blue;
 }
 
diff --git a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
index 48c6791..8c66e0c 100644
--- a/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
+++ b/gerrit-gwtui/src/main/java/com/google/gerrit/client/patches/SideBySideTable.java
@@ -90,11 +90,11 @@
         if (hunk.isContextLine()) {
           openLine(nc);
           final SafeHtml ctx = a.getSafeHtmlLine(hunk.getCurA());
-          appendLineText(nc, hunk.getCurA(), CONTEXT, ctx);
+          appendLineText(nc, hunk.getCurA(), CONTEXT, ctx, false);
           if (ignoreWS && b.contains(hunk.getCurB())) {
             appendLineText(nc, hunk.getCurB(), CONTEXT, b, hunk.getCurB());
           } else {
-            appendLineText(nc, hunk.getCurB(), CONTEXT, ctx);
+            appendLineText(nc, hunk.getCurB(), CONTEXT, ctx, false);
           }
           closeLine(nc);
           hunk.incBoth();
@@ -264,6 +264,7 @@
 
     m.openTd();
     m.setStyleName(Gerrit.RESOURCES.css().iconCell());
+    m.addStyleName(Gerrit.RESOURCES.css().skipLine());
     m.closeTd();
 
     m.openTd();
@@ -286,12 +287,13 @@
   private void appendLineText(final SafeHtmlBuilder m,
       final int lineNumberMinusOne, final PatchLine.Type type,
       final SparseHtmlFile src, final int i) {
-    appendLineText(m, lineNumberMinusOne, type, src.getSafeHtmlLine(i));
+    appendLineText(m, lineNumberMinusOne, type, //
+        src.getSafeHtmlLine(i), src.hasTrailingEdit(i));
   }
 
   private void appendLineText(final SafeHtmlBuilder m,
       final int lineNumberMinusOne, final PatchLine.Type type,
-      final SafeHtml lineHtml) {
+      final SafeHtml lineHtml, final boolean trailingEdit) {
     m.openTd();
     m.setStyleName(Gerrit.RESOURCES.css().lineNumber());
     m.append(lineNumberMinusOne + 1);
@@ -305,9 +307,15 @@
         break;
       case DELETE:
         m.addStyleName(Gerrit.RESOURCES.css().fileLineDELETE());
+        if (trailingEdit) {
+          m.addStyleName("wdd");
+        }
         break;
       case INSERT:
         m.addStyleName(Gerrit.RESOURCES.css().fileLineINSERT());
+        if (trailingEdit) {
+          m.addStyleName("wdi");
+        }
         break;
     }
     m.append(lineHtml);
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 f696683..49f71f7 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
@@ -21,7 +21,9 @@
 import org.eclipse.jgit.diff.ReplaceEdit;
 
 import java.util.ArrayList;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 public abstract class PrettyFormatter implements SparseHtmlFile {
   public static abstract class EditFilter {
@@ -70,6 +72,7 @@
   protected EditFilter side;
   protected List<Edit> edits;
   protected PrettySettings settings;
+  protected Set<Integer> trailingEdits;
 
   private int col;
   private int lineIdx;
@@ -89,6 +92,11 @@
     return content.contains(idx);
   }
 
+  @Override
+  public boolean hasTrailingEdit(int idx) {
+    return trailingEdits.contains(idx);
+  }
+
   public void setEditFilter(EditFilter f) {
     side = f;
   }
@@ -110,6 +118,7 @@
   public void format(SparseFileContent src) {
     content = new SparseFileContent();
     content.setSize(src.size());
+    trailingEdits = new HashSet<Integer>();
 
     String html = toHTML(src);
 
@@ -368,23 +377,33 @@
           final Edit edit = charEdits.get(lastIdx);
           final int b = side.getBegin(edit) - lastPos;
           final int e = side.getEnd(edit) - lastPos;
+          final int modLen = Math.min(e, line.length());
 
           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 int cmnLen = Math.min(b, line.length());
+            if (modLen == line.length()) {
+              buf.openSpan();
+              buf.setStyleName("wdc");
+            }
+            buf.append(line.substring(c, cmnLen));
+            if (modLen == line.length()) {
+              buf.closeSpan();
+            }
+            c = cmnLen;
           }
 
-          if (c < e) {
-            final int n = Math.min(e, line.length());
+          if (c < e && c < modLen) {
             buf.openSpan();
             buf.setStyleName(side.getStyleName());
-            buf.append(line.substring(c, n));
+            buf.append(line.substring(c, modLen));
             buf.closeSpan();
-            c = n;
+            if (modLen == line.length()) {
+              trailingEdits.add(index);
+            }
+            c = modLen;
           }
 
           if (e <= c) {
diff --git a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseHtmlFile.java b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseHtmlFile.java
index 27e9c23..ebe0855 100644
--- a/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseHtmlFile.java
+++ b/gerrit-prettify/src/main/java/com/google/gerrit/prettify/common/SparseHtmlFile.java
@@ -24,5 +24,8 @@
   public int size();
 
   /** @return true if the line is valid in this sparse list. */
-  public boolean contains(final int idx);
+  public boolean contains(int idx);
+
+  /** @return true if this line ends in the middle of a character edit span. */
+  public boolean hasTrailingEdit(int idx);
 }