use of com.randomnoun.build.javaToGraphviz.comment.CommentText in project java-to-graphviz by randomnoun.
the class CommentExtractor method getComments.
/**
* Return a list of processed comments from the source file.
*
* GvStyleComment: "// gv-style: { xxx }"
* GvKeepNodeComment: "// gv-keepNode: xxx"
* GvLiteralComment: "// gv-literal: xxx"
* GvDigraphComment: "// gv-graph: xxx"
* GvSubgraphComment: "// gv-subgraph: xxx"
* GvComment: "// gv.className.className.className#id: xxx { xxx }"
*
* @param cu
* @param src
* @return
*/
@SuppressWarnings("unchecked")
public List<CommentText> getComments(CompilationUnit cu, String src) {
// @TODO better regex
// Pattern gvPattern = Pattern.compile("^gv(\\.[a-zA-Z]+)*:"); // gv.some.class.names:
// probably do this right at the end as gv.literal affects how we parse it
// Pattern valPattern = Pattern.compile("(([a-zA-Z]+)\\s*([^;]*);\\s*)*"); // things;separated;by;semicolons;
List<CommentText> comments = new ArrayList<>();
for (Comment c : (List<Comment>) cu.getCommentList()) {
// comment.accept(cv);
boolean eolComment = (c instanceof LineComment);
int start = c.getStartPosition();
int end = start + c.getLength();
String text = src.substring(start, end);
int line = cu.getLineNumber(start);
int column = cu.getColumnNumber(start);
if (c.isBlockComment()) {
if (text.startsWith("/*") && text.endsWith("*/")) {
text = text.substring(2, text.length() - 2).trim();
} else {
throw new IllegalStateException("Block comment does not start with '/*' and end with '*/': '" + text + "'");
}
}
if (c.isLineComment()) {
if (text.startsWith("//")) {
text = text.substring(2).trim();
} else {
throw new IllegalStateException("Line comment does not start with '//': '" + text + "'");
}
}
if (text.startsWith("gv-style:")) {
String s = text.substring(9).trim();
if (s.startsWith("{") && s.endsWith("}")) {
s = s.substring(1, s.length() - 1).trim();
// here be the css
// remove inline comments
// logger.info("maybe here ? " + s);
comments.add(new GvStyleComment(c, line, column, eolComment, text, s));
} else {
throw new IllegalStateException("gv-style does not start with '{' and end with '}': '" + text + "'");
}
} else if (text.startsWith("gv-endGraph")) {
comments.add(new GvEndGraphComment(c, line, column, eolComment));
} else if (text.startsWith("gv-endSubgraph")) {
comments.add(new GvEndSubgraphComment(c, line, column, eolComment));
} else if (text.startsWith("gv-literal:")) {
String s = text.substring(11).trim();
comments.add(new GvLiteralComment(c, line, column, eolComment, s));
} else if (text.startsWith("gv-keepNode:")) {
String s = text.substring(12).trim();
comments.add(new GvKeepNodeComment(c, line, column, eolComment, s));
} else if (text.startsWith("gv-option:")) {
String s = text.substring(10).trim();
comments.add(new GvOptionComment(c, line, column, eolComment, s));
} else {
Matcher fgm;
CommentText gvc = null;
fgm = gvGraphClassPattern.matcher(text);
if (fgm.find()) {
gvc = getGvComment("gv-graph", c, line, column, fgm, text);
} else {
fgm = gvSubgraphClassPattern.matcher(text);
if (fgm.find()) {
gvc = getGvComment("gv-subgraph", c, line, column, fgm, text);
} else {
fgm = gvNodeClassPattern.matcher(text);
if (fgm.find()) {
gvc = getGvComment("gv", c, line, column, fgm, text);
} else {
// regular comment, ignore
}
}
}
if (gvc != null) {
comments.add(gvc);
}
}
}
return comments;
}
use of com.randomnoun.build.javaToGraphviz.comment.CommentText in project java-to-graphviz by randomnoun.
the class AstToDagVisitor method processCommentsToTypeOrMethodNode.
private void processCommentsToTypeOrMethodNode(DagNode pdn, int line, DagNode mn) {
// DagNode lastNode = null;
while (lastIdx < comments.size() && comments.get(lastIdx).line < line) {
CommentText ct = comments.get(lastIdx);
/*
DagNode dn = new DagNode();
dn.keepNode = true; // always keep comments
dn.type = "comment";
dn.line = ct.line;
dn.name = dag.getUniqueName("c_" + ct.line);
dn.label = ct.text;
dn.astNode = null;
dn.options = options;
*/
DagNode dn = null;
if (ct instanceof GvComment) {
mn.classes.addAll(((GvComment) ct).classes);
// last comment wins
mn.label = ct.text;
} else if (ct instanceof GvGraphComment) {
GvGraphComment gc = ((GvGraphComment) ct);
// to remove the class ast node from the 0th root graph
if (rootGraphIdx == 0) {
dag.clear();
root = new DagSubgraph(dag, null);
dag.rootGraphs.add(root);
} else {
root = new DagSubgraph(dag, null);
dag.rootGraphs.add(root);
}
root.name = gc.id;
root.classes.addAll(gc.classes);
// append to existing ?
root.gvAttributes.put("style", gc.inlineStyleString);
rootGraphIdx++;
} else if (ct instanceof GvEndGraphComment) {
if (rootGraphIdx == 0) {
throw new IllegalStateException("gv-endGraph without gv-graph");
} else {
root = null;
}
} else if (ct instanceof GvSubgraphComment) {
GvSubgraphComment gvsc = (GvSubgraphComment) ct;
dn = new DagNode();
// dn.name = dag.getUniqueName("c_" + ct.line);
// always keep gv comments
dn.keepNode = true;
dn.type = "comment";
dn.lineNumber = ct.line;
dn.classes.add("comment");
dn.label = ct.text;
dn.astNode = null;
dn.options = options;
dn.keepNodeMatcher = keepNodeMatcher;
dn.name = gvsc.id;
dn.classes.addAll(gvsc.classes);
dn.classes.add("beginSubgraph");
} else if (ct instanceof GvEndSubgraphComment) {
dn = new DagNode();
// dn.name = dag.getUniqueName("c_" + ct.line);
// always keep gv comments
dn.keepNode = true;
dn.type = "comment";
dn.lineNumber = ct.line;
dn.classes.add("comment");
dn.label = ct.text;
dn.astNode = null;
dn.options = options;
dn.keepNodeMatcher = keepNodeMatcher;
dn.classes.add("endSubgraph");
} else if (ct instanceof GvLiteralComment) {
logger.warn("gv-literal outside of method");
} else if (ct instanceof GvKeepNodeComment) {
GvKeepNodeComment knc = ((GvKeepNodeComment) ct);
boolean defaultKeepNode = "true".equals(options.get("defaultKeepNode"));
keepNodeMatcher = keepNodeMatcher.getModifiedKeepNodeMatcher(defaultKeepNode, knc.text.trim());
} else if (ct instanceof GvOptionComment) {
GvOptionComment oc = ((GvOptionComment) ct);
options = newOptions(oc.text.trim());
}
if (dn != null) {
if (pdn != null) {
if (root == null) {
throw new IllegalStateException("gv comment outside of graph");
}
dag.addNode(root, dn);
pdn.addChild(dn);
} else {
// could add as a root node, but let's see how we go
throw new IllegalStateException("null pdn in processCommentsToTypeOrMethodNode");
}
}
lastIdx++;
}
}
use of com.randomnoun.build.javaToGraphviz.comment.CommentText in project java-to-graphviz by randomnoun.
the class AstToDagVisitor method processCommentsToStatementNode.
private void processCommentsToStatementNode(DagNode pdn, int line, int column, DagNode currentLineDn) {
// DagNode lastNode = null;
while (lastIdx < comments.size() && (comments.get(lastIdx).line < line || (comments.get(lastIdx).line == line && comments.get(lastIdx).column < column))) {
CommentText ct = comments.get(lastIdx);
DagNode dn;
if (currentLineDn == null) {
dn = new DagNode();
// dn.name = dag.getUniqueName("c_" + ct.line);
// always keep gv comments
dn.keepNode = true;
dn.type = "comment";
dn.lineNumber = ct.line;
dn.classes.add("comment");
dn.label = ct.text;
dn.astNode = null;
dn.options = options;
dn.keepNodeMatcher = keepNodeMatcher;
} else {
dn = currentLineDn;
}
if (ct instanceof GvComment) {
GvComment gc = (GvComment) ct;
if (Text.isBlank(gc.direction)) {
DagNode prevDagNode = getStartingDagNodeOnLine(ct.line);
if (prevDagNode == null) {
// no direction
annotateDag(dn, gc);
} else {
annotateDag(prevDagNode, gc);
dn = null;
}
} else if (gc.direction.equals("^")) {
// apply to previous node instead
DagNode prevDagNode = getStartingDagNodeAboveLine(ct.line);
if (prevDagNode == null) {
throw new IllegalStateException("Could not find previous statement to associate with '^' comment on line " + ct.line);
}
annotateDag(prevDagNode, gc);
dn = null;
} else if (gc.direction.equals("<")) {
// apply to previous ast on this line
DagNode prevDagNode = getEndDagNodeBeforeLineColumn(ct.line, ct.column);
if (prevDagNode == null) {
throw new IllegalStateException("Could not find previous statement to associate with '<' comment on line " + ct.line);
}
annotateDag(prevDagNode, gc);
dn = null;
} else if (gc.direction.equals("v")) {
// apply to first node on next line instead
nextLineComments.add(gc);
nextLineFromLine = ct.line;
dn = null;
} else if (gc.direction.equals(">")) {
nextDagComments.add(gc);
dn = null;
} else {
throw new IllegalStateException("Unknown direction '" + gc.direction + "'");
}
} else if (ct instanceof GvGraphComment) {
GvGraphComment gc = ((GvGraphComment) ct);
// to remove the class ast node from the 0th root graph
if (rootGraphIdx == 0) {
dag.clear();
root = new DagSubgraph(dag, null);
dag.rootGraphs.add(root);
} else {
root = new DagSubgraph(dag, null);
dag.rootGraphs.add(root);
}
root.name = gc.id;
root.classes.addAll(gc.classes);
// append to existing ?
root.gvAttributes.put("style", gc.inlineStyleString);
rootGraphIdx++;
dn = null;
} else if (ct instanceof GvEndGraphComment) {
if (rootGraphIdx == 0) {
throw new IllegalStateException("gv-endGraph without gv-graph");
} else {
root = null;
}
dn = null;
} else if (ct instanceof GvSubgraphComment) {
GvSubgraphComment gvsc = (GvSubgraphComment) ct;
dn.name = gvsc.id;
dn.classes.addAll(gvsc.classes);
dn.classes.add("beginSubgraph");
} else if (ct instanceof GvEndSubgraphComment) {
dn.classes.add("endSubgraph");
} else if (ct instanceof GvLiteralComment) {
GvLiteralComment gvlc = (GvLiteralComment) ct;
dn.classes.add("gv-literal");
dn.skipNode = true;
} else if (ct instanceof GvKeepNodeComment) {
GvKeepNodeComment knc = ((GvKeepNodeComment) ct);
boolean defaultKeepNode = "true".equals(options.get("defaultKeepNode"));
keepNodeMatcher = keepNodeMatcher.getModifiedKeepNodeMatcher(defaultKeepNode, knc.text.trim());
dn = null;
} else if (ct instanceof GvOptionComment) {
GvOptionComment oc = ((GvOptionComment) ct);
options = newOptions(oc.text.trim());
dn = null;
}
if (dn != null && dn != currentLineDn) {
if (pdn != null) {
if (root == null) {
throw new IllegalStateException("gv comment outside of graph");
}
dag.addNode(root, dn);
pdn.addChild(dn);
} else {
throw new IllegalStateException("null pdn in createCommentNodesToLine");
// logger.warn("null pdn on " + dn.type + " on line " + dn.line);
}
}
lastIdx++;
}
}
use of com.randomnoun.build.javaToGraphviz.comment.CommentText in project java-to-graphviz by randomnoun.
the class CommentExtractor method getStyleSheet.
// when we construct the DagNodes, automatically add classes based on AST type
// and line number, which will make colouring these things in from jacoco output that much simpler
// and whatever JVMTI uses, which is probably line numbers as well
/**
* Return a stylesheet, composed of:
* <ul>
* <li>imported base CSS
* <li>imported user CSS
* <li>source code styles (gv-style blocks), may import other CSS
* <li>user CSS rules
* </ul>
*
* @param comments
* @param baseCssHref
* @param userCssHrefs
* @param userCssRules
* @return
* @throws IOException
*/
public CSSStyleSheet getStyleSheet(List<CommentText> comments, String baseCssHref, List<String> userCssHrefs, List<String> userCssRules) throws IOException {
String css = "";
if (!Text.isBlank(baseCssHref) && !baseCssHref.equals("-")) {
css = "@import \"" + baseCssHref + "\";\n";
}
if (userCssHrefs != null) {
for (String s : userCssHrefs) {
css += "@import \"" + s + "\";\n";
}
}
for (CommentText c : comments) {
// String t = c.text;
if (c instanceof GvStyleComment) {
// remove non-standard css comments
String[] ss = ((GvStyleComment) c).style.split("\n");
for (int i = 0; i < ss.length; i++) {
String s = ss[i];
if (s.contains("//") && !s.contains("://")) {
// double-slash can start a comment, but not if it might be a @import url(scheme://...) double-slash
s = s.substring(0, s.indexOf("//"));
}
css += (i == 0 ? "" : "\n") + s;
}
} else if (c instanceof GvComment) {
// could check inline styles here maybe
}
}
if (userCssRules != null) {
for (String s : userCssRules) {
css += s + "\n";
}
}
if (logger.isDebugEnabled()) {
logger.debug("here's the css: " + css);
}
// pre-process the // comments out of the block comments, which isn't standard CSS
CSSOMParser parser = new CSSOMParser(new SACParserCSS3());
InputSource source = new InputSource(new StringReader(css));
CSSStyleSheet stylesheet = parser.parseStyleSheet(source, null, null);
CSSStyleSheetImpl stylesheetImpl = (CSSStyleSheetImpl) stylesheet;
RestrictedCssStyleSheetImpl restrictedStylesheetImpl = new RestrictedCssStyleSheetImpl(stylesheetImpl);
// probably need to wrap this in something which overrides importImports
// public void importImports(final boolean recursive) throws DOMException {
// or provide my own URI handler and set a weird base URI
// stylesheetImpl.importImports(true); // recursive = true
restrictedStylesheetImpl.importImports(true);
if (logger.isDebugEnabled()) {
logger.debug("CSS rules: " + restrictedStylesheetImpl.getCssText());
}
return restrictedStylesheetImpl;
}
Aggregations