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