Skip to content

Commit

Permalink
Refactoring in JetMacro
Browse files Browse the repository at this point in the history
  • Loading branch information
NataliaUkhorskaya committed Apr 19, 2012
1 parent bbc8e37 commit 8074629
Show file tree
Hide file tree
Showing 6 changed files with 195 additions and 121 deletions.
2 changes: 1 addition & 1 deletion confluence/buildConfluenceLexer.xml
@@ -1,6 +1,6 @@
<project name="ConfluenceLexer" default="confluenceLexer"> <project name="ConfluenceLexer" default="confluenceLexer">
<property name="home" value="${basedir}"/> <property name="home" value="${basedir}"/>
<property file="${home}/../compiler/frontend/idea.properties"/> <property file="${home}/../ideaSDK/bin/idea.properties"/>


<property name="flex.base" value="${idea.home}/tools/lexer/jflex-1.4"/> <property name="flex.base" value="${idea.home}/tools/lexer/jflex-1.4"/>
<property name="out.dir" value="${basedir}/tmpout"/> <property name="out.dir" value="${basedir}/tmpout"/>
Expand Down
47 changes: 47 additions & 0 deletions confluence/src/main/java/org/jetbrains/jet/ConfluenceUtils.java
@@ -0,0 +1,47 @@
package org.jetbrains.jet;

/**
* @author Natalia.Ukhorskaya
*/

public class ConfluenceUtils {

public static void escapeHTML(StringBuilder builder, CharSequence seq) {
if (seq == null) return;
for (int i = 0; i < seq.length(); i++) {
char c = seq.charAt(i);
switch (c) {
case '<':
builder.append("&lt;");
break;
case '>':
builder.append("&gt;");
break;
case '&':
builder.append("&amp;");
break;
case ' ':
builder.append("&nbsp;");
break;
case '"':
builder.append("&quot;");
break;
default:
builder.append(c);
}
}
}

public static String getErrorInHtml(Throwable e, String info) {
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append("<div class=\"jet herror\">Jet highlighter error [").append(e.getClass().getSimpleName()).append("]: ");
ConfluenceUtils.escapeHTML(stringBuilder, e.getMessage());
stringBuilder.append("<br/>");
stringBuilder.append("Original text:");
stringBuilder.append("<pre>");
ConfluenceUtils.escapeHTML(stringBuilder, info);
stringBuilder.append("</pre>");
stringBuilder.append("</div>");
return stringBuilder.toString();
}
}
167 changes: 47 additions & 120 deletions confluence/src/main/java/org/jetbrains/jet/lexer/JetMacro.java
Expand Up @@ -25,6 +25,10 @@
import com.intellij.psi.TokenType; import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType; import com.intellij.psi.tree.IElementType;
import org.apache.velocity.VelocityContext; import org.apache.velocity.VelocityContext;
import org.jetbrains.jet.ConfluenceUtils;
import org.jetbrains.jet.tags.StyledDivTagType;
import org.jetbrains.jet.tags.TagData;
import org.jetbrains.jet.tags.TagType;


import java.io.StringReader; import java.io.StringReader;
import java.util.*; import java.util.*;
Expand All @@ -38,61 +42,6 @@ public class JetMacro extends BaseMacro {


public static final StringReader DUMMY_READER = new StringReader(""); public static final StringReader DUMMY_READER = new StringReader("");


private static class TagData {
final TagType type;
final String message;
final int start;
final boolean nextToken;
int end;

TagData(TagType type, String message, int start, boolean nextToken) {
this.type = type;
this.message = message;
this.start = start;
this.nextToken = nextToken;
}
}

private static abstract class TagType {
public final String tagName;

private TagType(String tagName) {
this.tagName = tagName;
}

public abstract void appendOpenTag(StringBuilder builder, TagData tagData);
public abstract void appendCloseTag(StringBuilder builder, TagData tagData);

@Override
public String toString() {
return tagName;
}
}

private static class StyledDivTagType extends TagType {

private StyledDivTagType(String tagName) {
super(tagName);
}

@Override
public void appendOpenTag(StringBuilder builder, TagData tagData) {
assert tagData.type == this;
builder.append("<div class=\"jet ").append(tagName).append("\"");
if (tagData.message != null) {
builder.append(" title=\"");
escapeHTML(builder, tagData.message);
builder.append("\"");
}
builder.append(">");
}

@Override
public void appendCloseTag(StringBuilder builder, TagData tagData) {
builder.append("</div>");
}
}

private static final TagType[] knownExtraTagTypes = { private static final TagType[] knownExtraTagTypes = {
new StyledDivTagType("error"), new StyledDivTagType("error"),
new StyledDivTagType("warning"), new StyledDivTagType("warning"),
Expand All @@ -101,7 +50,7 @@ public void appendCloseTag(StringBuilder builder, TagData tagData) {
@Override @Override
public void appendOpenTag(StringBuilder builder, TagData tagData) { public void appendOpenTag(StringBuilder builder, TagData tagData) {
builder.append("<a class=\"jet ref\" href=\"#"); builder.append("<a class=\"jet ref\" href=\"#");
builder.append(tagData.message); builder.append(tagData.getMessage());
builder.append("\">"); builder.append("\">");
} }


Expand All @@ -114,7 +63,7 @@ public void appendCloseTag(StringBuilder builder, TagData tagData) {
@Override @Override
public void appendOpenTag(StringBuilder builder, TagData tagData) { public void appendOpenTag(StringBuilder builder, TagData tagData) {
builder.append("<a name=\""); builder.append("<a name=\"");
builder.append(tagData.message); builder.append(tagData.getMessage());
builder.append("\">"); builder.append("\">");
} }


Expand All @@ -127,7 +76,7 @@ public void appendCloseTag(StringBuilder builder, TagData tagData) {
@Override @Override
public void appendOpenTag(StringBuilder builder, TagData tagData) { public void appendOpenTag(StringBuilder builder, TagData tagData) {
builder.append("<a class=\"jet anchor\" href=\""); builder.append("<a class=\"jet anchor\" href=\"");
builder.append(tagData.message); builder.append(tagData.getMessage());
builder.append("\">"); builder.append("\">");
} }


Expand All @@ -140,7 +89,7 @@ public void appendCloseTag(StringBuilder builder, TagData tagData) {
@Override @Override
public void appendOpenTag(StringBuilder builder, TagData tagData) { public void appendOpenTag(StringBuilder builder, TagData tagData) {
builder.append("<div style=\""); builder.append("<div style=\"");
builder.append(tagData.message); builder.append(tagData.getMessage());
builder.append("\">"); builder.append("\">");
} }


Expand All @@ -153,7 +102,7 @@ public void appendCloseTag(StringBuilder builder, TagData tagData) {
@Override @Override
public void appendOpenTag(StringBuilder builder, TagData tagData) { public void appendOpenTag(StringBuilder builder, TagData tagData) {
builder.append("<div class=\""); builder.append("<div class=\"");
builder.append(tagData.message); builder.append(tagData.getMessage());
builder.append("\">"); builder.append("\">");
} }


Expand All @@ -167,9 +116,10 @@ public void appendCloseTag(StringBuilder builder, TagData tagData) {
private static final Map<TagType, Pattern> nextTokenTags = new HashMap<TagType, Pattern>(); private static final Map<TagType, Pattern> nextTokenTags = new HashMap<TagType, Pattern>();
private static final Map<TagType, Pattern> closedTags = new HashMap<TagType, Pattern>(); private static final Map<TagType, Pattern> closedTags = new HashMap<TagType, Pattern>();
private static final Map<TagType, Pattern> closeTags = new HashMap<TagType, Pattern>(); private static final Map<TagType, Pattern> closeTags = new HashMap<TagType, Pattern>();

static { static {
for (TagType type : knownExtraTagTypes) { for (TagType type : knownExtraTagTypes) {
String tagName = type.tagName; String tagName = type.getTagName();
openTags.put(type, Pattern.compile("<" + tagName + "\\s*((desc)?=\\\"([^\n\"]*?)\\\")?>", Pattern.MULTILINE)); openTags.put(type, Pattern.compile("<" + tagName + "\\s*((desc)?=\\\"([^\n\"]*?)\\\")?>", Pattern.MULTILINE));
closeTags.put(type, Pattern.compile("</" + tagName + ">")); closeTags.put(type, Pattern.compile("</" + tagName + ">"));


Expand All @@ -179,6 +129,7 @@ public void appendCloseTag(StringBuilder builder, TagData tagData) {
} }


private static final Map<IElementType, String> styleMap = new HashMap<IElementType, String>(); private static final Map<IElementType, String> styleMap = new HashMap<IElementType, String>();

static { static {
styleMap.put(JetTokens.BLOCK_COMMENT, "jet-comment"); styleMap.put(JetTokens.BLOCK_COMMENT, "jet-comment");
styleMap.put(JetTokens.DOC_COMMENT, "jet-comment"); styleMap.put(JetTokens.DOC_COMMENT, "jet-comment");
Expand All @@ -198,7 +149,6 @@ public void appendCloseTag(StringBuilder builder, TagData tagData) {
styleMap.put(JetTokens.LABEL_IDENTIFIER, "label"); styleMap.put(JetTokens.LABEL_IDENTIFIER, "label");
styleMap.put(JetTokens.ATAT, "label"); styleMap.put(JetTokens.ATAT, "label");
styleMap.put(JetTokens.FIELD_IDENTIFIER, "field"); styleMap.put(JetTokens.FIELD_IDENTIFIER, "field");
styleMap.put(JetTokens.RAW_STRING_LITERAL, "string");
styleMap.put(TokenType.BAD_CHARACTER, "bad"); styleMap.put(TokenType.BAD_CHARACTER, "bad");
} }


Expand All @@ -212,32 +162,6 @@ public RenderMode getBodyRenderMode() {
return RenderMode.allow(0); return RenderMode.allow(0);
} }


private static void escapeHTML(StringBuilder builder, CharSequence seq) {
if (seq == null) return;
for (int i = 0; i < seq.length(); i++) {
char c = seq.charAt(i);
switch (c) {
case '<':
builder.append("&lt;");
break;
case '>':
builder.append("&gt;");
break;
case '&':
builder.append("&amp;");
break;
case ' ':
builder.append("&nbsp;");
break;
case '"':
builder.append("&quot;");
break;
default:
builder.append(c);
}
}
}

private String addNewLineOpenTag() { private String addNewLineOpenTag() {
return "<div class=\"line\">"; return "<div class=\"line\">";
} }
Expand All @@ -246,7 +170,7 @@ private String addNewLineCloseTag() {
return "</div>"; return "</div>";
} }


private void addNewLines(StringBuilder result, String yytext) { private void convertNewLines(StringBuilder result, String yytext) {
for (int i = 0; i < yytext.length(); i++) { for (int i = 0; i < yytext.length(); i++) {
if (yytext.charAt(i) == '\n') { if (yytext.charAt(i) == '\n') {
result.append("&nbsp;"); result.append("&nbsp;");
Expand All @@ -259,14 +183,23 @@ private void addNewLines(StringBuilder result, String yytext) {
@Override @Override
public String execute(Map map, String code, RenderContext renderContext) throws MacroException { public String execute(Map map, String code, RenderContext renderContext) throws MacroException {
try { try {
List<TagData> tags = new ArrayList<TagData>();

StringBuilder afterPreprocessing = preprocess(code.trim(), tags);

VelocityContext context = new VelocityContext(MacroUtils.defaultVelocityContext()); VelocityContext context = new VelocityContext(MacroUtils.defaultVelocityContext());
String renderedTemplate = VelocityUtils.getRenderedTemplate("template.velocity", context); String renderedTemplate = VelocityUtils.getRenderedTemplate("template.velocity", context);

StringBuilder result = new StringBuilder(renderedTemplate); StringBuilder result = new StringBuilder(renderedTemplate);

generateHtmlFromCode(code, result);

return result.toString();
} catch (Throwable e) {
return ConfluenceUtils.getErrorInHtml(e, code);
}
}

public void generateHtmlFromCode(String code, StringBuilder result) throws java.io.IOException {
try {
List<TagData> tags = new ArrayList<TagData>();
StringBuilder afterPreprocessing = preprocess(code.trim(), tags);

result.append( result.append(
"<div class=\"code panel\" style=\"border-width: 1px;\">" + "<div class=\"code panel\" style=\"border-width: 1px;\">" +
"<div class=\"codeContent panelContent\">" + "<div class=\"codeContent panelContent\">" +
Expand All @@ -282,24 +215,24 @@ public String execute(Map map, String code, RenderContext renderContext) throws
TagData tag = iterator.hasNext() ? iterator.next() : null; TagData tag = iterator.hasNext() ? iterator.next() : null;
while (true) { while (true) {
int tokenEnd = jetLexer.getTokenEnd(); int tokenEnd = jetLexer.getTokenEnd();
while (tag != null && tag.end < tokenEnd) { while (tag != null && tag.getEnd() < tokenEnd) {
result.append("<div class=\"jet hwarning\">Skipping a tag in the middle of a token: &lt;").append(tag.type).append("&gt;</div>"); result.append("<div class=\"jet hwarning\">Skipping a tag in the middle of a token: &lt;").append(tag.getType()).append("&gt;</div>");
tag = iterator.hasNext() ? iterator.next() : null; tag = iterator.hasNext() ? iterator.next() : null;
} }


if (tag != null) { if (tag != null) {
if (tag.start == tokenEnd) { if (tag.getStart() == tokenEnd) {
// result.append("<div class=\"jet ").append(tag.type).append("\""); // result.append("<div class=\"jet ").append(tag.type).append("\"");
// if (tag.message != null) { // if (tag.message != null) {
// result.append(" title=\"").append(tag.message).append("\""); // result.append(" title=\"").append(tag.message).append("\"");
// } // }
// result.append(">"); // result.append(">");
tag.type.appendOpenTag(result, tag); tag.getType().appendOpenTag(result, tag);
} }
} }
if (tag != null) { if (tag != null) {
if (tag.end == tokenEnd || (tag.nextToken && tag.start < tokenEnd)) { if (tag.getEnd() == tokenEnd || (tag.isNextToken() && tag.getStart() < tokenEnd)) {
tag.type.appendCloseTag(result, tag); tag.getType().appendCloseTag(result, tag);
tag = iterator.hasNext() ? iterator.next() : null; tag = iterator.hasNext() ? iterator.next() : null;
} }
} }
Expand All @@ -310,48 +243,42 @@ public String execute(Map map, String code, RenderContext renderContext) throws
String yytext = jetLexer.yytext().toString(); String yytext = jetLexer.yytext().toString();


if (yytext.contains("\n")) { if (yytext.contains("\n")) {
addNewLines(result, yytext); convertNewLines(result, yytext);
yytext = yytext.replaceAll("\n", ""); yytext = yytext.replaceAll("\n", "");
} }


String style = null; String style = null;
if (token instanceof JetKeywordToken) { if (token instanceof JetKeywordToken) {
style = "keyword"; style = "keyword";
} else if (token == JetTokens.IDENTIFIER) { }
else if (token == JetTokens.IDENTIFIER) {
for (IElementType softKeyword : JetTokens.SOFT_KEYWORDS.asSet()) { for (IElementType softKeyword : JetTokens.SOFT_KEYWORDS.asSet()) {
if (((JetKeywordToken) softKeyword).getValue().equals(yytext.toString())) { if (((JetKeywordToken) softKeyword).getValue().equals(yytext.toString())) {
style = "softkeyword"; style = "softkeyword";
break; break;
} }
} }
style = style == null ? "plain" : style; style = style == null ? "plain" : style;
} else if (styleMap.containsKey(token)) { }
else if (styleMap.containsKey(token)) {
style = styleMap.get(token); style = styleMap.get(token);
} else { }
else {
style = "plain"; style = "plain";
} }
result.append("<code class=\"jet ").append(style).append("\">"); result.append("<code class=\"jet ").append(style).append("\">");
escapeHTML(result, yytext); ConfluenceUtils.escapeHTML(result, yytext);
result.append("</code>"); result.append("</code>");
} }


result.append(addNewLineCloseTag()); result.append(addNewLineCloseTag());
result.append("</div>"); result.append("</div>");
result.append("</div>"); result.append("</div>");
result.append("</div>"); result.append("</div>");
return result.toString();
} catch (Throwable e) { } catch (Throwable e) {
StringBuilder stringBuilder = new StringBuilder(); result = new StringBuilder(ConfluenceUtils.getErrorInHtml(e, code));
stringBuilder.append("<div class=\"jet herror\">Jet highlighter error [").append(e.getClass().getSimpleName()).append("]: ");
escapeHTML(stringBuilder, e.getMessage());
stringBuilder.append("<br/>");
stringBuilder.append("Original text:");
stringBuilder.append("<pre>");
escapeHTML(stringBuilder, code);
stringBuilder.append("</pre>");
stringBuilder.append("</div>");
return stringBuilder.toString();
} }

} }


private StringBuilder preprocess(CharSequence code, Collection<TagData> tags) { private StringBuilder preprocess(CharSequence code, Collection<TagData> tags) {
Expand Down Expand Up @@ -382,11 +309,11 @@ private StringBuilder preprocess(CharSequence code, Collection<TagData> tags) {
} }
else { else {
TagData tag = tagStack.pop(); TagData tag = tagStack.pop();
if (type != tag.type) { if (type != tag.getType()) {
throw new IllegalArgumentException("Unmatched closing tag: " + closeMatcher.group()); throw new IllegalArgumentException("Unmatched closing tag: " + closeMatcher.group());
} }


tag.end = position; tag.setEnd(position);
tags.add(tag); tags.add(tag);
i += closeMatcher.end() - 1; i += closeMatcher.end() - 1;
continue charLoop; continue charLoop;
Expand All @@ -397,7 +324,7 @@ private StringBuilder preprocess(CharSequence code, Collection<TagData> tags) {
Matcher closedMatcher = matchFrom(code, i, closed); Matcher closedMatcher = matchFrom(code, i, closed);
if (closedMatcher != null) { if (closedMatcher != null) {
TagData tag = new TagData(type, closedMatcher.group(3), position, false); TagData tag = new TagData(type, closedMatcher.group(3), position, false);
tag.end = position; tag.setEnd(position);
tags.add(tag); tags.add(tag);
i += closedMatcher.end() - 1; i += closedMatcher.end() - 1;
continue charLoop; continue charLoop;
Expand All @@ -408,7 +335,7 @@ private StringBuilder preprocess(CharSequence code, Collection<TagData> tags) {
if (nextMatcher != null) { if (nextMatcher != null) {
TagData tag = new TagData(type, nextMatcher.group(3), position, true); TagData tag = new TagData(type, nextMatcher.group(3), position, true);
tags.add(tag); tags.add(tag);
tag.end = code.length(); tag.setEnd(code.length());
i += nextMatcher.end() - 1; i += nextMatcher.end() - 1;
continue charLoop; continue charLoop;
} }
Expand Down

0 comments on commit 8074629

Please sign in to comment.