1 package org.apache.maven.doxia.module.twiki.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.HashMap;
24 import java.util.List;
25 import java.util.Map;
26
27
28
29
30
31
32 public class FormatedTextParser
33 {
34
35
36
37 private TextParser textParser;
38
39
40
41
42 private static final Map<String, FormatBlockFactory> FACTORY_MAP = new HashMap<>();
43
44
45
46
47 private static final FormatBlockFactory BOLD_FACTORY = new FormatBlockFactory()
48 {
49
50 public Block createBlock( final Block[] childrens )
51 {
52 return new BoldBlock( childrens );
53 }
54 };
55
56
57
58
59 private static final FormatBlockFactory ITALIC_FACTORY = new FormatBlockFactory()
60 {
61
62 public Block createBlock( final Block[] childrens )
63 {
64 return new ItalicBlock( childrens );
65 }
66 };
67
68
69
70
71 private static final FormatBlockFactory MONOSPACED_FACTORY = new FormatBlockFactory()
72 {
73
74 public Block createBlock( final Block[] childrens )
75 {
76 return new MonospaceBlock( childrens );
77 }
78 };
79
80
81
82
83 private static final FormatBlockFactory BOLDITALIC_FACTORY = new FormatBlockFactory()
84 {
85
86 public Block createBlock( final Block[] childrens )
87 {
88 return new BoldBlock( new Block[] { new ItalicBlock( childrens ) } );
89 }
90 };
91
92
93
94
95 private static final FormatBlockFactory BOLDMONO_FACTORY = new FormatBlockFactory()
96 {
97
98 public Block createBlock( final Block[] childrens )
99 {
100 return new BoldBlock( new Block[] { new MonospaceBlock( childrens ) } );
101 }
102 };
103
104
105
106
107 private static final String[] SPECIAL_CHAR = new String[] { "__", "==", "*", "_", "=" };
108
109 static
110 {
111 FACTORY_MAP.put( "*", BOLD_FACTORY );
112 FACTORY_MAP.put( "_", ITALIC_FACTORY );
113 FACTORY_MAP.put( "=", MONOSPACED_FACTORY );
114 FACTORY_MAP.put( "__", BOLDITALIC_FACTORY );
115 FACTORY_MAP.put( "==", BOLDMONO_FACTORY );
116 }
117
118
119
120
121
122 final Block[] parse( final String line )
123 {
124 return parseFormat( line ).toArray( new Block[] {} );
125 }
126
127
128
129
130
131 static boolean isSpace( final char c )
132 {
133 return c == ' ' || c == '\t';
134 }
135
136
137
138
139
140 static boolean isSpecial( final char c )
141 {
142 boolean ret = false;
143
144 for ( int i = 0; !ret && i < SPECIAL_CHAR.length; i++ )
145 {
146 if ( SPECIAL_CHAR[i].charAt( 0 ) == c )
147 {
148 ret = true;
149 }
150 }
151
152 return ret;
153 }
154
155
156
157
158
159
160
161
162
163 private List<Block> parseFormat( final String line )
164 {
165 final List<Block> ret = new ArrayList<>();
166 final int[] lhOffsets = new int[SPECIAL_CHAR.length];
167 final int[] rhOffsets = new int[SPECIAL_CHAR.length];
168
169
170 for ( int i = 0; i < SPECIAL_CHAR.length; i++ )
171 {
172 final int specialLen = SPECIAL_CHAR[i].length();
173 int t = 0;
174
175 while ( t != -1 && ( t = line.indexOf( SPECIAL_CHAR[i], t ) ) != -1 )
176 {
177
178 if ( t == 0 || isSpace( line.charAt( t - 1 ) ) || isParenthesis( line.charAt( t - 1 ) ) )
179 {
180
181 if ( t + specialLen < line.length() )
182 {
183
184
185 if ( isSpecial( line.charAt( t + specialLen ) ) )
186 {
187 t += specialLen;
188 }
189 else
190 {
191
192 break;
193 }
194 }
195 else
196 {
197 t = -1;
198 }
199 }
200 else
201 {
202 t += specialLen;
203 }
204 }
205 lhOffsets[i] = t;
206 }
207
208
209 for ( int i = 0; i < lhOffsets.length; i++ )
210 {
211 final int specialLen = SPECIAL_CHAR[i].length();
212
213 if ( lhOffsets[i] != -1 )
214 {
215 int t = lhOffsets[i] + specialLen;
216
217 while ( ( t = line.indexOf( SPECIAL_CHAR[i], t ) ) != -1 )
218 {
219
220 final char c = line.charAt( t - 1 );
221 if ( t > 0 && !isSpace( c ) && !isSpecial( c ) )
222 {
223 break;
224 }
225 else
226 {
227 t += specialLen;
228 }
229 }
230 rhOffsets[i] = t;
231 }
232 }
233
234
235 int minIndex = -1;
236 int charType = 0;
237 for ( int i = 0; i < lhOffsets.length; i++ )
238 {
239 if ( lhOffsets[i] != -1 && rhOffsets[i] != 1 )
240 {
241 if ( minIndex == -1 || lhOffsets[i] < minIndex )
242 {
243 if ( rhOffsets[i] > lhOffsets[i] )
244 {
245
246 minIndex = lhOffsets[i];
247 charType = i;
248 }
249 }
250 }
251 }
252
253 if ( minIndex == -1 )
254 {
255 ret.addAll( textParser.parse( line ) );
256 }
257 else
258 {
259 int len = SPECIAL_CHAR[charType].length();
260 ret.addAll( parseFormat( line.substring( 0, minIndex ) ) );
261 ret.add( FACTORY_MAP.get( SPECIAL_CHAR[charType] )
262 .createBlock( parseFormat( line.substring( minIndex + len, rhOffsets[charType] ) )
263 .toArray( new Block[] {} ) ) );
264 ret.addAll( parseFormat( line.substring( rhOffsets[charType] + len ) ) );
265 }
266
267
268 return ret;
269 }
270
271
272
273
274
275 private boolean isParenthesis( final char c )
276 {
277 return c == '(' || c == ')';
278 }
279
280
281
282
283
284
285
286 public final void setTextParser( final TextParser textParser )
287 {
288 if ( textParser == null )
289 {
290 throw new IllegalArgumentException( "argument can't be null" );
291 }
292
293 this.textParser = textParser;
294 }
295 }
296
297
298
299
300 interface FormatBlockFactory
301 {
302
303
304
305
306
307
308 Block createBlock( final Block[] childrens );
309 }