1 package org.apache.maven.doxia.module.confluence.parser;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import org.codehaus.plexus.util.StringUtils;
26
27
28
29
30
31
32
33
34
35 public class ChildBlocksBuilder
36 {
37 private boolean insideBold = false;
38
39 private boolean insideItalic = false;
40
41 private boolean insideLink = false;
42
43 private boolean insideLinethrough = false;
44
45 private boolean insideUnderline = false;
46
47 private boolean insideSub = false;
48
49 private boolean insideSup = false;
50
51 private List<Block> blocks = new ArrayList<>();
52
53 private StringBuilder text = new StringBuilder();
54
55 private String input;
56
57 private boolean insideMonospaced;
58
59
60
61
62
63
64 public ChildBlocksBuilder( String input )
65 {
66 this.input = input;
67 }
68
69
70
71
72
73
74 public List<Block> getBlocks()
75 {
76 List<Block> specialBlocks = new ArrayList<>();
77
78 for ( int i = 0; i < input.length(); i++ )
79 {
80 char c = input.charAt( i );
81
82 switch ( c )
83 {
84 case '*':
85 if ( insideBold )
86 {
87 insideBold = false;
88 specialBlocks = getList( new BoldBlock( getChildren( text, specialBlocks ) ), specialBlocks );
89 text = new StringBuilder();
90 }
91 else if ( insideMonospaced )
92 {
93 text.append( c );
94 }
95 else
96 {
97 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
98 insideBold = true;
99 }
100
101 break;
102 case '_':
103 if ( insideItalic )
104 {
105 insideItalic = false;
106 specialBlocks = getList( new ItalicBlock( getChildren( text, specialBlocks ) ), specialBlocks );
107 text = new StringBuilder();
108 }
109 else if ( insideLink || insideMonospaced )
110 {
111 text.append( c );
112 }
113 else
114 {
115 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
116 insideItalic = true;
117 }
118
119 break;
120 case '-':
121 if ( insideLinethrough )
122 {
123 insideLinethrough = false;
124 blocks.add( new LinethroughBlock( text.toString() ) );
125 text = new StringBuilder();
126 }
127 else if ( insideLink || insideMonospaced )
128 {
129 text.append( c );
130 }
131 else
132 {
133 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
134 insideLinethrough = true;
135 }
136 break;
137 case '+':
138 if ( insideUnderline )
139 {
140 insideUnderline = false;
141 blocks.add( new UnderlineBlock( text.toString() ) );
142 text = new StringBuilder();
143 }
144 else if ( insideLink || insideMonospaced )
145 {
146 text.append( c );
147 }
148 else
149 {
150 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
151 insideUnderline = true;
152 }
153 break;
154 case '~':
155 if ( insideSub )
156 {
157 insideSub = false;
158 blocks.add( new SubBlock( text.toString() ) );
159 text = new StringBuilder();
160 }
161 else if ( insideLink || insideMonospaced )
162 {
163 text.append( c );
164 }
165 else
166 {
167 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
168 insideSub = true;
169 }
170 break;
171 case '^':
172 if ( insideSup )
173 {
174 insideSup = false;
175 blocks.add( new SupBlock( text.toString() ) );
176 text = new StringBuilder();
177 }
178 else if ( insideLink || insideMonospaced )
179 {
180 text.append( c );
181 }
182 else
183 {
184 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
185 insideSup = true;
186 }
187 break;
188 case '[':
189 if ( insideMonospaced )
190 {
191 text.append( c );
192 }
193 else
194 {
195 insideLink = true;
196 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
197 }
198 break;
199 case ']':
200 if ( insideLink )
201 {
202 boolean addHTMLSuffix = false;
203 String link = text.toString();
204
205 if ( !link.endsWith( ".html" ) )
206 {
207 if ( !link.contains( "http" ) )
208 {
209
210 addHTMLSuffix = true;
211 }
212 }
213 if ( link.contains( "|" ) )
214 {
215 String[] pieces = StringUtils.split( text.toString(), "|" );
216
217 if ( pieces[1].startsWith( "^" ) )
218 {
219
220
221 pieces[1] = pieces[1].substring( 1 );
222 addHTMLSuffix = false;
223
224 }
225
226 if ( addHTMLSuffix )
227 {
228 if ( !pieces[1].contains( "#" ) )
229 {
230 pieces[1] = pieces[1].concat( ".html" );
231 }
232 else
233 {
234 if ( !pieces[1].startsWith( "#" ) )
235 {
236 String[] temp = pieces[1].split( "#" );
237 pieces[1] = temp[0] + ".html#" + temp[1];
238 }
239 }
240 }
241
242 blocks.add( new LinkBlock( pieces[1], pieces[0] ) );
243 }
244 else
245 {
246 String value = link;
247
248 if ( link.startsWith( "#" ) )
249 {
250 value = link.substring( 1 );
251 }
252 else if ( link.startsWith( "^" ) )
253 {
254 link = link.substring( 1 );
255 value = link;
256 addHTMLSuffix = false;
257
258 }
259
260 if ( addHTMLSuffix )
261 {
262 if ( !link.contains( "#" ) )
263 {
264 link = link.concat( ".html" );
265 }
266 else
267 {
268 if ( !link.startsWith( "#" ) )
269 {
270 String[] temp = link.split( "#" );
271 link = temp[0] + ".html#" + temp[1];
272 }
273 }
274 }
275
276 blocks.add( new LinkBlock( link, value ) );
277 }
278
279 text = new StringBuilder();
280 insideLink = false;
281 }
282 else if ( insideMonospaced )
283 {
284 text.append( c );
285 }
286
287 break;
288 case '{':
289 if ( insideMonospaced )
290 {
291 text.append( c );
292 }
293 else
294 {
295 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
296
297 if ( nextChar( input, i ) == '{' )
298 {
299 i++;
300 insideMonospaced = true;
301 }
302 }
303
304
305 break;
306 case '}':
307 if ( nextChar( input, i ) == '}' )
308 {
309 i++;
310 insideMonospaced = false;
311 specialBlocks = getList( new MonospaceBlock( getChildren( text, specialBlocks ) ),
312 specialBlocks );
313 text = new StringBuilder();
314 }
315 else if ( insideMonospaced )
316 {
317 text.append( c );
318 }
319 else
320 {
321 String name = text.toString();
322 if ( name.startsWith( "anchor:" ) )
323 {
324 blocks.add( new AnchorBlock( name.substring( "anchor:".length() ) ) );
325 }
326 else
327 {
328 blocks.add( new TextBlock( "{" + name + "}" ) );
329 }
330 text = new StringBuilder();
331 }
332
333 break;
334 case '\\':
335 if ( insideMonospaced )
336 {
337 text.append( c );
338 }
339 else if ( nextChar( input, i ) == '\\' )
340 {
341 i++;
342 text = addTextBlockIfNecessary( blocks, specialBlocks, text );
343 blocks.add( new LinebreakBlock() );
344 }
345 else
346 {
347
348 if ( i == input.length() - 1 )
349 {
350 text.append( '\\' );
351 }
352 else
353 {
354 text.append( input.charAt( ++i ) );
355 }
356 }
357
358 break;
359 default:
360 text.append( c );
361 }
362
363 if ( !specialBlocks.isEmpty() )
364 {
365 if ( !insideItalic && !insideBold && !insideMonospaced )
366 {
367 blocks.addAll( specialBlocks );
368 specialBlocks.clear();
369 }
370 }
371
372 }
373
374 if ( text.length() > 0 )
375 {
376 blocks.add( new TextBlock( text.toString() ) );
377 }
378
379 return blocks;
380 }
381
382 private List<Block> getList( Block block, List<Block> currentBlocks )
383 {
384 List<Block> list = new ArrayList<>();
385
386 if ( insideBold || insideItalic || insideMonospaced )
387 {
388 list.addAll( currentBlocks );
389 }
390
391 list.add( block );
392
393 return list;
394 }
395
396 private List<Block> getChildren( StringBuilder buffer, List<Block> currentBlocks )
397 {
398 String txt = buffer.toString().trim();
399
400 if ( currentBlocks.isEmpty() && StringUtils.isEmpty( txt ) )
401 {
402 return new ArrayList<>();
403 }
404
405 ArrayList<Block> list = new ArrayList<>();
406
407 if ( !insideBold && !insideItalic && !insideMonospaced )
408 {
409 list.addAll( currentBlocks );
410 }
411
412 if ( StringUtils.isEmpty( txt ) )
413 {
414 return list;
415 }
416
417 list.add( new TextBlock( txt ) );
418
419 return list;
420 }
421
422 private static char nextChar( String input, int i )
423 {
424 return input.length() > i + 1 ? input.charAt( i + 1 ) : '\0';
425 }
426
427 private StringBuilder addTextBlockIfNecessary( List<Block> blcks, List<Block> specialBlocks, StringBuilder txt )
428 {
429 if ( txt.length() == 0 )
430 {
431 return txt;
432 }
433
434 TextBlock textBlock = new TextBlock( txt.toString() );
435
436 if ( !insideBold && !insideItalic && !insideMonospaced )
437 {
438 blcks.add( textBlock );
439 }
440 else
441 {
442 specialBlocks.add( textBlock );
443 }
444
445 return new StringBuilder();
446 }
447
448 }