Add links to path view from file diff headers

Change-Id: I4e71dce2db6392739bd8713ccdf819f44de33ad1
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/DiffServlet.java b/gitiles-servlet/src/main/java/com/google/gitiles/DiffServlet.java
index 2a18afb..bf90bf7 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/DiffServlet.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/DiffServlet.java
@@ -104,7 +104,7 @@
       OutputStream out = res.getOutputStream();
       try {
         out.write(html[0].getBytes(Charsets.UTF_8));
-        formatHtmlDiff(out, repo, oldTree, newTree, view.getPathPart());
+        formatHtmlDiff(out, view, repo, oldTree, newTree, view.getPathPart());
         out.write(html[1].getBytes(Charsets.UTF_8));
       } finally {
         out.close();
@@ -138,11 +138,11 @@
     return new String[] {html.substring(0, lt), html.substring(gt + 1)};
   }
 
-  private void formatHtmlDiff(OutputStream out,
+  private void formatHtmlDiff(OutputStream out, GitilesView view,
       Repository repo, AbstractTreeIterator oldTree,
       AbstractTreeIterator newTree, String path)
       throws IOException {
-    DiffFormatter diff = new HtmlDiffFormatter(renderer, out);
+    DiffFormatter diff = new HtmlDiffFormatter(renderer, view, out);
     try {
       if (!path.equals("")) {
         diff.setPathFilter(PathFilter.create(path));
diff --git a/gitiles-servlet/src/main/java/com/google/gitiles/HtmlDiffFormatter.java b/gitiles-servlet/src/main/java/com/google/gitiles/HtmlDiffFormatter.java
index 993197d..98a8be3 100644
--- a/gitiles-servlet/src/main/java/com/google/gitiles/HtmlDiffFormatter.java
+++ b/gitiles-servlet/src/main/java/com/google/gitiles/HtmlDiffFormatter.java
@@ -15,12 +15,15 @@
 package com.google.gitiles;
 
 import static com.google.common.base.Preconditions.checkNotNull;
+import static org.eclipse.jgit.util.QuotedString.GIT_PATH;
 
 import com.google.common.base.Charsets;
 import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.Lists;
 
 import org.apache.commons.lang3.StringEscapeUtils;
 import org.eclipse.jgit.diff.DiffEntry;
+import org.eclipse.jgit.diff.DiffEntry.ChangeType;
 import org.eclipse.jgit.diff.DiffFormatter;
 import org.eclipse.jgit.diff.RawText;
 import org.eclipse.jgit.patch.FileHeader;
@@ -30,6 +33,7 @@
 import java.io.IOException;
 import java.io.OutputStream;
 import java.util.List;
+import java.util.Map;
 
 /** Formats a unified format patch as UTF-8 encoded HTML. */
 final class HtmlDiffFormatter extends DiffFormatter {
@@ -45,17 +49,21 @@
   private static final byte[] LINE_END = "</span>\n".getBytes(Charsets.UTF_8);
 
   private final Renderer renderer;
+  private final GitilesView view;
   private int fileIndex;
+  private DiffEntry entry;
 
-  HtmlDiffFormatter(Renderer renderer, OutputStream out) {
+  HtmlDiffFormatter(Renderer renderer, GitilesView view, OutputStream out) {
     super(out);
     this.renderer = checkNotNull(renderer, "renderer");
+    this.view = checkNotNull(view, "view");
   }
 
   @Override
   public void format(List<? extends DiffEntry> entries) throws IOException {
     for (fileIndex = 0; fileIndex < entries.size(); fileIndex++) {
-      format(entries.get(fileIndex));
+      entry = entries.get(fileIndex);
+      format(entry);
     }
   }
 
@@ -79,21 +87,43 @@
   private void renderHeader(String header)
       throws IOException {
     int lf = header.indexOf('\n');
-    String first;
-    String rest;
-    if (0 <= lf) {
-      first = header.substring(0, lf);
-      rest = header.substring(lf + 1);
+    String rest = 0 <= lf ?  header.substring(lf + 1) : "";
+
+    // Based on DiffFormatter.formatGitDiffFirstHeaderLine.
+    List<Map<String, String>> parts = Lists.newArrayListWithCapacity(3);
+    parts.add(ImmutableMap.of("text", "diff --git"));
+    if (entry.getChangeType() != ChangeType.ADD) {
+      parts.add(ImmutableMap.of(
+          "text", GIT_PATH.quote(getOldPrefix() + entry.getOldPath()),
+          "url", revisionUrl(view.getOldRevision(), entry.getOldPath())));
     } else {
-      first = header;
-      rest = "";
+      parts.add(ImmutableMap.of(
+          "text", GIT_PATH.quote(getOldPrefix() + entry.getNewPath())));
     }
+    if (entry.getChangeType() != ChangeType.DELETE) {
+      parts.add(ImmutableMap.of(
+          "text", GIT_PATH.quote(getNewPrefix() + entry.getNewPath()),
+          "url", revisionUrl(view.getRevision(), entry.getNewPath())));
+    } else {
+      parts.add(ImmutableMap.of(
+          "text", GIT_PATH.quote(getNewPrefix() + entry.getOldPath())));
+    }
+
     getOutputStream().write(renderer.newRenderer("gitiles.diffHeader")
-        .setData(ImmutableMap.of("first", first, "rest", rest, "fileIndex", fileIndex))
+        .setData(ImmutableMap.of("firstParts", parts, "rest", rest, "fileIndex", fileIndex))
         .render()
         .getBytes(Charsets.UTF_8));
   }
 
+  private String revisionUrl(Revision rev, String path) {
+    return GitilesView.path()
+        .copyFrom(view)
+        .setOldRevision(Revision.NULL)
+        .setRevision(Revision.named(rev.getId().name()))
+        .setPathPart(path)
+        .toUrl();
+  }
+
   @Override
   protected void writeHunkHeader(int aStartLine, int aEndLine,
       int bStartLine, int bEndLine) throws IOException {
diff --git a/gitiles-servlet/src/main/resources/com/google/gitiles/templates/DiffDetail.soy b/gitiles-servlet/src/main/resources/com/google/gitiles/templates/DiffDetail.soy
index d888d0a..5222fa0 100644
--- a/gitiles-servlet/src/main/resources/com/google/gitiles/templates/DiffDetail.soy
+++ b/gitiles-servlet/src/main/resources/com/google/gitiles/templates/DiffDetail.soy
@@ -38,13 +38,22 @@
 /**
  * File header for a single unified diff patch.
  *
- * @param first the first line of the header, with no trailing LF.
+ * @param firstParts parts of the first line of the header, with "text" and
+ *     optional "url" fields.
  * @param rest remaining lines of the header, if any.
  * @param fileIndex position of the file within the difference.
  */
 {template .diffHeader}
 <pre class="diff-header">
-<a name="F{$fileIndex}" class="diff-git">{$first}</a>{\n}
+<a name="F{$fileIndex}" class="diff-git"></a>
+{foreach $part in $firstParts}
+  {if not isFirst($part)}{sp}{/if}
+  {if $part.url}
+    <a href="{$part.url}">{$part.text}</a>
+  {else}
+    {$part.text}
+  {/if}
+{/foreach}{\n}
 {$rest}
 </pre>
 {/template}