16d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski/*
26d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * Copyright (C) 2010 The Android Open Source Project
36d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski *
46d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * Licensed under the Apache License, Version 2.0 (the "License");
56d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * you may not use this file except in compliance with the License.
66d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * You may obtain a copy of the License at
76d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski *
86d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski *      http://www.apache.org/licenses/LICENSE-2.0
96d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski *
106d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * Unless required by applicable law or agreed to in writing, software
116d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * distributed under the License is distributed on an "AS IS" BASIS,
126d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * See the License for the specific language governing permissions and
146d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * limitations under the License.
156d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski */
166d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
176d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowskipackage com.android.dumprendertree2;
186d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
196d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowskiimport name.fraser.neil.plaintext.diff_match_patch;
206d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
216d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowskiimport java.util.LinkedList;
226d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
236d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski/**
246d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski * Helper methods fo TextResult.getDiffAsHtml()
256d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski */
266d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowskipublic class VisualDiffUtils {
276d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
286d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    private static final int DONT_PRINT_LINE_NUMBER = -1;
296d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
306d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    /**
316d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * Preprocesses the list of diffs so that new line characters appear only at the end of
326d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * diff.text
336d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     *
346d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * @param diffs
356d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * @return
366d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     *      LinkedList of diffs where new line character appears only on the end of
376d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     *      diff.text
386d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     */
396d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    public static LinkedList<diff_match_patch.Diff> splitDiffsOnNewline(
406d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            LinkedList<diff_match_patch.Diff> diffs) {
416d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        LinkedList<diff_match_patch.Diff> newDiffs = new LinkedList<diff_match_patch.Diff>();
426d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
436d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        String[] parts;
446d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        int lengthMinusOne;
456d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        for (diff_match_patch.Diff diff : diffs) {
466d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            parts = diff.text.split("\n", -1);
476d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            if (parts.length == 1) {
486d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                newDiffs.add(diff);
496d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                continue;
506d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            }
516d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
526d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            lengthMinusOne = parts.length - 1;
536d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            for (int i = 0; i < lengthMinusOne; i++) {
546d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                newDiffs.add(new diff_match_patch.Diff(diff.operation, parts[i] + "\n"));
556d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            }
566d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            if (!parts[lengthMinusOne].isEmpty()) {
576d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                newDiffs.add(new diff_match_patch.Diff(diff.operation, parts[lengthMinusOne]));
586d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            }
596d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        }
606d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
616d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        return newDiffs;
626d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    }
636d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
646d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    public static void generateExpectedResultLines(LinkedList<diff_match_patch.Diff> diffs,
656d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            LinkedList<Integer> lineNums, LinkedList<String> lines) {
666d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        String delSpan = "<span class=\"del\">";
676d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        String eqlSpan = "<span class=\"eql\">";
686d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
696d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        String line = "";
706d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        int i = 1;
71856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block        diff_match_patch.Diff diff;
72856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block        int size = diffs.size();
73856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block        boolean isLastDiff;
74856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block        for (int j = 0; j < size; j++) {
75856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block            diff = diffs.get(j);
76856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block            isLastDiff = j == size - 1;
776d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            switch (diff.operation) {
786d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                case DELETE:
79856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    line = processDiff(diff, lineNums, lines, line, i, delSpan, isLastDiff);
806d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    if (line.equals("")) {
816d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                        i++;
826d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    }
836d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    break;
846d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
856d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                case INSERT:
86856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    // If the line is currently empty and this insertion is the entire line, the
87856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    // expected line is absent, so it has no line number.
88856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    if (diff.text.endsWith("\n") || isLastDiff) {
89856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                        lineNums.add(line.equals("") ? DONT_PRINT_LINE_NUMBER : i++);
90856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                        lines.add(line);
91856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                        line = "";
926d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    }
936d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    break;
946d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
956d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                case EQUAL:
96856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    line = processDiff(diff, lineNums, lines, line, i, eqlSpan, isLastDiff);
976d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    if (line.equals("")) {
986d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                        i++;
996d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    }
1006d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    break;
1016d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            }
1026d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        }
1036d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    }
1046d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1056d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    public static void generateActualResultLines(LinkedList<diff_match_patch.Diff> diffs,
1066d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            LinkedList<Integer> lineNums, LinkedList<String> lines) {
1076d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        String insSpan = "<span class=\"ins\">";
1086d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        String eqlSpan = "<span class=\"eql\">";
1096d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1106d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        String line = "";
1116d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        int i = 1;
112856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block        diff_match_patch.Diff diff;
113856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block        int size = diffs.size();
114856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block        boolean isLastDiff;
115856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block        for (int j = 0; j < size; j++) {
116856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block            diff = diffs.get(j);
117856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block            isLastDiff = j == size - 1;
1186d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            switch (diff.operation) {
1196d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                case INSERT:
120856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    line = processDiff(diff, lineNums, lines, line, i, insSpan, isLastDiff);
1216d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    if (line.equals("")) {
1226d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                        i++;
1236d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    }
1246d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    break;
1256d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1266d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                case DELETE:
127856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    // If the line is currently empty and deletion is the entire line, the
128856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    // actual line is absent, so it has no line number.
129856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    if (diff.text.endsWith("\n") || isLastDiff) {
130856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                        lineNums.add(line.equals("") ? DONT_PRINT_LINE_NUMBER : i++);
131856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                        lines.add(line);
132856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                        line = "";
1336d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    }
1346d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    break;
1356d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1366d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                case EQUAL:
137856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block                    line = processDiff(diff, lineNums, lines, line, i, eqlSpan, isLastDiff);
1386d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    if (line.equals("")) {
1396d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                        i++;
1406d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    }
1416d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    break;
1426d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            }
1436d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        }
1446d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    }
1456d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1466d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    /**
1476d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * Generate or append a line for a given diff and add it to given collections if necessary.
1486d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * It puts diffs in HTML spans.
1496d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     *
1506d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * @param diff
1516d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * @param lineNums
1526d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * @param lines
1536d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * @param line
1546d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * @param i
1556d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * @param begSpan
156856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block     * @param forceOutputLine Force the current line to be output
1576d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     * @return
1586d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski     */
1596d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    public static String processDiff(diff_match_patch.Diff diff, LinkedList<Integer> lineNums,
160856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block            LinkedList<String> lines, String line, int i, String begSpan, boolean forceOutputLine) {
1616d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        String endSpan = "</span>";
1626d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        String br = "&nbsp;";
1636d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
164856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block        if (diff.text.endsWith("\n") || forceOutputLine) {
165856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block            lineNums.add(i);
1666d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            /** TODO: Think of better way to replace stuff */
1676d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            line += begSpan + diff.text.replace("  ", "&nbsp;&nbsp;")
1686d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                    + endSpan + br;
1696d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            lines.add(line);
1706d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            line = "";
1716d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        } else {
1726d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            line += begSpan + diff.text.replace("  ", "&nbsp;&nbsp;") + endSpan;
1736d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        }
1746d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1756d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        return line;
1766d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    }
1776d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1786d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    public static String getHtml(LinkedList<Integer> lineNums1, LinkedList<String> lines1,
1796d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            LinkedList<Integer> lineNums2, LinkedList<String> lines2) {
1806d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        StringBuilder html = new StringBuilder();
1816d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        int lineNum;
1826d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        int size = lines1.size();
1836d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        for (int i = 0; i < size; i++) {
1846d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("<tr class=\"results\">");
1856d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1866d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("    <td class=\"line_count\">");
1876d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            lineNum = lineNums1.removeFirst();
1886d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            if (lineNum > 0) {
1896d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                html.append(lineNum);
1906d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            }
1916d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("    </td>");
1926d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1936d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("    <td class=\"line\">");
1946d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append(lines1.removeFirst());
1956d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("    </td>");
1966d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1976d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("    <td class=\"space\"></td>");
1986d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
1996d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("    <td class=\"line_count\">");
2006d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            lineNum = lineNums2.removeFirst();
2016d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            if (lineNum > 0) {
2026d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski                html.append(lineNum);
2036d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            }
2046d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("    </td>");
2056d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
2066d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("    <td class=\"line\">");
2076d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append(lines2.removeFirst());
2086d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("    </td>");
2096d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski
2106d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski            html.append("</tr>");
2116d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        }
2126d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski        return html.toString();
2136d0dae6a6534a01ee4c58d4f4ee1bf115c82319cMaksymilian Osowski    }
214856f2859e8550c274c7fe3f05b971bf34bdcb525Steve Block}
215