/* * Copyright (C) 2010 The Android Open Source Project * * 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.android.dumprendertree2; import name.fraser.neil.plaintext.diff_match_patch; import java.util.LinkedList; /** * Helper methods fo TextResult.getDiffAsHtml() */ public class VisualDiffUtils { private static final int DONT_PRINT_LINE_NUMBER = -1; /** * Preprocesses the list of diffs so that new line characters appear only at the end of * diff.text * * @param diffs * @return * LinkedList of diffs where new line character appears only on the end of * diff.text */ public static LinkedList splitDiffsOnNewline( LinkedList diffs) { LinkedList newDiffs = new LinkedList(); String[] parts; int lengthMinusOne; for (diff_match_patch.Diff diff : diffs) { parts = diff.text.split("\n", -1); if (parts.length == 1) { newDiffs.add(diff); continue; } lengthMinusOne = parts.length - 1; for (int i = 0; i < lengthMinusOne; i++) { newDiffs.add(new diff_match_patch.Diff(diff.operation, parts[i] + "\n")); } if (!parts[lengthMinusOne].isEmpty()) { newDiffs.add(new diff_match_patch.Diff(diff.operation, parts[lengthMinusOne])); } } return newDiffs; } public static void generateExpectedResultLines(LinkedList diffs, LinkedList lineNums, LinkedList lines) { String delSpan = ""; String eqlSpan = ""; String line = ""; int i = 1; diff_match_patch.Diff diff; int size = diffs.size(); boolean isLastDiff; for (int j = 0; j < size; j++) { diff = diffs.get(j); isLastDiff = j == size - 1; switch (diff.operation) { case DELETE: line = processDiff(diff, lineNums, lines, line, i, delSpan, isLastDiff); if (line.equals("")) { i++; } break; case INSERT: // If the line is currently empty and this insertion is the entire line, the // expected line is absent, so it has no line number. if (diff.text.endsWith("\n") || isLastDiff) { lineNums.add(line.equals("") ? DONT_PRINT_LINE_NUMBER : i++); lines.add(line); line = ""; } break; case EQUAL: line = processDiff(diff, lineNums, lines, line, i, eqlSpan, isLastDiff); if (line.equals("")) { i++; } break; } } } public static void generateActualResultLines(LinkedList diffs, LinkedList lineNums, LinkedList lines) { String insSpan = ""; String eqlSpan = ""; String line = ""; int i = 1; diff_match_patch.Diff diff; int size = diffs.size(); boolean isLastDiff; for (int j = 0; j < size; j++) { diff = diffs.get(j); isLastDiff = j == size - 1; switch (diff.operation) { case INSERT: line = processDiff(diff, lineNums, lines, line, i, insSpan, isLastDiff); if (line.equals("")) { i++; } break; case DELETE: // If the line is currently empty and deletion is the entire line, the // actual line is absent, so it has no line number. if (diff.text.endsWith("\n") || isLastDiff) { lineNums.add(line.equals("") ? DONT_PRINT_LINE_NUMBER : i++); lines.add(line); line = ""; } break; case EQUAL: line = processDiff(diff, lineNums, lines, line, i, eqlSpan, isLastDiff); if (line.equals("")) { i++; } break; } } } /** * Generate or append a line for a given diff and add it to given collections if necessary. * It puts diffs in HTML spans. * * @param diff * @param lineNums * @param lines * @param line * @param i * @param begSpan * @param forceOutputLine Force the current line to be output * @return */ public static String processDiff(diff_match_patch.Diff diff, LinkedList lineNums, LinkedList lines, String line, int i, String begSpan, boolean forceOutputLine) { String endSpan = ""; String br = " "; if (diff.text.endsWith("\n") || forceOutputLine) { lineNums.add(i); /** TODO: Think of better way to replace stuff */ line += begSpan + diff.text.replace(" ", "  ") + endSpan + br; lines.add(line); line = ""; } else { line += begSpan + diff.text.replace(" ", "  ") + endSpan; } return line; } public static String getHtml(LinkedList lineNums1, LinkedList lines1, LinkedList lineNums2, LinkedList lines2) { StringBuilder html = new StringBuilder(); int lineNum; int size = lines1.size(); for (int i = 0; i < size; i++) { html.append(""); html.append(" "); lineNum = lineNums1.removeFirst(); if (lineNum > 0) { html.append(lineNum); } html.append(" "); html.append(" "); html.append(lines1.removeFirst()); html.append(" "); html.append(" "); html.append(" "); lineNum = lineNums2.removeFirst(); if (lineNum > 0) { html.append(lineNum); } html.append(" "); html.append(" "); html.append(lines2.removeFirst()); html.append(" "); html.append(""); } return html.toString(); } }