1 package org.apache.maven.doxia.module.apt;
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.Writer;
24 import java.util.ArrayList;
25 import java.util.List;
26 import java.util.Stack;
27
28 import org.apache.maven.doxia.sink.SinkEventAttributes;
29 import org.apache.maven.doxia.sink.impl.AbstractTextSink;
30 import org.apache.maven.doxia.sink.impl.SinkEventAttributeSet;
31 import org.codehaus.plexus.util.StringUtils;
32
33
34
35
36
37
38
39
40
41 public class AptSink
42 extends AbstractTextSink
43 implements AptMarkup
44 {
45
46
47
48
49
50 private StringBuffer buffer;
51
52
53 private StringBuilder tableCaptionBuffer;
54
55
56 private String author;
57
58
59 private String title;
60
61
62 private String date;
63
64
65 private boolean startFlag;
66
67
68 private boolean tableCaptionFlag;
69
70
71 private boolean tableCellFlag;
72
73
74 private boolean headerFlag;
75
76
77 private boolean bufferFlag;
78
79
80 private boolean itemFlag;
81
82
83 private boolean verbatimFlag;
84
85
86 private boolean isBoxed;
87
88
89 private boolean gridFlag;
90
91
92 private int cellCount;
93
94
95 private final PrintWriter writer;
96
97
98 private int[] cellJustif;
99
100
101 private String rowLine;
102
103
104 private String listNestingIndent;
105
106
107 private final Stack<String> listStyles;
108
109
110 protected Stack<List<String>> inlineStack = new Stack<>();
111
112
113
114
115
116
117
118
119
120
121
122 protected AptSink( Writer writer )
123 {
124 this.writer = new PrintWriter( writer );
125 this.listStyles = new Stack<>();
126
127 init();
128 }
129
130
131
132
133
134
135 protected StringBuffer getBuffer()
136 {
137 return buffer;
138 }
139
140
141
142
143
144
145 protected void setHeadFlag( boolean headFlag )
146 {
147 this.headerFlag = headFlag;
148 }
149
150
151
152
153
154
155 protected void resetState()
156 {
157 init();
158 }
159
160
161
162
163 protected void init()
164 {
165 super.init();
166
167 resetBuffer();
168
169 this.tableCaptionBuffer = new StringBuilder();
170 this.listNestingIndent = "";
171
172 this.author = null;
173 this.title = null;
174 this.date = null;
175 this.startFlag = true;
176 this.tableCaptionFlag = false;
177 this.tableCellFlag = false;
178 this.headerFlag = false;
179 this.bufferFlag = false;
180 this.itemFlag = false;
181 this.verbatimFlag = false;
182 this.isBoxed = false;
183 this.gridFlag = false;
184 this.cellCount = 0;
185 this.cellJustif = null;
186 this.rowLine = null;
187 this.listStyles.clear();
188 this.inlineStack.clear();
189 }
190
191
192
193
194 protected void resetBuffer()
195 {
196 buffer = new StringBuffer();
197 }
198
199
200
201
202 protected void resetTableCaptionBuffer()
203 {
204 tableCaptionBuffer = new StringBuilder();
205 }
206
207
208
209
210 public void head()
211 {
212 boolean startFlag = this.startFlag;
213
214 init();
215
216 headerFlag = true;
217 this.startFlag = startFlag;
218 }
219
220
221
222
223 public void head_()
224 {
225 headerFlag = false;
226
227 if ( ! startFlag )
228 {
229 write( EOL );
230 }
231 write( HEADER_START_MARKUP + EOL );
232 if ( title != null )
233 {
234 write( " " + title + EOL );
235 }
236 write( HEADER_START_MARKUP + EOL );
237 if ( author != null )
238 {
239 write( " " + author + EOL );
240 }
241 write( HEADER_START_MARKUP + EOL );
242 if ( date != null )
243 {
244 write( " " + date + EOL );
245 }
246 write( HEADER_START_MARKUP + EOL );
247 }
248
249
250
251
252 public void title_()
253 {
254 if ( buffer.length() > 0 )
255 {
256 title = buffer.toString();
257 resetBuffer();
258 }
259 }
260
261
262
263
264 public void author_()
265 {
266 if ( buffer.length() > 0 )
267 {
268 author = buffer.toString();
269 resetBuffer();
270 }
271 }
272
273
274
275
276 public void date_()
277 {
278 if ( buffer.length() > 0 )
279 {
280 date = buffer.toString();
281 resetBuffer();
282 }
283 }
284
285
286
287
288 public void section1_()
289 {
290 write( EOL );
291 }
292
293
294
295
296 public void section2_()
297 {
298 write( EOL );
299 }
300
301
302
303
304 public void section3_()
305 {
306 write( EOL );
307 }
308
309
310
311
312 public void section4_()
313 {
314 write( EOL );
315 }
316
317
318
319
320 public void section5_()
321 {
322 write( EOL );
323 }
324
325
326
327
328 public void sectionTitle1()
329 {
330 write( EOL );
331 }
332
333
334
335
336 public void sectionTitle1_()
337 {
338 write( EOL + EOL );
339 }
340
341
342
343
344 public void sectionTitle2()
345 {
346 write( EOL + SECTION_TITLE_START_MARKUP );
347 }
348
349
350
351
352 public void sectionTitle2_()
353 {
354 write( EOL + EOL );
355 }
356
357
358
359
360 public void sectionTitle3()
361 {
362 write( EOL + StringUtils.repeat( SECTION_TITLE_START_MARKUP, 2 ) );
363 }
364
365
366
367
368 public void sectionTitle3_()
369 {
370 write( EOL + EOL );
371 }
372
373
374
375
376 public void sectionTitle4()
377 {
378 write( EOL + StringUtils.repeat( SECTION_TITLE_START_MARKUP, 3 ) );
379 }
380
381
382
383
384 public void sectionTitle4_()
385 {
386 write( EOL + EOL );
387 }
388
389
390
391
392 public void sectionTitle5()
393 {
394 write( EOL + StringUtils.repeat( SECTION_TITLE_START_MARKUP, 4 ) );
395 }
396
397
398
399
400 public void sectionTitle5_()
401 {
402 write( EOL + EOL );
403 }
404
405
406
407
408 public void list()
409 {
410 listNestingIndent += " ";
411 listStyles.push( LIST_START_MARKUP );
412 write( EOL );
413 }
414
415
416
417
418 public void list_()
419 {
420 if ( listNestingIndent.length() <= 1 )
421 {
422 write( EOL + listNestingIndent + LIST_END_MARKUP + EOL );
423 }
424 else
425 {
426 write( EOL );
427 }
428 listNestingIndent = StringUtils.chomp( listNestingIndent, " " );
429 listStyles.pop();
430 itemFlag = false;
431 }
432
433
434
435
436 public void listItem()
437 {
438
439
440
441 numberedListItem();
442 itemFlag = true;
443 }
444
445
446
447
448 public void listItem_()
449 {
450 write( EOL );
451 itemFlag = false;
452 }
453
454
455 public void numberedList( int numbering )
456 {
457 listNestingIndent += " ";
458 write( EOL );
459
460 String style;
461 switch ( numbering )
462 {
463 case NUMBERING_UPPER_ALPHA:
464 style = String.valueOf( NUMBERING_UPPER_ALPHA_CHAR );
465 break;
466 case NUMBERING_LOWER_ALPHA:
467 style = String.valueOf( NUMBERING_LOWER_ALPHA_CHAR );
468 break;
469 case NUMBERING_UPPER_ROMAN:
470 style = String.valueOf( NUMBERING_UPPER_ROMAN_CHAR );
471 break;
472 case NUMBERING_LOWER_ROMAN:
473 style = String.valueOf( NUMBERING_LOWER_ROMAN_CHAR );
474 break;
475 case NUMBERING_DECIMAL:
476 default:
477 style = String.valueOf( NUMBERING );
478 }
479
480 listStyles.push( style );
481 }
482
483
484
485
486 public void numberedList_()
487 {
488 if ( listNestingIndent.length() <= 1 )
489 {
490 write( EOL + listNestingIndent + LIST_END_MARKUP + EOL );
491 }
492 else
493 {
494 write( EOL );
495 }
496 listNestingIndent = StringUtils.chomp( listNestingIndent, " " );
497 listStyles.pop();
498 itemFlag = false;
499 }
500
501
502
503
504 public void numberedListItem()
505 {
506 String style = listStyles.peek();
507 if ( style.equals( String.valueOf( STAR ) ) )
508 {
509 write( EOL + listNestingIndent + STAR + SPACE );
510 }
511 else
512 {
513 write( EOL + listNestingIndent + LEFT_SQUARE_BRACKET
514 + LEFT_SQUARE_BRACKET + style + RIGHT_SQUARE_BRACKET
515 + RIGHT_SQUARE_BRACKET + SPACE );
516 }
517 itemFlag = true;
518 }
519
520
521
522
523 public void numberedListItem_()
524 {
525 write( EOL );
526 itemFlag = false;
527 }
528
529
530
531
532 public void definitionList()
533 {
534 listNestingIndent += " ";
535 listStyles.push( "" );
536 write( EOL );
537 }
538
539
540
541
542 public void definitionList_()
543 {
544 if ( listNestingIndent.length() <= 1 )
545 {
546 write( EOL + listNestingIndent + LIST_END_MARKUP + EOL );
547 }
548 else
549 {
550 write( EOL );
551 }
552 listNestingIndent = StringUtils.chomp( listNestingIndent, " " );
553 listStyles.pop();
554 itemFlag = false;
555 }
556
557
558
559
560 public void definedTerm()
561 {
562 write( EOL + " [" );
563 }
564
565
566
567
568 public void definedTerm_()
569 {
570 write( "] " );
571 }
572
573
574
575
576 public void definition()
577 {
578 itemFlag = true;
579 }
580
581
582
583
584 public void definition_()
585 {
586 write( EOL );
587 itemFlag = false;
588 }
589
590
591
592
593 public void pageBreak()
594 {
595 write( EOL + PAGE_BREAK + EOL );
596 }
597
598
599
600
601 public void paragraph()
602 {
603 if ( tableCellFlag )
604 {
605
606 }
607 else if ( itemFlag )
608 {
609 write( EOL + EOL + " " + listNestingIndent );
610 }
611 else
612 {
613 write( EOL + " " );
614 }
615 }
616
617
618
619
620 public void paragraph_()
621 {
622 if ( tableCellFlag )
623 {
624
625 }
626 else
627 {
628 write( EOL + EOL );
629 }
630 }
631
632
633 public void verbatim( boolean boxed )
634 {
635 verbatimFlag = true;
636 this.isBoxed = boxed;
637 write( EOL );
638 if ( boxed )
639 {
640 write( EOL + BOXED_VERBATIM_START_MARKUP + EOL );
641 }
642 else
643 {
644 write( EOL + NON_BOXED_VERBATIM_START_MARKUP + EOL );
645 }
646 }
647
648
649
650
651 public void verbatim_()
652 {
653 if ( isBoxed )
654 {
655 write( EOL + BOXED_VERBATIM_END_MARKUP + EOL );
656 }
657 else
658 {
659 write( EOL + NON_BOXED_VERBATIM_END_MARKUP + EOL );
660 }
661 isBoxed = false;
662 verbatimFlag = false;
663 }
664
665
666
667
668 public void horizontalRule()
669 {
670 write( EOL + HORIZONTAL_RULE_MARKUP + EOL );
671 }
672
673
674
675
676 public void table()
677 {
678 write( EOL );
679 }
680
681
682
683
684 public void table_()
685 {
686 if ( rowLine != null )
687 {
688 write( rowLine );
689 }
690 rowLine = null;
691
692 if ( tableCaptionBuffer.length() > 0 )
693 {
694 text( tableCaptionBuffer.toString() + EOL );
695 }
696
697 resetTableCaptionBuffer();
698 }
699
700
701 public void tableRows( int[] justification, boolean grid )
702 {
703 cellJustif = justification;
704 gridFlag = grid;
705 }
706
707
708
709
710 public void tableRows_()
711 {
712 cellJustif = null;
713 gridFlag = false;
714 }
715
716
717
718
719 public void tableRow()
720 {
721 bufferFlag = true;
722 cellCount = 0;
723 }
724
725
726
727
728 public void tableRow_()
729 {
730 bufferFlag = false;
731
732
733 buildRowLine();
734
735 write( rowLine );
736
737
738 if ( gridFlag )
739 {
740 write( TABLE_ROW_SEPARATOR_MARKUP );
741 }
742
743 write( buffer.toString() );
744
745 resetBuffer();
746
747 write( EOL );
748
749
750 cellCount = 0;
751 }
752
753
754 private void buildRowLine()
755 {
756 StringBuilder rLine = new StringBuilder();
757 rLine.append( TABLE_ROW_START_MARKUP );
758
759 for ( int i = 0; i < cellCount; i++ )
760 {
761 if ( cellJustif != null )
762 {
763 switch ( cellJustif[i] )
764 {
765 case 1:
766 rLine.append( TABLE_COL_LEFT_ALIGNED_MARKUP );
767 break;
768 case 2:
769 rLine.append( TABLE_COL_RIGHT_ALIGNED_MARKUP );
770 break;
771 default:
772 rLine.append( TABLE_COL_CENTERED_ALIGNED_MARKUP );
773 }
774 }
775 else
776 {
777 rLine.append( TABLE_COL_CENTERED_ALIGNED_MARKUP );
778 }
779 }
780 rLine.append( EOL );
781
782 this.rowLine = rLine.toString();
783 }
784
785
786
787
788 public void tableCell()
789 {
790 tableCell( false );
791 }
792
793
794
795
796 public void tableHeaderCell()
797 {
798 tableCell( true );
799 }
800
801
802
803
804
805
806 public void tableCell( boolean headerRow )
807 {
808 if ( headerRow )
809 {
810 buffer.append( TABLE_CELL_SEPARATOR_MARKUP );
811 }
812 tableCellFlag = true;
813 }
814
815
816
817
818 public void tableCell_()
819 {
820 endTableCell();
821 }
822
823
824
825
826 public void tableHeaderCell_()
827 {
828 endTableCell();
829 }
830
831
832
833
834 private void endTableCell()
835 {
836 tableCellFlag = false;
837 buffer.append( TABLE_CELL_SEPARATOR_MARKUP );
838 cellCount++;
839 }
840
841
842
843
844 public void tableCaption()
845 {
846 tableCaptionFlag = true;
847 }
848
849
850
851
852 public void tableCaption_()
853 {
854 tableCaptionFlag = false;
855 }
856
857
858
859
860 public void figureCaption_()
861 {
862 write( EOL );
863 }
864
865
866 public void figureGraphics( String name )
867 {
868 write( EOL + "[" + name + "] " );
869 }
870
871
872 public void anchor( String name )
873 {
874 write( ANCHOR_START_MARKUP );
875 }
876
877
878
879
880 public void anchor_()
881 {
882 write( ANCHOR_END_MARKUP );
883 }
884
885
886 public void link( String name )
887 {
888 if ( !headerFlag )
889 {
890 write( LINK_START_1_MARKUP );
891 text( name.startsWith( "#" ) ? name.substring( 1 ) : name );
892 write( LINK_START_2_MARKUP );
893 }
894 }
895
896
897
898
899 public void link_()
900 {
901 if ( !headerFlag )
902 {
903 write( LINK_END_MARKUP );
904 }
905 }
906
907
908
909
910
911
912
913 public void link( String name, String target )
914 {
915 if ( !headerFlag )
916 {
917 write( LINK_START_1_MARKUP );
918 text( target );
919 write( LINK_START_2_MARKUP );
920 text( name );
921 }
922 }
923
924
925
926
927 public void inline()
928 {
929 inline( null );
930 }
931
932
933 public void inline( SinkEventAttributes attributes )
934 {
935 if ( !headerFlag )
936 {
937 List<String> tags = new ArrayList<>();
938
939 if ( attributes != null )
940 {
941
942 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "italic" ) )
943 {
944 write( ITALIC_START_MARKUP );
945 tags.add( 0, ITALIC_END_MARKUP );
946 }
947
948 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "bold" ) )
949 {
950 write( BOLD_START_MARKUP );
951 tags.add( 0, BOLD_END_MARKUP );
952 }
953
954 if ( attributes.containsAttribute( SinkEventAttributes.SEMANTICS, "code" ) )
955 {
956 write( MONOSPACED_START_MARKUP );
957 tags.add( 0, MONOSPACED_END_MARKUP );
958 }
959
960 }
961
962 inlineStack.push( tags );
963 }
964 }
965
966
967
968
969 public void inline_()
970 {
971 if ( !headerFlag )
972 {
973 for ( String tag: inlineStack.pop() )
974 {
975 write( tag );
976 }
977 }
978 }
979
980
981
982
983 public void italic()
984 {
985 inline( SinkEventAttributeSet.Semantics.ITALIC );
986 }
987
988
989
990
991 public void italic_()
992 {
993 inline_();
994 }
995
996
997
998
999 public void bold()
1000 {
1001 inline( SinkEventAttributeSet.Semantics.BOLD );
1002 }
1003
1004
1005
1006
1007 public void bold_()
1008 {
1009 inline_();
1010 }
1011
1012
1013
1014
1015 public void monospaced()
1016 {
1017 inline( SinkEventAttributeSet.Semantics.CODE );
1018 }
1019
1020
1021
1022
1023 public void monospaced_()
1024 {
1025 inline_();
1026 }
1027
1028
1029
1030
1031 public void lineBreak()
1032 {
1033 if ( headerFlag || bufferFlag )
1034 {
1035 buffer.append( EOL );
1036 }
1037 else if ( verbatimFlag )
1038 {
1039 write( EOL );
1040 }
1041 else
1042 {
1043 write( "\\" + EOL );
1044 }
1045 }
1046
1047
1048
1049
1050 public void nonBreakingSpace()
1051 {
1052 if ( headerFlag || bufferFlag )
1053 {
1054 buffer.append( NON_BREAKING_SPACE_MARKUP );
1055 }
1056 else
1057 {
1058 write( NON_BREAKING_SPACE_MARKUP );
1059 }
1060 }
1061
1062
1063 public void text( String text )
1064 {
1065 if ( tableCaptionFlag )
1066 {
1067 tableCaptionBuffer.append( text );
1068 }
1069 else if ( headerFlag || bufferFlag )
1070 {
1071 buffer.append( text );
1072 }
1073 else if ( verbatimFlag )
1074 {
1075 verbatimContent( text );
1076 }
1077 else
1078 {
1079 content( text );
1080 }
1081 }
1082
1083
1084 public void rawText( String text )
1085 {
1086 write( text );
1087 }
1088
1089
1090 public void comment( String comment )
1091 {
1092 rawText( ( startFlag ? "" : EOL ) + COMMENT + COMMENT + comment );
1093 }
1094
1095
1096
1097
1098
1099
1100
1101 public void unknown( String name, Object[] requiredParams, SinkEventAttributes attributes )
1102 {
1103 getLog().warn( "[Apt Sink] Unknown Sink event: '" + name + "', ignoring!" );
1104 }
1105
1106
1107
1108
1109
1110
1111 protected void write( String text )
1112 {
1113 startFlag = false;
1114 if ( tableCellFlag )
1115 {
1116 buffer.append( text );
1117 }
1118 else
1119 {
1120 writer.write( unifyEOLs( text ) );
1121 }
1122 }
1123
1124
1125
1126
1127
1128
1129 protected void content( String text )
1130 {
1131 write( escapeAPT( text ) );
1132 }
1133
1134
1135
1136
1137
1138
1139 protected void verbatimContent( String text )
1140 {
1141 write( escapeAPT( text ) );
1142 }
1143
1144
1145
1146
1147 public void flush()
1148 {
1149 writer.flush();
1150 }
1151
1152
1153
1154
1155 public void close()
1156 {
1157 writer.close();
1158
1159 init();
1160 }
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176 private static String escapeAPT( String text )
1177 {
1178 if ( text == null )
1179 {
1180 return "";
1181 }
1182
1183 int length = text.length();
1184 StringBuilder buffer = new StringBuilder( length );
1185
1186 for ( int i = 0; i < length; ++i )
1187 {
1188 char c = text.charAt( i );
1189 switch ( c )
1190 {
1191 case '\\':
1192 case '~':
1193 case '=':
1194 case '-':
1195 case '+':
1196 case '*':
1197 case '[':
1198 case ']':
1199 case '<':
1200 case '>':
1201 case '{':
1202 case '}':
1203 buffer.append( '\\' );
1204 buffer.append( c );
1205 break;
1206 default:
1207 buffer.append( c );
1208 }
1209 }
1210
1211 return buffer.toString();
1212 }
1213 }