1 package org.apache.maven.doxia.module.twiki;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.PrintWriter;
23 import java.io.StringWriter;
24 import java.io.Writer;
25 import java.util.ArrayList;
26 import java.util.List;
27 import java.util.Stack;
28
29 import javax.swing.text.MutableAttributeSet;
30 import javax.swing.text.html.HTML.Attribute;
31 import javax.swing.text.html.HTML.Tag;
32
33 import org.apache.maven.doxia.sink.SinkEventAttributes;
34 import org.apache.maven.doxia.sink.impl.AbstractTextSink;
35 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
36 import org.apache.maven.doxia.sink.impl.SinkUtils;
37 import org.apache.maven.doxia.util.HtmlTools;
38 import org.codehaus.plexus.util.StringUtils;
39
40
41
42
43
44
45
46
47
48 public class TWikiSink
49 extends AbstractTextSink
50 implements TWikiMarkup
51 {
52
53 private final PrintWriter out;
54
55
56 private StringWriter writer;
57
58
59 private boolean boldFlag;
60
61
62 private boolean headFlag;
63
64 private int levelList = 0;
65
66
67 private final Stack<String> listStyles;
68
69
70 protected Stack<Boolean> boldStack = new Stack<>();
71
72
73 protected Stack<List<String>> inlineStack = new Stack<>();
74
75
76
77
78
79
80
81 protected TWikiSink( Writer writer )
82 {
83 this.out = new PrintWriter( writer );
84 this.listStyles = new Stack<>();
85
86 init();
87 }
88
89
90 public void anchor( String name )
91 {
92 write( EOL );
93 write( ANCHOR_MARKUP + name );
94 }
95
96
97 public void anchor( String name, SinkEventAttributes attributes )
98 {
99 anchor( name );
100 }
101
102
103
104
105
106 public void anchor_()
107 {
108
109 }
110
111
112
113
114
115 public void author()
116 {
117
118 }
119
120
121 public void author( SinkEventAttributes attributes )
122 {
123 author();
124 }
125
126
127
128
129
130 public void author_()
131 {
132
133 }
134
135
136
137
138
139 public void body()
140 {
141
142 }
143
144
145 public void body( SinkEventAttributes attributes )
146 {
147 body();
148 }
149
150
151
152
153
154 public void body_()
155 {
156
157 }
158
159
160
161
162 public void bold()
163 {
164 inline( SinkEventAttributeSet.Semantics.BOLD );
165 }
166
167
168
169
170 public void bold_()
171 {
172 inline_();
173 }
174
175
176
177
178
179 public void comment( String comment )
180 {
181
182 }
183
184
185
186
187 public void close()
188 {
189 out.write( writer.toString() );
190 out.close();
191
192 init();
193 }
194
195
196
197
198
199 public void date()
200 {
201
202 }
203
204
205 public void date( SinkEventAttributes attributes )
206 {
207 date();
208 }
209
210
211
212
213
214 public void date_()
215 {
216
217 }
218
219
220
221
222
223 public void definedTerm()
224 {
225
226 }
227
228
229 public void definedTerm( SinkEventAttributes attributes )
230 {
231 definedTerm();
232 }
233
234
235
236
237
238 public void definedTerm_()
239 {
240
241 }
242
243
244
245
246 public void definition()
247 {
248 write( DEFINITION_LIST_DEFINITION_MARKUP );
249 }
250
251
252 public void definition( SinkEventAttributes attributes )
253 {
254 definition();
255 }
256
257
258
259
260 public void definition_()
261 {
262 writeEOL();
263 }
264
265
266
267
268
269 public void definitionList()
270 {
271
272 }
273
274
275 public void definitionList( SinkEventAttributes attributes )
276 {
277 definitionList();
278 }
279
280
281
282
283
284 public void definitionList_()
285 {
286
287 }
288
289
290
291
292 public void definitionListItem()
293 {
294 write( DEFINITION_LIST_ITEM_MARKUP );
295 }
296
297
298 public void definitionListItem( SinkEventAttributes attributes )
299 {
300 definitionListItem();
301 }
302
303
304
305
306
307 public void definitionListItem_()
308 {
309
310 }
311
312
313
314
315 public void figure()
316 {
317 write( LESS_THAN + Tag.IMG.toString() + SPACE );
318 }
319
320
321 public void figure( SinkEventAttributes attributes )
322 {
323 figure();
324 }
325
326
327
328
329
330 public void figure_()
331 {
332 write( SLASH + String.valueOf( GREATER_THAN ) );
333 }
334
335
336
337
338
339 public void figureCaption()
340 {
341 write( Attribute.ALT.toString() + EQUAL + QUOTE );
342 }
343
344
345 public void figureCaption( SinkEventAttributes attributes )
346 {
347 figureCaption();
348 }
349
350
351
352
353
354 public void figureCaption_()
355 {
356 write( QUOTE + String.valueOf( SPACE ) );
357 }
358
359
360 public void figureGraphics( String name )
361 {
362 write( Attribute.SRC.toString() + EQUAL + QUOTE + name + QUOTE + SPACE );
363 }
364
365
366 public void figureGraphics( String src, SinkEventAttributes attributes )
367 {
368 figureGraphics( src );
369 }
370
371
372
373
374 public void flush()
375 {
376 close();
377 writer.flush();
378 }
379
380
381
382
383 public void head()
384 {
385 init();
386
387 headFlag = true;
388 }
389
390
391 public void head( SinkEventAttributes attributes )
392 {
393 head();
394 }
395
396
397
398
399 public void head_()
400 {
401 headFlag = false;
402 }
403
404
405
406
407 public void horizontalRule()
408 {
409 writeEOL( true );
410 write( HORIZONTAL_RULE_MARKUP );
411 writeEOL( true );
412 }
413
414
415 public void horizontalRule( SinkEventAttributes attributes )
416 {
417 horizontalRule();
418 }
419
420
421
422
423 public void inline()
424 {
425 inline( null );
426 }
427
428
429 public void inline( SinkEventAttributes attributes )
430 {
431 List<String> tags = new ArrayList<>();
432
433 boldStack.push( boldFlag );
434
435 if ( attributes != null )
436 {
437
438 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
439 {
440 boldFlag = true;
441 write( BOLD_START_MARKUP );
442 tags.add( 0, BOLD_END_MARKUP );
443 }
444
445 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
446 {
447 if ( boldFlag )
448 {
449 String tmp = writer.toString();
450 writer = new StringWriter();
451 writer.write( tmp.substring( 0, tmp.length() - 1 ) );
452 write( BOLD_ITALIC_START_MARKUP );
453 tags.add( 0, BOLD_ITALIC_END_MARKUP );
454 }
455 else
456 {
457 write( ITALIC_START_MARKUP );
458 tags.add( ITALIC_END_MARKUP );
459 }
460 }
461
462 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
463 {
464 if ( boldFlag )
465 {
466 String tmp = writer.toString();
467 writer = new StringWriter();
468 writer.write( tmp.substring( 0, tmp.length() - 1 ) );
469 write( BOLD_MONOSPACED_START_MARKUP );
470 tags.add( 0, BOLD_MONOSPACED_END_MARKUP );
471 }
472 else
473 {
474 write( MONOSPACED_START_MARKUP );
475 tags.add( 0, MONOSPACED_END_MARKUP );
476 }
477 }
478
479 }
480
481 inlineStack.push( tags );
482 }
483
484
485
486
487 public void inline_()
488 {
489 for ( String tag: inlineStack.pop() )
490 {
491 write( tag );
492 }
493 this.boldFlag = boldStack.pop();
494 }
495
496
497
498
499 public void italic()
500 {
501 inline( SinkEventAttributeSet.Semantics.ITALIC );
502 }
503
504
505
506
507 public void italic_()
508 {
509 inline_();
510 }
511
512
513
514
515
516 public void lineBreak()
517 {
518
519 }
520
521
522 public void lineBreak( SinkEventAttributes attributes )
523 {
524 lineBreak();
525 }
526
527
528 public void link( String name )
529 {
530 write( LINK_START_MARKUP + name + LINK_MIDDLE_MARKUP );
531 }
532
533
534 public void link( String name, SinkEventAttributes attributes )
535 {
536 link( name );
537 }
538
539
540
541
542 public void link_()
543 {
544 write( LINK_END_MARKUP );
545 }
546
547
548
549
550 public void list()
551 {
552 if ( !writer.toString().endsWith( EOL + EOL ) )
553 {
554 writeEOL( true );
555 }
556
557 levelList++;
558 }
559
560
561 public void list( SinkEventAttributes attributes )
562 {
563 list();
564 }
565
566
567
568
569 public void list_()
570 {
571 levelList--;
572 }
573
574
575
576
577 public void listItem()
578 {
579 String indent = StringUtils.repeat( THREE_SPACES_MARKUP, levelList );
580 write( indent + LIST_ITEM_MARKUP );
581 }
582
583
584 public void listItem( SinkEventAttributes attributes )
585 {
586 listItem();
587 }
588
589
590
591
592 public void listItem_()
593 {
594 writeEOL( true );
595 }
596
597
598
599
600 public void monospaced()
601 {
602 inline( SinkEventAttributeSet.Semantics.CODE );
603 }
604
605
606
607
608 public void monospaced_()
609 {
610 inline_();
611 }
612
613
614
615
616
617 public void nonBreakingSpace()
618 {
619
620 }
621
622
623 public void numberedList( int numbering )
624 {
625 levelList++;
626
627 String style;
628 switch ( numbering )
629 {
630 case NUMBERING_UPPER_ALPHA:
631 style = NUMBERING_UPPER_ALPHA_MARKUP;
632 break;
633 case NUMBERING_LOWER_ALPHA:
634 style = NUMBERING_LOWER_ALPHA_MARKUP;
635 break;
636 case NUMBERING_UPPER_ROMAN:
637 style = NUMBERING_UPPER_ROMAN_MARKUP;
638 break;
639 case NUMBERING_LOWER_ROMAN:
640 style = NUMBERING_LOWER_ROMAN_MARKUP;
641 break;
642 case NUMBERING_DECIMAL:
643 default:
644 style = NUMBERING_MARKUP;
645 }
646
647 listStyles.push( style );
648 }
649
650
651 public void numberedList( int numbering, SinkEventAttributes attributes )
652 {
653 numberedList( numbering );
654 }
655
656
657
658
659 public void numberedList_()
660 {
661 levelList--;
662 listStyles.pop();
663 }
664
665
666
667
668 public void numberedListItem()
669 {
670 writeEOL( true );
671 String style = listStyles.peek();
672 String indent = StringUtils.repeat( THREE_SPACES_MARKUP, levelList );
673 write( indent + style + SPACE );
674 }
675
676
677 public void numberedListItem( SinkEventAttributes attributes )
678 {
679 numberedListItem();
680 }
681
682
683
684
685 public void numberedListItem_()
686 {
687 writeEOL( true );
688 }
689
690
691
692
693
694 public void pageBreak()
695 {
696
697 }
698
699
700
701
702
703 public void paragraph()
704 {
705
706 }
707
708
709 public void paragraph( SinkEventAttributes attributes )
710 {
711 paragraph();
712 }
713
714
715
716
717 public void paragraph_()
718 {
719 writeEOL( true );
720 writeEOL();
721 }
722
723
724
725
726
727 public void rawText( String text )
728 {
729
730 }
731
732
733
734
735
736 public void section( int level, SinkEventAttributes attributes )
737 {
738
739 }
740
741
742
743
744
745 public void section1()
746 {
747
748 }
749
750
751
752
753
754 public void section1_()
755 {
756
757 }
758
759
760
761
762
763 public void section2()
764 {
765
766 }
767
768
769
770
771
772 public void section2_()
773 {
774
775 }
776
777
778
779
780
781 public void section3()
782 {
783
784 }
785
786
787
788
789
790 public void section3_()
791 {
792
793 }
794
795
796
797
798
799 public void section4()
800 {
801
802 }
803
804
805
806
807
808 public void section4_()
809 {
810
811 }
812
813
814
815
816
817 public void section5()
818 {
819
820 }
821
822
823
824
825
826 public void section5_()
827 {
828
829 }
830
831
832
833
834
835 public void section_( int level )
836 {
837
838 }
839
840
841
842
843
844 public void sectionTitle()
845 {
846
847 }
848
849
850 public void sectionTitle( int level, SinkEventAttributes attributes )
851 {
852 if ( level > 0 && level < 6 )
853 {
854 write( StringUtils.repeat( "-", 3 ) + StringUtils.repeat( "+", level ) );
855 }
856 }
857
858
859
860
861 public void sectionTitle1()
862 {
863 sectionTitle( 1, null );
864 }
865
866
867
868
869 public void sectionTitle1_()
870 {
871 sectionTitle_( 1 );
872 }
873
874
875
876
877 public void sectionTitle2()
878 {
879 sectionTitle( 2, null );
880 }
881
882
883
884
885 public void sectionTitle2_()
886 {
887 sectionTitle_( 2 );
888 }
889
890
891
892
893 public void sectionTitle3()
894 {
895 sectionTitle( 3, null );
896 }
897
898
899
900
901 public void sectionTitle3_()
902 {
903 sectionTitle_( 3 );
904 }
905
906
907
908
909 public void sectionTitle4()
910 {
911 sectionTitle( 4, null );
912 }
913
914
915
916
917 public void sectionTitle4_()
918 {
919 sectionTitle_( 4 );
920 }
921
922
923
924
925 public void sectionTitle5()
926 {
927 sectionTitle( 5, null );
928 }
929
930
931
932
933 public void sectionTitle5_()
934 {
935 sectionTitle_( 5 );
936 }
937
938
939
940
941
942 public void sectionTitle_()
943 {
944
945 }
946
947
948 public void sectionTitle_( int level )
949 {
950 writeEOL( true );
951 writeEOL();
952 }
953
954
955
956
957
958 public void table()
959 {
960
961 }
962
963
964 public void table( SinkEventAttributes attributes )
965 {
966 table();
967 }
968
969
970
971
972
973 public void table_()
974 {
975
976 }
977
978
979
980
981
982 public void tableCaption()
983 {
984
985 }
986
987
988 public void tableCaption( SinkEventAttributes attributes )
989 {
990 tableCaption();
991 }
992
993
994
995
996
997 public void tableCaption_()
998 {
999
1000 }
1001
1002
1003
1004
1005 public void tableCell()
1006 {
1007 write( " " );
1008 }
1009
1010
1011 public void tableCell( SinkEventAttributes attributes )
1012 {
1013 tableCell();
1014 }
1015
1016
1017 public void tableCell( String width )
1018 {
1019 tableCell();
1020 }
1021
1022
1023
1024
1025 public void tableCell_()
1026 {
1027 write( TABLE_CELL_MARKUP );
1028 }
1029
1030
1031
1032
1033 public void tableHeaderCell()
1034 {
1035 write( TABLE_CELL_HEADER_START_MARKUP );
1036 }
1037
1038
1039 public void tableHeaderCell( SinkEventAttributes attributes )
1040 {
1041 tableHeaderCell();
1042 }
1043
1044
1045 public void tableHeaderCell( String width )
1046 {
1047 tableHeaderCell();
1048 }
1049
1050
1051
1052
1053 public void tableHeaderCell_()
1054 {
1055 write( TABLE_CELL_HEADER_END_MARKUP );
1056 }
1057
1058
1059
1060
1061 public void tableRow()
1062 {
1063 write( TABLE_ROW_MARKUP );
1064 }
1065
1066
1067 public void tableRow( SinkEventAttributes attributes )
1068 {
1069 tableRow();
1070 }
1071
1072
1073
1074
1075 public void tableRow_()
1076 {
1077 writeEOL( true );
1078 }
1079
1080
1081
1082
1083
1084 public void tableRows( int[] justification, boolean grid )
1085 {
1086
1087 }
1088
1089
1090
1091
1092
1093 public void tableRows_()
1094 {
1095
1096 }
1097
1098
1099 public void text( String text )
1100 {
1101 if ( headFlag )
1102 {
1103 return;
1104 }
1105
1106 content( text );
1107 }
1108
1109
1110 public void text( String text, SinkEventAttributes attributes )
1111 {
1112 if ( attributes == null )
1113 {
1114 text( text );
1115 }
1116 else
1117 {
1118 if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) )
1119 {
1120 writeStartTag( Tag.U );
1121 }
1122 if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) )
1123 {
1124 writeStartTag( Tag.S );
1125 }
1126 if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) )
1127 {
1128 writeStartTag( Tag.SUB );
1129 }
1130 if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) )
1131 {
1132 writeStartTag( Tag.SUP );
1133 }
1134
1135 text( text );
1136
1137 if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sup" ) )
1138 {
1139 writeEndTag( Tag.SUP );
1140 }
1141 if ( attributes.containsAttribute( SinkEventAttributes.VALIGN, "sub" ) )
1142 {
1143 writeEndTag( Tag.SUB );
1144 }
1145 if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "line-through" ) )
1146 {
1147 writeEndTag( Tag.S );
1148 }
1149 if ( attributes.containsAttribute( SinkEventAttributes.DECORATION, "underline" ) )
1150 {
1151 writeEndTag( Tag.U );
1152 }
1153 }
1154 }
1155
1156
1157
1158
1159
1160 public void title()
1161 {
1162
1163 }
1164
1165
1166 public void title( SinkEventAttributes attributes )
1167 {
1168 title();
1169 }
1170
1171
1172
1173
1174
1175 public void title_()
1176 {
1177
1178 }
1179
1180
1181
1182
1183
1184 public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes )
1185 {
1186
1187 }
1188
1189
1190 public void verbatim( boolean boxed )
1191 {
1192 SinkEventAttributeSet att = new SinkEventAttributeSet();
1193
1194 if ( boxed )
1195 {
1196 att.addAttribute( SinkEventAttributes.DECORATION, "boxed" );
1197 }
1198
1199 verbatim( att );
1200 }
1201
1202
1203
1204
1205
1206
1207 public void verbatim( SinkEventAttributes attributes )
1208 {
1209 MutableAttributeSet atts = SinkUtils.filterAttributes( attributes, SinkUtils.SINK_VERBATIM_ATTRIBUTES );
1210
1211 if ( atts == null )
1212 {
1213 atts = new SinkEventAttributeSet();
1214 }
1215
1216 boolean boxed = false;
1217
1218 if ( atts.isDefined( SinkEventAttributes.DECORATION ) )
1219 {
1220 boxed = "boxed".equals( atts.getAttribute( SinkEventAttributes.DECORATION ).toString() );
1221 }
1222
1223 if ( boxed )
1224 {
1225 atts.addAttribute( Attribute.CLASS, "source" );
1226 }
1227
1228 atts.removeAttribute( SinkEventAttributes.DECORATION );
1229
1230 String width = (String) atts.getAttribute( Attribute.WIDTH.toString() );
1231 atts.removeAttribute( Attribute.WIDTH.toString() );
1232
1233 writeStartTag( Tag.DIV, atts );
1234 writeEOL( true );
1235
1236 if ( width != null )
1237 {
1238 atts.addAttribute( Attribute.WIDTH.toString(), width );
1239 }
1240
1241 atts.removeAttribute( Attribute.ALIGN.toString() );
1242 atts.removeAttribute( Attribute.CLASS.toString() );
1243
1244 writeStartTag( VERBATIM_TAG, atts );
1245 }
1246
1247
1248
1249
1250 public void verbatim_()
1251 {
1252 writeEndTag( VERBATIM_TAG );
1253 writeEOL( true );
1254 writeEndTag( Tag.DIV );
1255 writeEOL( true );
1256 }
1257
1258
1259
1260
1261
1262 private void write( String text )
1263 {
1264 writer.write( unifyEOLs( text ) );
1265 }
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277 private void writeStartTag( Tag t )
1278 {
1279 writeStartTag( t, null );
1280 }
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293 private void writeStartTag( Tag t, MutableAttributeSet att )
1294 {
1295 writeStartTag( t, att, false );
1296 }
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309 private void writeStartTag( Tag t, MutableAttributeSet att, boolean isSimpleTag )
1310 {
1311 if ( t == null )
1312 {
1313 throw new IllegalArgumentException( "A tag is required" );
1314 }
1315
1316 StringBuilder sb = new StringBuilder();
1317 sb.append( LESS_THAN );
1318
1319 sb.append( t.toString() );
1320
1321 sb.append( SinkUtils.getAttributeString( att ) );
1322
1323 if ( isSimpleTag )
1324 {
1325 sb.append( SPACE ).append( SLASH );
1326 }
1327
1328 sb.append( GREATER_THAN );
1329
1330 write( sb.toString() );
1331 }
1332
1333
1334
1335
1336 private void writeEOL()
1337 {
1338 write( EOL );
1339 }
1340
1341
1342
1343
1344 private void writeEOL( boolean trim )
1345 {
1346 if ( !trim )
1347 {
1348 writeEOL();
1349 return;
1350 }
1351
1352 String tmp = writer.toString().trim();
1353 writer = new StringWriter();
1354 writer.write( tmp );
1355 write( EOL );
1356 }
1357
1358
1359
1360
1361
1362
1363 private void writeEndTag( Tag t )
1364 {
1365 StringBuilder sb = new StringBuilder();
1366 sb.append( LESS_THAN );
1367 sb.append( SLASH );
1368
1369 sb.append( t.toString() );
1370 sb.append( GREATER_THAN );
1371
1372 write( sb.toString() );
1373 }
1374
1375
1376
1377
1378
1379
1380 protected void content( String text )
1381 {
1382 write( escapeHTML( text ) );
1383 }
1384
1385
1386
1387
1388 protected void init()
1389 {
1390 super.init();
1391
1392 this.writer = new StringWriter();
1393 this.headFlag = false;
1394 this.levelList = 0;
1395 this.listStyles.clear();
1396 this.boldFlag = false;
1397 }
1398
1399
1400
1401
1402
1403
1404
1405
1406 protected static String escapeHTML( String text )
1407 {
1408 return HtmlTools.escapeHTML( text );
1409 }
1410 }