SourceHighlighter.java

    1/*******************************************************************************
    2 * Copyright (c) 2009, 2010 Mountainminds GmbH & Co. KG and Contributors
    3 * All rights reserved. This program and the accompanying materials
    4 * are made available under the terms of the Eclipse Public License v1.0
    5 * which accompanies this distribution, and is available at
    6 * http://www.eclipse.org/legal/epl-v10.html
    7 *
    8 * Contributors:
    9 *    Marc R. Hoffmann - initial API and implementation
   10 *    
   11 * $Id: $
   12 *******************************************************************************/
   13package org.jacoco.report.html;
   14
   15import java.io.BufferedReader;
   16import java.io.IOException;
   17import java.io.Reader;
   18import java.util.Arrays;
   19
   20import org.jacoco.core.analysis.ILines;
   21import org.jacoco.report.html.resources.Styles;
   22
   23/**
   24 * Creates a highlighted output of a source file.
   25 * 
   26 * @author Marc R. Hoffmann
   27 * @version $Revision: $
   28 */
   29public class SourceHighlighter {
   30
   31    /** Number of characters reserved for the line number column */
   32    private static final int LINENR_WIDTH = 5;
   33
   34    private String tabReplacement;
   35
   36    private String lang = "java";
   37
   38    /**
   39     * Creates a new highlighter with default settings.
   40     */
   41    public SourceHighlighter() {
   42        setTabWidth(4);
   43    }
   44
   45    /**
   46     * Specifies the number of spaces that are represented by a single tab.
   47     * Default is 4.
   48     * 
   49     * @param width
   50     *            spaces per tab
   51     */
   52    public void setTabWidth(final int width) {
   53        final char[] blanks = new char[width];
   54        Arrays.fill(blanks, ' ');
   55        tabReplacement = new String(blanks);
   56    }
   57
   58    /**
   59     * Specifies the source language. This value might be used for syntax
   60     * highlighting. Default is "java".
   61     * 
   62     * @param lang
   63     *            source language identifier
   64     */
   65    public void setLanguage(final String lang) {
   66        this.lang = lang;
   67    }
   68
   69    /**
   70     * Highlights the given source file.
   71     * 
   72     * @param parent
   73     *            parent HTML element
   74     * @param lines
   75     *            highlighting information
   76     * @param contents
   77     *            contents of the source file
   78     * @throws IOException
   79     *             problems while reading the source file or writing the output
   80     */
   81    public void render(final HTMLElement parent, final ILines lines,
   82            final Reader contents) throws IOException {
   83        final HTMLElement pre = parent.pre(Styles.SOURCE + " lang-" + lang);
   84        final BufferedReader lineBuffer = new BufferedReader(contents);
   85        String line;
   86        int nr = 0;
   87        while ((line = lineBuffer.readLine()) != null) {
   88            nr++;
   89            renderLineNr(pre, nr);
   90            renderCodeLine(pre, line, lines.getStatus(nr));
   91        }
   92    }
   93
   94    private void renderLineNr(final HTMLElement pre, final int nr)
   95            throws IOException {
   96        final String linestr = String.valueOf(nr);
   97        final HTMLElement linespan = pre.span(Styles.NR, "L" + linestr);
   98        for (int i = linestr.length(); i < LINENR_WIDTH; i++) {
   99            linespan.text("\u00A0"); // non-breaking space
  100        }
  101        linespan.text(linestr);
  102    }
  103
  104    private void renderCodeLine(final HTMLElement pre, final String line,
  105            final int status) throws IOException {
  106        final String lineWithoutTabs = line.replace("\t", tabReplacement);
  107        switch (status) {
  108        case ILines.NOT_COVERED:
  109            pre.span(Styles.NOT_COVERED).text(lineWithoutTabs);
  110            break;
  111        case ILines.FULLY_COVERED:
  112            pre.span(Styles.FULLY_COVERED).text(lineWithoutTabs);
  113            break;
  114        case ILines.PARTLY_COVERED:
  115            pre.span(Styles.PARTLY_COVERED).text(lineWithoutTabs);
  116            break;
  117        default:
  118            pre.text(lineWithoutTabs);
  119        }
  120        pre.text("\n");
  121    }
  122
  123}