com.google.gitiles.HtmlDiffFormatter.java Source code

Java tutorial

Introduction

Here is the source code for com.google.gitiles.HtmlDiffFormatter.java

Source

// Copyright 2012 Google Inc. All Rights Reserved.
//
// 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.gitiles;

import static com.google.common.base.Preconditions.checkNotNull;

import com.google.common.base.Charsets;
import com.google.common.collect.ImmutableMap;

import org.apache.commons.lang3.StringEscapeUtils;
import org.eclipse.jgit.diff.DiffEntry;
import org.eclipse.jgit.diff.DiffFormatter;
import org.eclipse.jgit.diff.RawText;
import org.eclipse.jgit.patch.FileHeader;
import org.eclipse.jgit.patch.FileHeader.PatchType;
import org.eclipse.jgit.util.RawParseUtils;

import java.io.IOException;
import java.io.OutputStream;
import java.util.List;

/** Formats a unified format patch as UTF-8 encoded HTML. */
final class HtmlDiffFormatter extends DiffFormatter {
    private static final byte[] DIFF_BEGIN = "<pre class=\"diff-unified\">".getBytes(Charsets.UTF_8);
    private static final byte[] DIFF_END = "</pre>".getBytes(Charsets.UTF_8);

    private static final byte[] HUNK_BEGIN = "<span class=\"h\">".getBytes(Charsets.UTF_8);
    private static final byte[] HUNK_END = "</span>".getBytes(Charsets.UTF_8);

    private static final byte[] LINE_INSERT_BEGIN = "<span class=\"i\">".getBytes(Charsets.UTF_8);
    private static final byte[] LINE_DELETE_BEGIN = "<span class=\"d\">".getBytes(Charsets.UTF_8);
    private static final byte[] LINE_CHANGE_BEGIN = "<span class=\"c\">".getBytes(Charsets.UTF_8);
    private static final byte[] LINE_END = "</span>\n".getBytes(Charsets.UTF_8);

    private final Renderer renderer;
    private int fileIndex;

    HtmlDiffFormatter(Renderer renderer, OutputStream out) {
        super(out);
        this.renderer = checkNotNull(renderer, "renderer");
    }

    @Override
    public void format(List<? extends DiffEntry> entries) throws IOException {
        for (fileIndex = 0; fileIndex < entries.size(); fileIndex++) {
            format(entries.get(fileIndex));
        }
    }

    @Override
    public void format(FileHeader hdr, RawText a, RawText b) throws IOException {
        int start = hdr.getStartOffset();
        int end = hdr.getEndOffset();
        if (!hdr.getHunks().isEmpty()) {
            end = hdr.getHunks().get(0).getStartOffset();
        }
        renderHeader(RawParseUtils.decode(hdr.getBuffer(), start, end));

        if (hdr.getPatchType() == PatchType.UNIFIED) {
            getOutputStream().write(DIFF_BEGIN);
            format(hdr.toEditList(), a, b);
            getOutputStream().write(DIFF_END);
        }
    }

    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);
        } else {
            first = header;
            rest = "";
        }
        getOutputStream().write(renderer.newRenderer("gitiles.diffHeader")
                .setData(ImmutableMap.of("first", first, "rest", rest, "fileIndex", fileIndex)).render()
                .getBytes(Charsets.UTF_8));
    }

    @Override
    protected void writeHunkHeader(int aStartLine, int aEndLine, int bStartLine, int bEndLine) throws IOException {
        getOutputStream().write(HUNK_BEGIN);
        // TODO(sop): If hunk header starts including method names, escape it.
        super.writeHunkHeader(aStartLine, aEndLine, bStartLine, bEndLine);
        getOutputStream().write(HUNK_END);
    }

    @Override
    protected void writeLine(char prefix, RawText text, int cur) throws IOException {
        // Manually render each line, rather than invoke a Soy template. This method
        // can be called thousands of times in a single request. Avoid unnecessary
        // overheads by formatting as-is.
        OutputStream out = getOutputStream();
        switch (prefix) {
        case '+':
            out.write(LINE_INSERT_BEGIN);
            break;
        case '-':
            out.write(LINE_DELETE_BEGIN);
            break;
        case ' ':
        default:
            out.write(LINE_CHANGE_BEGIN);
            break;
        }
        out.write(StringEscapeUtils.escapeHtml4(text.getString(cur)).getBytes(Charsets.UTF_8));
        out.write(LINE_END);
    }
}