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