• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.dumprendertree2;
18 
19 import name.fraser.neil.plaintext.diff_match_patch;
20 
21 import java.util.LinkedList;
22 
23 /**
24  * Helper methods fo TextResult.getDiffAsHtml()
25  */
26 public class VisualDiffUtils {
27 
28     private static final int DONT_PRINT_LINE_NUMBER = -1;
29 
30     /**
31      * Preprocesses the list of diffs so that new line characters appear only at the end of
32      * diff.text
33      *
34      * @param diffs
35      * @return
36      *      LinkedList of diffs where new line character appears only on the end of
37      *      diff.text
38      */
splitDiffsOnNewline( LinkedList<diff_match_patch.Diff> diffs)39     public static LinkedList<diff_match_patch.Diff> splitDiffsOnNewline(
40             LinkedList<diff_match_patch.Diff> diffs) {
41         LinkedList<diff_match_patch.Diff> newDiffs = new LinkedList<diff_match_patch.Diff>();
42 
43         String[] parts;
44         int lengthMinusOne;
45         for (diff_match_patch.Diff diff : diffs) {
46             parts = diff.text.split("\n", -1);
47             if (parts.length == 1) {
48                 newDiffs.add(diff);
49                 continue;
50             }
51 
52             lengthMinusOne = parts.length - 1;
53             for (int i = 0; i < lengthMinusOne; i++) {
54                 newDiffs.add(new diff_match_patch.Diff(diff.operation, parts[i] + "\n"));
55             }
56             if (!parts[lengthMinusOne].isEmpty()) {
57                 newDiffs.add(new diff_match_patch.Diff(diff.operation, parts[lengthMinusOne]));
58             }
59         }
60 
61         return newDiffs;
62     }
63 
generateExpectedResultLines(LinkedList<diff_match_patch.Diff> diffs, LinkedList<Integer> lineNums, LinkedList<String> lines)64     public static void generateExpectedResultLines(LinkedList<diff_match_patch.Diff> diffs,
65             LinkedList<Integer> lineNums, LinkedList<String> lines) {
66         String delSpan = "<span class=\"del\">";
67         String eqlSpan = "<span class=\"eql\">";
68 
69         String line = "";
70         int i = 1;
71         diff_match_patch.Diff diff;
72         int size = diffs.size();
73         boolean isLastDiff;
74         for (int j = 0; j < size; j++) {
75             diff = diffs.get(j);
76             isLastDiff = j == size - 1;
77             switch (diff.operation) {
78                 case DELETE:
79                     line = processDiff(diff, lineNums, lines, line, i, delSpan, isLastDiff);
80                     if (line.equals("")) {
81                         i++;
82                     }
83                     break;
84 
85                 case INSERT:
86                     // If the line is currently empty and this insertion is the entire line, the
87                     // expected line is absent, so it has no line number.
88                     if (diff.text.endsWith("\n") || isLastDiff) {
89                         lineNums.add(line.equals("") ? DONT_PRINT_LINE_NUMBER : i++);
90                         lines.add(line);
91                         line = "";
92                     }
93                     break;
94 
95                 case EQUAL:
96                     line = processDiff(diff, lineNums, lines, line, i, eqlSpan, isLastDiff);
97                     if (line.equals("")) {
98                         i++;
99                     }
100                     break;
101             }
102         }
103     }
104 
generateActualResultLines(LinkedList<diff_match_patch.Diff> diffs, LinkedList<Integer> lineNums, LinkedList<String> lines)105     public static void generateActualResultLines(LinkedList<diff_match_patch.Diff> diffs,
106             LinkedList<Integer> lineNums, LinkedList<String> lines) {
107         String insSpan = "<span class=\"ins\">";
108         String eqlSpan = "<span class=\"eql\">";
109 
110         String line = "";
111         int i = 1;
112         diff_match_patch.Diff diff;
113         int size = diffs.size();
114         boolean isLastDiff;
115         for (int j = 0; j < size; j++) {
116             diff = diffs.get(j);
117             isLastDiff = j == size - 1;
118             switch (diff.operation) {
119                 case INSERT:
120                     line = processDiff(diff, lineNums, lines, line, i, insSpan, isLastDiff);
121                     if (line.equals("")) {
122                         i++;
123                     }
124                     break;
125 
126                 case DELETE:
127                     // If the line is currently empty and deletion is the entire line, the
128                     // actual line is absent, so it has no line number.
129                     if (diff.text.endsWith("\n") || isLastDiff) {
130                         lineNums.add(line.equals("") ? DONT_PRINT_LINE_NUMBER : i++);
131                         lines.add(line);
132                         line = "";
133                     }
134                     break;
135 
136                 case EQUAL:
137                     line = processDiff(diff, lineNums, lines, line, i, eqlSpan, isLastDiff);
138                     if (line.equals("")) {
139                         i++;
140                     }
141                     break;
142             }
143         }
144     }
145 
146     /**
147      * Generate or append a line for a given diff and add it to given collections if necessary.
148      * It puts diffs in HTML spans.
149      *
150      * @param diff
151      * @param lineNums
152      * @param lines
153      * @param line
154      * @param i
155      * @param begSpan
156      * @param forceOutputLine Force the current line to be output
157      * @return
158      */
processDiff(diff_match_patch.Diff diff, LinkedList<Integer> lineNums, LinkedList<String> lines, String line, int i, String begSpan, boolean forceOutputLine)159     public static String processDiff(diff_match_patch.Diff diff, LinkedList<Integer> lineNums,
160             LinkedList<String> lines, String line, int i, String begSpan, boolean forceOutputLine) {
161         String endSpan = "</span>";
162         String br = "&nbsp;";
163 
164         if (diff.text.endsWith("\n") || forceOutputLine) {
165             lineNums.add(i);
166             /** TODO: Think of better way to replace stuff */
167             line += begSpan + diff.text.replace("  ", "&nbsp;&nbsp;")
168                     + endSpan + br;
169             lines.add(line);
170             line = "";
171         } else {
172             line += begSpan + diff.text.replace("  ", "&nbsp;&nbsp;") + endSpan;
173         }
174 
175         return line;
176     }
177 
getHtml(LinkedList<Integer> lineNums1, LinkedList<String> lines1, LinkedList<Integer> lineNums2, LinkedList<String> lines2)178     public static String getHtml(LinkedList<Integer> lineNums1, LinkedList<String> lines1,
179             LinkedList<Integer> lineNums2, LinkedList<String> lines2) {
180         StringBuilder html = new StringBuilder();
181         int lineNum;
182         int size = lines1.size();
183         for (int i = 0; i < size; i++) {
184             html.append("<tr class=\"results\">");
185 
186             html.append("    <td class=\"line_count\">");
187             lineNum = lineNums1.removeFirst();
188             if (lineNum > 0) {
189                 html.append(lineNum);
190             }
191             html.append("    </td>");
192 
193             html.append("    <td class=\"line\">");
194             html.append(lines1.removeFirst());
195             html.append("    </td>");
196 
197             html.append("    <td class=\"space\"></td>");
198 
199             html.append("    <td class=\"line_count\">");
200             lineNum = lineNums2.removeFirst();
201             if (lineNum > 0) {
202                 html.append(lineNum);
203             }
204             html.append("    </td>");
205 
206             html.append("    <td class=\"line\">");
207             html.append(lines2.removeFirst());
208             html.append("    </td>");
209 
210             html.append("</tr>");
211         }
212         return html.toString();
213     }
214 }
215