| | { |
| | private enum StyleClass { |
| | - strong, |
| | - em, |
| | - |
| | - // headers |
| | - h1, |
| | - h2, |
| | - h3, |
| | - h4, |
| | - h5, |
| | - h6, |
| | - }; |
| | - |
| | - /** |
| | - * style bits (1 << StyleClass.ordinal()) for each character |
| | - * simplifies implementation of overlapping styles |
| | - */ |
| | - private int[] styleClassBits; |
| | - |
| | - static void highlight(StyleClassedTextArea textArea, RootNode astRoot) { |
| | - assert StyleClass.values().length <= 32; |
| | - assert Platform.isFxApplicationThread(); |
| | - |
| | - textArea.setStyleSpans(0, new MarkdownSyntaxHighlighter() |
| | - .computeHighlighting(astRoot, textArea.getLength())); |
| | - } |
| | - |
| | - private MarkdownSyntaxHighlighter() { |
| | - } |
| | - |
| | - private StyleSpans<Collection<String>> computeHighlighting(RootNode astRoot, int textLength) { |
| | - styleClassBits = new int[textLength]; |
| | - |
| | - // visit all nodes |
| | - astRoot.accept(this); |
| | - |
| | - // build style spans |
| | - StyleSpansBuilder<Collection<String>> spansBuilder = new StyleSpansBuilder<>(); |
| | - if (styleClassBits.length > 0) { |
| | - int spanStart = 0; |
| | - int previousBits = styleClassBits[0]; |
| | - |
| | - for (int i = 1; i < styleClassBits.length; i++) { |
| | - int bits = styleClassBits[i]; |
| | - if (bits == previousBits) |
| | - continue; |
| | - |
| | - spansBuilder.add(toStyleClasses(previousBits), i - spanStart); |
| | - |
| | - spanStart = i; |
| | - previousBits = bits; |
| | - } |
| | - spansBuilder.add(toStyleClasses(previousBits), styleClassBits.length - spanStart); |
| | - } else |
| | - spansBuilder.add(Collections.emptyList(), 0); |
| | - return spansBuilder.create(); |
| | - } |
| | - |
| | - private Collection<String> toStyleClasses(int bits) { |
| | - if (bits == 0) |
| | - return Collections.emptyList(); |
| | - |
| | - Collection<String> styleClasses = new ArrayList<>(1); |
| | - for (StyleClass styleClass : StyleClass.values()) { |
| | - if ((bits & (1 << styleClass.ordinal())) != 0) |
| | - styleClasses.add(styleClass.name()); |
| | - } |
| | - return styleClasses; |
| | - } |
| | - |
| | - @Override |
| | - public void visit(AbbreviationNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(AnchorLinkNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(AutoLinkNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(BlockQuoteNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(BulletListNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(CodeNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(DefinitionListNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(DefinitionNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(DefinitionTermNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(ExpImageNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(ExpLinkNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(HeaderNode node) { |
| | - StyleClass styleClass; |
| | - switch (node.getLevel()) { |
| | - case 1: styleClass = StyleClass.h1; break; |
| | - case 2: styleClass = StyleClass.h2; break; |
| | - case 3: styleClass = StyleClass.h3; break; |
| | - case 4: styleClass = StyleClass.h4; break; |
| | - case 5: styleClass = StyleClass.h5; break; |
| | - case 6: styleClass = StyleClass.h6; break; |
| | - default: return; |
| | - } |
| | - setStyleClass(node, styleClass); |
| | - visitChildren(node); |
| | - } |
| | - |
| | - @Override |
| | - public void visit(HtmlBlockNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(InlineHtmlNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(ListItemNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(MailLinkNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(OrderedListNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(ParaNode node) { |
| | - // TODO Auto-generated method stub |
| | - visitChildren(node); |
| | - } |
| | - |
| | - @Override |
| | - public void visit(QuotedNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(ReferenceNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(RefImageNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(RefLinkNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(RootNode node) { |
| | - // TODO Auto-generated method stub |
| | - visitChildren(node); |
| | - } |
| | - |
| | - @Override |
| | - public void visit(SimpleNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(SpecialTextNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(StrikeNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(StrongEmphSuperNode node) { |
| | - setStyleClass(node, node.isStrong() ? StyleClass.strong : StyleClass.em); |
| | - } |
| | - |
| | - @Override |
| | - public void visit(TableBodyNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(TableCaptionNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(TableCellNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(TableColumnNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(TableHeaderNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(TableNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(TableRowNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(VerbatimNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(WikiLinkNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(TextNode node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | - } |
| | - |
| | - @Override |
| | - public void visit(SuperNode node) { |
| | - // TODO Auto-generated method stub |
| | - visitChildren(node); |
| | - } |
| | - |
| | - @Override |
| | - public void visit(Node node) { |
| | - // TODO Auto-generated method stub |
| | - |
| | + // headers |
| | + h1, |
| | + h2, |
| | + h3, |
| | + h4, |
| | + h5, |
| | + h6, |
| | + |
| | + // inlines |
| | + strong, |
| | + em, |
| | + del, |
| | + a, |
| | + img, |
| | + code, |
| | + |
| | + // blocks |
| | + pre, |
| | + blockquote, |
| | + |
| | + // lists |
| | + ul, |
| | + ol, |
| | + li, |
| | + dl, |
| | + dt, |
| | + dd, |
| | + |
| | + // tables |
| | + table, |
| | + thead, |
| | + tbody, |
| | + caption, |
| | + th, |
| | + tr, |
| | + td, |
| | + |
| | + // misc |
| | + html, |
| | + }; |
| | + |
| | + /** |
| | + * style bits (1 << StyleClass.ordinal()) for each character |
| | + * simplifies implementation of overlapping styles |
| | + */ |
| | + private int[] styleClassBits; |
| | + private boolean inTableHeader; |
| | + |
| | + static void highlight(StyleClassedTextArea textArea, RootNode astRoot) { |
| | + assert StyleClass.values().length <= 32; |
| | + assert Platform.isFxApplicationThread(); |
| | + |
| | + textArea.setStyleSpans(0, new MarkdownSyntaxHighlighter() |
| | + .computeHighlighting(astRoot, textArea.getLength())); |
| | + } |
| | + |
| | + private MarkdownSyntaxHighlighter() { |
| | + } |
| | + |
| | + private StyleSpans<Collection<String>> computeHighlighting(RootNode astRoot, int textLength) { |
| | + styleClassBits = new int[textLength]; |
| | + |
| | + // visit all nodes |
| | + astRoot.accept(this); |
| | + |
| | + // build style spans |
| | + StyleSpansBuilder<Collection<String>> spansBuilder = new StyleSpansBuilder<>(); |
| | + if (styleClassBits.length > 0) { |
| | + int spanStart = 0; |
| | + int previousBits = styleClassBits[0]; |
| | + |
| | + for (int i = 1; i < styleClassBits.length; i++) { |
| | + int bits = styleClassBits[i]; |
| | + if (bits == previousBits) |
| | + continue; |
| | + |
| | + spansBuilder.add(toStyleClasses(previousBits), i - spanStart); |
| | + |
| | + spanStart = i; |
| | + previousBits = bits; |
| | + } |
| | + spansBuilder.add(toStyleClasses(previousBits), styleClassBits.length - spanStart); |
| | + } else |
| | + spansBuilder.add(Collections.emptyList(), 0); |
| | + return spansBuilder.create(); |
| | + } |
| | + |
| | + private Collection<String> toStyleClasses(int bits) { |
| | + if (bits == 0) |
| | + return Collections.emptyList(); |
| | + |
| | + Collection<String> styleClasses = new ArrayList<>(1); |
| | + for (StyleClass styleClass : StyleClass.values()) { |
| | + if ((bits & (1 << styleClass.ordinal())) != 0) |
| | + styleClasses.add(styleClass.name()); |
| | + } |
| | + return styleClasses; |
| | + } |
| | + |
| | + @Override |
| | + public void visit(AbbreviationNode node) { |
| | + // noting to do here |
| | + } |
| | + |
| | + @Override |
| | + public void visit(AnchorLinkNode node) { |
| | + // noting to do here |
| | + } |
| | + |
| | + @Override |
| | + public void visit(AutoLinkNode node) { |
| | + setStyleClass(node, StyleClass.a); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(BlockQuoteNode node) { |
| | + setStyleClass(node, StyleClass.blockquote); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(BulletListNode node) { |
| | + setStyleClass(node, StyleClass.ul); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(CodeNode node) { |
| | + setStyleClass(node, StyleClass.code); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(DefinitionListNode node) { |
| | + setStyleClass(node, StyleClass.dl); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(DefinitionNode node) { |
| | + setStyleClass(node, StyleClass.dd); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(DefinitionTermNode node) { |
| | + setStyleClass(node, StyleClass.dt); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(ExpImageNode node) { |
| | + setStyleClass(node, StyleClass.img); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(ExpLinkNode node) { |
| | + setStyleClass(node, StyleClass.a); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(HeaderNode node) { |
| | + StyleClass styleClass; |
| | + switch (node.getLevel()) { |
| | + case 1: styleClass = StyleClass.h1; break; |
| | + case 2: styleClass = StyleClass.h2; break; |
| | + case 3: styleClass = StyleClass.h3; break; |
| | + case 4: styleClass = StyleClass.h4; break; |
| | + case 5: styleClass = StyleClass.h5; break; |
| | + case 6: styleClass = StyleClass.h6; break; |
| | + default: return; |
| | + } |
| | + setStyleClass(node, styleClass); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(HtmlBlockNode node) { |
| | + setStyleClass(node, StyleClass.html); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(InlineHtmlNode node) { |
| | + setStyleClass(node, StyleClass.html); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(ListItemNode node) { |
| | + setStyleClass(node, StyleClass.li); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(MailLinkNode node) { |
| | + setStyleClass(node, StyleClass.a); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(OrderedListNode node) { |
| | + setStyleClass(node, StyleClass.ol); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(ParaNode node) { |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(QuotedNode node) { |
| | + // noting to do here |
| | + } |
| | + |
| | + @Override |
| | + public void visit(ReferenceNode node) { |
| | + // noting to do here |
| | + } |
| | + |
| | + @Override |
| | + public void visit(RefImageNode node) { |
| | + setStyleClass(node, StyleClass.img); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(RefLinkNode node) { |
| | + setStyleClass(node, StyleClass.a); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(RootNode node) { |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(SimpleNode node) { |
| | + // noting to do here |
| | + } |
| | + |
| | + @Override |
| | + public void visit(SpecialTextNode node) { |
| | + // noting to do here |
| | + } |
| | + |
| | + @Override |
| | + public void visit(StrikeNode node) { |
| | + setStyleClass(node, StyleClass.del); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(StrongEmphSuperNode node) { |
| | + if (node.isClosed()) |
| | + setStyleClass(node, node.isStrong() ? StyleClass.strong : StyleClass.em); |
| | + // else sequence was not closed, treat open chars as ordinary chars |
| | + |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(TableBodyNode node) { |
| | + setStyleClass(node, StyleClass.tbody); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(TableCaptionNode node) { |
| | + setStyleClass(node, StyleClass.caption); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(TableCellNode node) { |
| | + setStyleClass(node, inTableHeader ? StyleClass.th : StyleClass.td); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(TableColumnNode node) { |
| | + // noting to do here |
| | + } |
| | + |
| | + @Override |
| | + public void visit(TableHeaderNode node) { |
| | + setStyleClass(node, StyleClass.thead); |
| | + |
| | + inTableHeader = true; |
| | + visitChildren(node); |
| | + inTableHeader = false; |
| | + } |
| | + |
| | + @Override |
| | + public void visit(TableNode node) { |
| | + setStyleClass(node, StyleClass.table); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(TableRowNode node) { |
| | + setStyleClass(node, StyleClass.tr); |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(VerbatimNode node) { |
| | + setStyleClass(node, StyleClass.pre); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(WikiLinkNode node) { |
| | + setStyleClass(node, StyleClass.a); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(TextNode node) { |
| | + // noting to do here |
| | + } |
| | + |
| | + @Override |
| | + public void visit(SuperNode node) { |
| | + visitChildren(node); |
| | + } |
| | + |
| | + @Override |
| | + public void visit(Node node) { |
| | + // ignore custom Node implementations |
| | } |
| | |