Line data Source code
1 :
2 : #include "InlineJSONFormatter.h"
3 : #include <iomanip>
4 :
5 : namespace wikidiff2 {
6 :
7 0 : const char * InlineJSONFormatter::getName()
8 : {
9 0 : return "inlineJSON";
10 : }
11 :
12 11 : void InlineJSONFormatter::printFileHeader()
13 : {
14 11 : result << "{\"diff\": [";
15 11 : }
16 :
17 11 : void InlineJSONFormatter::printFileFooter()
18 : {
19 11 : result << "]}";
20 11 : }
21 :
22 23 : void InlineJSONFormatter::printAdd(const String& line, int leftLine, int rightLine,
23 : int offsetFrom, int offsetTo)
24 : {
25 23 : printAddDelete(line, DiffType::AddLine, toString(rightLine), offsetFrom, offsetTo);
26 23 : }
27 :
28 46 : void InlineJSONFormatter::printDelete(const String& line, int leftLine, int rightLine,
29 : int offsetFrom, int offsetTo)
30 : {
31 46 : printAddDelete(line, DiffType::DeleteLine, "", offsetFrom, offsetTo);
32 46 : }
33 :
34 : /**
35 : * Shared code for printAdd and printDelete
36 : */
37 69 : void InlineJSONFormatter::printAddDelete(const String& line, DiffType diffType, const String& lineNumber,
38 : int offsetFrom, int offsetTo) {
39 69 : if (hasResults)
40 68 : result << ",";
41 :
42 115 : String lineNumberJSON = lineNumber.length() == 0 ? "" : ", \"lineNumber\": " + lineNumber;
43 69 : result << "{\"type\": " << (int)diffType;
44 69 : if (lineNumber.length()) {
45 23 : result << ", \"lineNumber\": " << lineNumber;
46 : }
47 69 : result << ", \"text\": \"";
48 69 : printEscapedJSON(line);
49 69 : result << "\"";
50 69 : appendOffset(offsetFrom, offsetTo);
51 69 : result << "}";
52 :
53 69 : hasResults = true;
54 69 : }
55 :
56 44 : void InlineJSONFormatter::printWordDiff(const WordDiff & worddiff, int leftLine,
57 : int rightLine, int offsetFrom, int offsetTo, bool printLeft, bool printRight,
58 : const String & srcAnchor, const String & dstAnchor, bool moveDirectionDownwards)
59 : {
60 44 : bool moved = printLeft != printRight,
61 44 : isMoveSrc = moved && printLeft;
62 :
63 44 : if (hasResults)
64 37 : result << ",";
65 44 : if (moved) {
66 18 : LinkDirection direction = moveDirectionDownwards ? LinkDirection::Down : LinkDirection::Up;
67 18 : if (isMoveSrc) {
68 9 : result << "{\"type\": " << (int)DiffType::MoveSource
69 : << ", \"moveInfo\": "
70 : << "{\"id\": \"" << srcAnchor << "\", \"linkId\": \"" << dstAnchor
71 9 : << "\", \"linkDirection\": " << (int)direction << "}"
72 9 : << ", \"text\": \"";
73 : } else {
74 9 : result << "{\"type\": " << (int)DiffType::MoveDestination
75 9 : << ", \"lineNumber\": " << rightLine
76 : << ", \"moveInfo\": "
77 : << "{\"id\": \"" << srcAnchor << "\", \"linkId\": \"" << dstAnchor
78 9 : << "\", \"linkDirection\": " << (int)direction << "}"
79 9 : << ", \"text\": \"";
80 : }
81 : } else {
82 26 : result << "{\"type\": " << (int)DiffType::Change
83 26 : << ", \"lineNumber\": " << rightLine
84 26 : << ", \"text\": \"";
85 : }
86 44 : hasResults = true;
87 :
88 44 : unsigned int rangeCalcResult = 0;
89 88 : String ranges;
90 212 : for (unsigned i = 0; i < worddiff.size(); ++i) {
91 168 : const DiffOp<Word> & op = worddiff[i];
92 : unsigned long n;
93 : int j;
94 168 : if (op.op == DiffOp<Word>::copy) {
95 94 : n = op.from.size();
96 1604 : for (j=0; j<n; j++) {
97 1510 : const Word & word = *op.from[j];
98 1510 : rangeCalcResult += word.size();
99 1510 : printEscapedJSON(word);
100 : }
101 74 : } else if (op.op == DiffOp<Word>::del) {
102 15 : n = op.from.size();
103 15 : unsigned int start = rangeCalcResult;
104 15 : unsigned int length = 0;
105 72 : for (j=0; j<n; j++) {
106 57 : const Word & word = *op.from[j];
107 :
108 57 : length += word.size();
109 57 : rangeCalcResult += word.size();
110 57 : printEscapedJSON(word);
111 : }
112 :
113 15 : if (!isMoveSrc) {
114 10 : if (ranges.length() > 1)
115 6 : ranges.append(",");
116 20 : ranges.append("{\"start\": " + toString(start) + ", \"length\": " +
117 40 : toString(length) + ", \"type\": " + toString(HighlightType::Delete) +
118 10 : " }");
119 : }
120 59 : } else if (op.op == DiffOp<Word>::add) {
121 50 : if (isMoveSrc)
122 10 : continue;
123 40 : n = op.to.size();
124 40 : unsigned int start = rangeCalcResult;
125 40 : unsigned int length = 0;
126 150 : for (j=0; j<n; j++) {
127 110 : const Word & word = *op.to[j];
128 :
129 110 : length += word.size();
130 110 : rangeCalcResult += word.size();
131 110 : printEscapedJSON(word);
132 : }
133 :
134 40 : if (ranges.length() > 1)
135 17 : ranges.append(",");
136 80 : ranges.append("{\"start\": " + toString(start) + ", \"length\": " +
137 120 : toString(length) + ", \"type\": " + toString(HighlightType::Add) + " }");
138 :
139 9 : } else if (op.op == DiffOp<Word>::change) {
140 9 : n = op.from.size();
141 9 : unsigned int start = rangeCalcResult;
142 9 : unsigned int length = 0;
143 13047 : for (j=0; j<n; j++) {
144 13038 : const Word & word = *op.from[j];
145 :
146 13038 : length += word.size();
147 13038 : rangeCalcResult += word.size();
148 13038 : printEscapedJSON(word);
149 : }
150 :
151 9 : if (!isMoveSrc) {
152 7 : if (ranges.length() > 1)
153 4 : ranges.append(",");
154 14 : ranges.append("{\"start\": " + toString(start) + ", \"length\": " +
155 28 : toString(length) + ", \"type\": " + toString(HighlightType::Delete) +
156 7 : " }");
157 : }
158 :
159 9 : if (isMoveSrc)
160 2 : continue;
161 7 : n = op.to.size();
162 7 : start = rangeCalcResult;
163 7 : length = 0;
164 12013 : for (j=0; j<n; j++) {
165 12006 : const Word & word = *op.to[j];
166 :
167 12006 : length += word.size();
168 12006 : rangeCalcResult += word.size();
169 :
170 12006 : printEscapedJSON(word);
171 : }
172 :
173 7 : if (ranges.length() > 1)
174 7 : ranges.append(",");
175 14 : ranges.append("{\"start\": " + toString(start) + ", \"length\": " +
176 21 : toString(length) + ", \"type\": " + toString(HighlightType::Add) + " }");
177 : }
178 : }
179 :
180 44 : result << "\"";
181 44 : appendOffset(offsetFrom, offsetTo);
182 44 : if (moved && isMoveSrc) {
183 9 : result << "}";
184 : } else {
185 35 : result << ", \"highlightRanges\": [" << ranges << "]}";
186 : }
187 44 : }
188 :
189 21 : void InlineJSONFormatter::printBlockHeader(int leftLine, int rightLine)
190 : {
191 : //inline diff json not setup to print this
192 21 : }
193 :
194 137 : void InlineJSONFormatter::printContext(const String & input, int leftLine, int rightLine,
195 : int offsetFrom, int offsetTo)
196 : {
197 137 : if (hasResults)
198 134 : result << ",";
199 :
200 137 : result << "{\"type\": " << (int)DiffType::Context
201 137 : << ", \"lineNumber\": " << rightLine << ", \"text\": \"";
202 137 : printEscapedJSON(input);
203 137 : result << "\"";
204 137 : appendOffset(offsetFrom, offsetTo);
205 137 : result << "}";
206 137 : hasResults = true;
207 137 : }
208 :
209 : /**
210 : * Append a String range to the output, escaping it for JSON
211 : */
212 26927 : void InlineJSONFormatter::printEscapedJSON(StringIterator start, StringIterator end) {
213 62278 : for (auto c = start; c != end; c++) {
214 35351 : switch (*c) {
215 15 : case '"': result << "\\\""; break;
216 22 : case '\\': result << "\\\\"; break;
217 0 : case '\b': result << "\\b"; break;
218 2 : case '\f': result << "\\f"; break;
219 0 : case '\n': result << "\\n"; break;
220 1 : case '\r': result << "\\r"; break;
221 1 : case '\t': result << "\\t"; break;
222 35310 : default:
223 35310 : if ('\x00' <= *c && *c <= '\x1f') {
224 0 : char origFill = result.fill();
225 0 : result << "\\u"
226 0 : << std::hex << std::setw(4) << std::setfill('0') << (int)*c
227 0 : << std::setfill(origFill) << std::dec;
228 : } else {
229 35310 : result.put(*c);
230 : }
231 : }
232 : }
233 26927 : }
234 :
235 : /**
236 : * Append current offsets to the output
237 : */
238 250 : void InlineJSONFormatter::appendOffset(int offsetFrom, int offsetTo) {
239 : result << ", \"offset\": {"
240 250 : << "\"from\": ";
241 250 : if (offsetFrom > -1) {
242 218 : result << offsetFrom;
243 : } else {
244 32 : result << "null";
245 : }
246 250 : result << ",\"to\": ";
247 250 : if (offsetTo > -1) {
248 195 : result << offsetTo;
249 : } else {
250 55 : result << "null";
251 : }
252 250 : result << "}";
253 250 : }
254 :
255 : } // namespace wikidiff2
|