Confluence highlighter with error/warning/unresolved supported

This commit is contained in:
Andrey Breslav
2011-07-12 21:55:37 +04:00
parent 2f3c5b0912
commit 6a3289dc97
7 changed files with 103 additions and 186 deletions
-1
View File
@@ -3,7 +3,6 @@
<component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_6" inherit-compiler-output="false">
<output url="file://$MODULE_DIR$/target/classes" />
<output-test url="file://$MODULE_DIR$/target/test-classes" />
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/src/main/resources" isTestSource="false" />
@@ -1,174 +0,0 @@
/* It's an automatically generated code. Do not modify it. */
package org.jetbrains.jet.confluence;
import org.jetbrains.jet.confluence.JetTokens;
%%
%unicode
%class _JetLexer
%function advance
%type JetToken
%eof{ return;
%eof}
DIGIT=[0-9]
HEX_DIGIT=[0-9A-Fa-f]
WHITE_SPACE_CHAR=[\ \t\f\r]
// TODO: prohibit '$' in identifiers?
PLAIN_IDENTIFIER=[:jletter:] [:jletterdigit:]*
// TODO: this one MUST allow everything accepted by the runtime
// TODO: Replace backticks by one backslash in the begining
ESCAPED_IDENTIFIER = `{PLAIN_IDENTIFIER}`
IDENTIFIER = {PLAIN_IDENTIFIER}|{ESCAPED_IDENTIFIER}
FIELD_IDENTIFIER = \${IDENTIFIER}
LABEL_IDENTIFIER = \@{IDENTIFIER}
BLOCK_COMMENT=("/*"[^"*"]{COMMENT_TAIL})|"/*"
// TODO: Wiki markup for doc comments?
DOC_COMMENT="/*""*"+("/"|([^"/""*"]{COMMENT_TAIL}))?
COMMENT_TAIL=([^"*"]*("*"+[^"*""/"])?)*("*"+"/")?
EOL_COMMENT="/""/"[^\n]*
INTEGER_LITERAL={DECIMAL_INTEGER_LITERAL}|{HEX_INTEGER_LITERAL}|{BIN_INTEGER_LITERAL}
DECIMAL_INTEGER_LITERAL=(0|([1-9]({DIGIT})*))
HEX_INTEGER_LITERAL=0[Xx]({HEX_DIGIT})*
BIN_INTEGER_LITERAL=0[Bb]({DIGIT})*
LONG_LITERAL=({INTEGER_LITERAL})[Ll]
//FLOAT_LITERAL=(({FLOATING_POINT_LITERAL1})[Ff])|(({FLOATING_POINT_LITERAL2})[Ff])|(({FLOATING_POINT_LITERAL3})[Ff])|(({FLOATING_POINT_LITERAL4})[Ff])
//DOUBLE_LITERAL=(({FLOATING_POINT_LITERAL1})[Dd]?)|(({FLOATING_POINT_LITERAL2})[Dd]?)|(({FLOATING_POINT_LITERAL3})[Dd]?)|(({FLOATING_POINT_LITERAL4})[Dd])
DOUBLE_LITERAL={FLOATING_POINT_LITERAL1}|{FLOATING_POINT_LITERAL2}|{FLOATING_POINT_LITERAL3}|{FLOATING_POINT_LITERAL4}
FLOATING_POINT_LITERAL1=({DIGIT})+"."({DIGIT})+({EXPONENT_PART})?
FLOATING_POINT_LITERAL2="."({DIGIT})+({EXPONENT_PART})?
FLOATING_POINT_LITERAL3=({DIGIT})+({EXPONENT_PART})
FLOATING_POINT_LITERAL4=({DIGIT})+
EXPONENT_PART=[Ee]["+""-"]?({DIGIT})*
HEX_FLOAT_LITERAL={HEX_SIGNIFICAND}{BINARY_EXPONENT}[Ff]
//HEX_DOUBLE_LITERAL={HEX_SIGNIFICAND}{BINARY_EXPONENT}[Dd]?
HEX_DOUBLE_LITERAL={HEX_SIGNIFICAND}{BINARY_EXPONENT}?
BINARY_EXPONENT=[Pp][+-]?{DIGIT}+
HEX_SIGNIFICAND={HEX_INTEGER_LITERAL}|0[Xx]{HEX_DIGIT}*\.{HEX_DIGIT}+
//HEX_SIGNIFICAND={HEX_INTEGER_LITERAL}|{HEX_INTEGER_LITERAL}\.|0[Xx]{HEX_DIGIT}*\.{HEX_DIGIT}+
CHARACTER_LITERAL="'"([^\\\'\n]|{ESCAPE_SEQUENCE})*("'"|\\)?
// TODO: introduce symbols (e.g. 'foo) as another way to write string literals
STRING_LITERAL=\"([^\\\"\n]|{ESCAPE_SEQUENCE})*(\"|\\)?
ESCAPE_SEQUENCE=\\[^\n]
// ANY_ESCAPE_SEQUENCE = \\[^]
THREE_QUO = (\"\"\")
ONE_TWO_QUO = (\"[^\"]) | (\"\"[^\"])
QUO_STRING_CHAR = [^\"] | {ONE_TWO_QUO}
RAW_STRING_LITERAL = {THREE_QUO} {QUO_STRING_CHAR}* {THREE_QUO}?
%%
<YYINITIAL> {BLOCK_COMMENT} { return JetTokens.BLOCK_COMMENT; }
<YYINITIAL> {DOC_COMMENT} { return JetTokens.DOC_COMMENT; }
\n {return JetTokens.WHITE_SPACE; }
({WHITE_SPACE_CHAR})+ { return JetTokens.WHITE_SPACE; }
<YYINITIAL> {EOL_COMMENT} { return JetTokens.EOL_COMMENT; }
<YYINITIAL> {INTEGER_LITERAL}\.\. { yypushback(2); return JetTokens.INTEGER_LITERAL; }
<YYINITIAL> {INTEGER_LITERAL} { return JetTokens.INTEGER_LITERAL; }
//<YYINITIAL> {LONG_LITERAL} { return JetTokens.LONG_LITERAL; }
//<YYINITIAL> {FLOAT_LITERAL} { return JetTokens.FLOAT_LITERAL; }
//<YYINITIAL> {HEX_FLOAT_LITERAL} { return JetTokens.FLOAT_LITERAL; }
<YYINITIAL> {DOUBLE_LITERAL} { return JetTokens.FLOAT_LITERAL; }
<YYINITIAL> {HEX_DOUBLE_LITERAL} { return JetTokens.FLOAT_LITERAL; }
<YYINITIAL> {CHARACTER_LITERAL} { return JetTokens.CHARACTER_LITERAL; }
<YYINITIAL> {STRING_LITERAL} { return JetTokens.STRING_LITERAL; }
// TODO: Decide what to do with """ ... """"
<YYINITIAL> {RAW_STRING_LITERAL} { return JetTokens.RAW_STRING_LITERAL; }
<YYINITIAL> "namespace" { return JetTokens.NAMESPACE_KEYWORD ;}
<YYINITIAL> "extension" { return JetTokens.EXTENSION_KEYWORD ;}
<YYINITIAL> "continue" { return JetTokens.CONTINUE_KEYWORD ;}
<YYINITIAL> "return" { return JetTokens.RETURN_KEYWORD ;}
<YYINITIAL> "typeof" { return JetTokens.TYPEOF_KEYWORD ;}
<YYINITIAL> "object" { return JetTokens.OBJECT_KEYWORD ;}
<YYINITIAL> "while" { return JetTokens.WHILE_KEYWORD ;}
<YYINITIAL> "break" { return JetTokens.BREAK_KEYWORD ;}
<YYINITIAL> "class" { return JetTokens.CLASS_KEYWORD ;}
<YYINITIAL> "throw" { return JetTokens.THROW_KEYWORD ;}
<YYINITIAL> "false" { return JetTokens.FALSE_KEYWORD ;}
<YYINITIAL> "when" { return JetTokens.WHEN_KEYWORD ;}
<YYINITIAL> "true" { return JetTokens.TRUE_KEYWORD ;}
<YYINITIAL> "type" { return JetTokens.TYPE_KEYWORD ;}
<YYINITIAL> "this" { return JetTokens.THIS_KEYWORD ;}
<YYINITIAL> "null" { return JetTokens.NULL_KEYWORD ;}
<YYINITIAL> "else" { return JetTokens.ELSE_KEYWORD ;}
<YYINITIAL> "This" { return JetTokens.CAPITALIZED_THIS_KEYWORD ;}
<YYINITIAL> "try" { return JetTokens.TRY_KEYWORD ;}
<YYINITIAL> "val" { return JetTokens.VAL_KEYWORD ;}
<YYINITIAL> "var" { return JetTokens.VAR_KEYWORD ;}
<YYINITIAL> "fun" { return JetTokens.FUN_KEYWORD ;}
<YYINITIAL> "for" { return JetTokens.FOR_KEYWORD ;}
//<YYINITIAL> "new" { return JetTokens.NEW_KEYWORD ;}
<YYINITIAL> "is" { return JetTokens.IS_KEYWORD ;}
<YYINITIAL> "in" { return JetTokens.IN_KEYWORD ;}
<YYINITIAL> "if" { return JetTokens.IF_KEYWORD ;}
<YYINITIAL> "do" { return JetTokens.DO_KEYWORD ;}
<YYINITIAL> "as" { return JetTokens.AS_KEYWORD ;}
<YYINITIAL> {FIELD_IDENTIFIER} { return JetTokens.FIELD_IDENTIFIER; }
<YYINITIAL> {IDENTIFIER} { return JetTokens.IDENTIFIER; }
<YYINITIAL> {LABEL_IDENTIFIER} { return JetTokens.LABEL_IDENTIFIER; }
<YYINITIAL> "===" { return JetTokens.EQEQEQ ; }
<YYINITIAL> "!==" { return JetTokens.EXCLEQEQEQ; }
<YYINITIAL> "!in" { return JetTokens.NOT_IN; }
<YYINITIAL> "!is" { return JetTokens.NOT_IS; }
<YYINITIAL> "as?" { return JetTokens.AS_SAFE; }
<YYINITIAL> "++" { return JetTokens.PLUSPLUS ; }
<YYINITIAL> "--" { return JetTokens.MINUSMINUS; }
<YYINITIAL> "<=" { return JetTokens.LTEQ ; }
<YYINITIAL> ">=" { return JetTokens.GTEQ ; }
<YYINITIAL> "==" { return JetTokens.EQEQ ; }
<YYINITIAL> "!=" { return JetTokens.EXCLEQ ; }
<YYINITIAL> "&&" { return JetTokens.ANDAND ; }
<YYINITIAL> "||" { return JetTokens.OROR ; }
<YYINITIAL> "?." { return JetTokens.SAFE_ACCESS;}
<YYINITIAL> "?:" { return JetTokens.ELVIS ; }
//<YYINITIAL> ".*" { return JetTokens.MAP ; }
//<YYINITIAL> ".?" { return JetTokens.FILTER ; }
<YYINITIAL> "*=" { return JetTokens.MULTEQ ; }
<YYINITIAL> "/=" { return JetTokens.DIVEQ ; }
<YYINITIAL> "%=" { return JetTokens.PERCEQ ; }
<YYINITIAL> "+=" { return JetTokens.PLUSEQ ; }
<YYINITIAL> "-=" { return JetTokens.MINUSEQ ; }
<YYINITIAL> "->" { return JetTokens.ARROW ; }
<YYINITIAL> "=>" { return JetTokens.DOUBLE_ARROW; }
<YYINITIAL> ".." { return JetTokens.RANGE ; }
<YYINITIAL> "@@" { return JetTokens.ATAT ; }
<YYINITIAL> "[" { return JetTokens.LBRACKET ; }
<YYINITIAL> "]" { return JetTokens.RBRACKET ; }
<YYINITIAL> "{" { return JetTokens.LBRACE ; }
<YYINITIAL> "}" { return JetTokens.RBRACE ; }
<YYINITIAL> "(" { return JetTokens.LPAR ; }
<YYINITIAL> ")" { return JetTokens.RPAR ; }
<YYINITIAL> "." { return JetTokens.DOT ; }
<YYINITIAL> "*" { return JetTokens.MUL ; }
<YYINITIAL> "+" { return JetTokens.PLUS ; }
<YYINITIAL> "-" { return JetTokens.MINUS ; }
<YYINITIAL> "!" { return JetTokens.EXCL ; }
<YYINITIAL> "/" { return JetTokens.DIV ; }
<YYINITIAL> "%" { return JetTokens.PERC ; }
<YYINITIAL> "<" { return JetTokens.LT ; }
<YYINITIAL> ">" { return JetTokens.GT ; }
<YYINITIAL> "?" { return JetTokens.QUEST ; }
<YYINITIAL> ":" { return JetTokens.COLON ; }
<YYINITIAL> ";" { return JetTokens.SEMICOLON ; }
<YYINITIAL> "=" { return JetTokens.EQ ; }
<YYINITIAL> "," { return JetTokens.COMMA ; }
<YYINITIAL> "#" { return JetTokens.HASH ; }
<YYINITIAL> "@" { return JetTokens.AT ; }
<YYINITIAL> . { return JetTokens.BAD_CHARACTER; }
@@ -10,10 +10,10 @@ import com.intellij.psi.TokenType;
import com.intellij.psi.tree.IElementType;
import org.apache.velocity.VelocityContext;
import java.io.IOException;
import java.io.StringReader;
import java.util.HashMap;
import java.util.Map;
import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author abreslav
@@ -31,7 +31,72 @@ public class JetMacro extends BaseMacro {
@Override
public String execute(Map map, String code, RenderContext renderContext) throws MacroException {
class ExtraTag {
final String name;
final String message;
final int start;
int end;
ExtraTag(String name, String message, int start) {
this.name = name;
this.message = message;
this.start = start;
}
}
String[] knownExtraTagNames = {"error", "warning", "unresolved"};
Map<String, Pattern> openTags = new HashMap<String, Pattern>();
Map<String, Pattern> closeTags = new HashMap<String, Pattern>();
for (String name : knownExtraTagNames) {
Pattern open = Pattern.compile("<" + name + "\\s*(desc=\\\"([^\n\"]*?)\\\")?>", Pattern.MULTILINE);
openTags.put(name, open);
closeTags.put(name, Pattern.compile("</" + name + ">"));
}
Stack<ExtraTag> tagStack = new Stack<ExtraTag>();
List<ExtraTag> tags = new ArrayList<ExtraTag>();
code = code.trim();
StringBuilder normalizedNewlines = new StringBuilder();
charLoop:
for (int i = 0; i < code.length(); i++) {
char c = code.charAt(i);
if (c == '\r') continue;
for (String tagName : knownExtraTagNames) {
Pattern open = openTags.get(tagName);
CharSequence remainingInput = code.subSequence(i, code.length());
Matcher openMatcher = open.matcher(remainingInput);
if (openMatcher.find() && openMatcher.start() == 0) {
tagStack.push(new ExtraTag(tagName, openMatcher.group(2), normalizedNewlines.length()));
i += openMatcher.end() - 1;
continue charLoop;
}
Pattern close = closeTags.get(tagName);
Matcher closeMatcher = close.matcher(remainingInput);
if (closeMatcher.find() && closeMatcher.start() == 0) {
if (tagStack.isEmpty()) {
return "<div style=\"jet error\">Error: unmatched closing tag: " + closeMatcher.group() + "</div>";
}
else {
ExtraTag tag = tagStack.pop();
if (!tagName.equals(tag.name)) {
return "<div style=\"jet error\">Error: unmatched closing tag: " + closeMatcher.group() + "</div>";
}
tag.end = normalizedNewlines.length();
tags.add(tag);
i += closeMatcher.end() - 1;
continue charLoop;
}
}
}
normalizedNewlines.append(c);
}
VelocityContext context = new VelocityContext(MacroUtils.defaultVelocityContext());
String renderedTemplate = VelocityUtils.getRenderedTemplate("template.velocity", context);
@@ -43,7 +108,7 @@ public class JetMacro extends BaseMacro {
);
_JetLexer jetLexer = new _JetLexer(new StringReader(""));
jetLexer.reset(code, 0, code.length(), _JetLexer.YYINITIAL);
jetLexer.reset(normalizedNewlines, 0, normalizedNewlines.length(), _JetLexer.YYINITIAL);
Map<IElementType, String> styleMap = new HashMap<IElementType, String>();
styleMap.put(JetTokens.BLOCK_COMMENT, "comment");
@@ -67,8 +132,23 @@ public class JetMacro extends BaseMacro {
styleMap.put(JetTokens.RAW_STRING_LITERAL, "string");
styleMap.put(TokenType.BAD_CHARACTER, "bad");
Iterator<ExtraTag> iterator = tags.iterator();
ExtraTag tag = iterator.hasNext() ? iterator.next() : null;
while (true) {
try {
if (tag != null) {
if (tag.start == jetLexer.getTokenEnd()) {
result.append("<div class=\"jet ").append(tag.name).append("\"");
if (tag.message != null) {
result.append(" title=\"").append(tag.message).append("\"");
}
result.append(">");
}
else if (tag.end == jetLexer.getTokenEnd()) {
result.append("</div>");
tag = iterator.hasNext() ? iterator.next() : null;
}
}
IElementType token = jetLexer.advance();
if (token == null) break;
CharSequence yytext = jetLexer.yytext();
@@ -90,7 +170,7 @@ public class JetMacro extends BaseMacro {
}
result.append("<code class=\"jet ").append(style).append("\">").append(yytext).append("</code>");
} catch (IOException e) {
} catch (Throwable e) {
result.append("ERROR IN HIGHLIGHTER: ").append(e.getClass().getSimpleName()).append(" : ").append(e.getMessage());
}
}
@@ -1,4 +1,4 @@
/* The following code was generated by JFlex 1.4.3 on 7/12/11 6:40 PM */
/* The following code was generated by JFlex 1.4.3 on 7/12/11 9:54 PM */
/* It's an automatically generated code. Do not modify it. */
package org.jetbrains.jet.lexer;
@@ -14,7 +14,7 @@ import org.jetbrains.jet.lexer.JetTokens;
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
* on 7/12/11 6:40 PM from the specification file
* on 7/12/11 9:54 PM from the specification file
* <tt>/Users/abreslav/work/jet/confluence/../idea/src/org/jetbrains/jet/lexer/Jet.flex</tt>
*/
class _JetLexer implements FlexLexer {
@@ -1,4 +1,4 @@
<atlassian-plugin key="${project.groupId}.${project.artifactId}" name="${project.name}" plugins-version="2">
<atlassian-plugin key="${project.groupId}.${project.artifactId}" name="jet" plugins-version="2">
<plugin-info>
<description>${project.description}</description>
<version>${project.version}</version>
@@ -11,5 +11,6 @@
<web-resource key="resources">
    <resource type="download" name="jet.css" location="jet.css"/>
    <resource type="download" name="underline.gif" location="underline.gif"/>
</web-resource>
</atlassian-plugin>
+12 -1
View File
@@ -20,7 +20,6 @@
}
.jet.string {
color : #000099;
font-weight: bold;
}
.jet.escape {
font-weight: bold;
@@ -37,3 +36,15 @@
background-color : #FF9999;
color:black;
}
.jet.error {
background: url(underline.gif) bottom repeat-x;
display:inline;
}
.jet.warning {
background-color : #f5eabb;
display:inline;
}
.jet.unresolved {
color : red;
display:inline;
}
@@ -1,4 +1,4 @@
/* The following code was generated by JFlex 1.4.3 on 7/12/11 1:25 PM */
/* The following code was generated by JFlex 1.4.3 on 7/12/11 9:54 PM */
/* It's an automatically generated code. Do not modify it. */
package org.jetbrains.jet.lexer;
@@ -14,7 +14,7 @@ import org.jetbrains.jet.lexer.JetTokens;
/**
* This class is a scanner generated by
* <a href="http://www.jflex.de/">JFlex</a> 1.4.3
* on 7/12/11 1:25 PM from the specification file
* on 7/12/11 9:54 PM from the specification file
* <tt>/Users/abreslav/work/jet/idea/src/org/jetbrains/jet/lexer/Jet.flex</tt>
*/
class _JetLexer implements FlexLexer {