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