diff --git a/confluence/confluence.iml b/confluence/confluence.iml index fc5cac66650..b7031cfb474 100644 --- a/confluence/confluence.iml +++ b/confluence/confluence.iml @@ -3,7 +3,6 @@ - diff --git a/confluence/src/main/java/org/jetbrains/jet/confluence/Jet.flex b/confluence/src/main/java/org/jetbrains/jet/confluence/Jet.flex deleted file mode 100644 index ddb8978e4de..00000000000 --- a/confluence/src/main/java/org/jetbrains/jet/confluence/Jet.flex +++ /dev/null @@ -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}? - -%% - - {BLOCK_COMMENT} { return JetTokens.BLOCK_COMMENT; } - {DOC_COMMENT} { return JetTokens.DOC_COMMENT; } - -\n {return JetTokens.WHITE_SPACE; } -({WHITE_SPACE_CHAR})+ { return JetTokens.WHITE_SPACE; } - - {EOL_COMMENT} { return JetTokens.EOL_COMMENT; } - - {INTEGER_LITERAL}\.\. { yypushback(2); return JetTokens.INTEGER_LITERAL; } - {INTEGER_LITERAL} { return JetTokens.INTEGER_LITERAL; } -// {LONG_LITERAL} { return JetTokens.LONG_LITERAL; } - -// {FLOAT_LITERAL} { return JetTokens.FLOAT_LITERAL; } -// {HEX_FLOAT_LITERAL} { return JetTokens.FLOAT_LITERAL; } - {DOUBLE_LITERAL} { return JetTokens.FLOAT_LITERAL; } - {HEX_DOUBLE_LITERAL} { return JetTokens.FLOAT_LITERAL; } - - {CHARACTER_LITERAL} { return JetTokens.CHARACTER_LITERAL; } - {STRING_LITERAL} { return JetTokens.STRING_LITERAL; } -// TODO: Decide what to do with """ ... """" - {RAW_STRING_LITERAL} { return JetTokens.RAW_STRING_LITERAL; } - - "namespace" { return JetTokens.NAMESPACE_KEYWORD ;} - "extension" { return JetTokens.EXTENSION_KEYWORD ;} - "continue" { return JetTokens.CONTINUE_KEYWORD ;} - "return" { return JetTokens.RETURN_KEYWORD ;} - "typeof" { return JetTokens.TYPEOF_KEYWORD ;} - "object" { return JetTokens.OBJECT_KEYWORD ;} - "while" { return JetTokens.WHILE_KEYWORD ;} - "break" { return JetTokens.BREAK_KEYWORD ;} - "class" { return JetTokens.CLASS_KEYWORD ;} - "throw" { return JetTokens.THROW_KEYWORD ;} - "false" { return JetTokens.FALSE_KEYWORD ;} - "when" { return JetTokens.WHEN_KEYWORD ;} - "true" { return JetTokens.TRUE_KEYWORD ;} - "type" { return JetTokens.TYPE_KEYWORD ;} - "this" { return JetTokens.THIS_KEYWORD ;} - "null" { return JetTokens.NULL_KEYWORD ;} - "else" { return JetTokens.ELSE_KEYWORD ;} - "This" { return JetTokens.CAPITALIZED_THIS_KEYWORD ;} - "try" { return JetTokens.TRY_KEYWORD ;} - "val" { return JetTokens.VAL_KEYWORD ;} - "var" { return JetTokens.VAR_KEYWORD ;} - "fun" { return JetTokens.FUN_KEYWORD ;} - "for" { return JetTokens.FOR_KEYWORD ;} -// "new" { return JetTokens.NEW_KEYWORD ;} - "is" { return JetTokens.IS_KEYWORD ;} - "in" { return JetTokens.IN_KEYWORD ;} - "if" { return JetTokens.IF_KEYWORD ;} - "do" { return JetTokens.DO_KEYWORD ;} - "as" { return JetTokens.AS_KEYWORD ;} - - {FIELD_IDENTIFIER} { return JetTokens.FIELD_IDENTIFIER; } - {IDENTIFIER} { return JetTokens.IDENTIFIER; } - {LABEL_IDENTIFIER} { return JetTokens.LABEL_IDENTIFIER; } - - "===" { return JetTokens.EQEQEQ ; } - "!==" { return JetTokens.EXCLEQEQEQ; } - "!in" { return JetTokens.NOT_IN; } - "!is" { return JetTokens.NOT_IS; } - "as?" { return JetTokens.AS_SAFE; } - "++" { return JetTokens.PLUSPLUS ; } - "--" { return JetTokens.MINUSMINUS; } - "<=" { return JetTokens.LTEQ ; } - ">=" { return JetTokens.GTEQ ; } - "==" { return JetTokens.EQEQ ; } - "!=" { return JetTokens.EXCLEQ ; } - "&&" { return JetTokens.ANDAND ; } - "||" { return JetTokens.OROR ; } - "?." { return JetTokens.SAFE_ACCESS;} - "?:" { return JetTokens.ELVIS ; } -// ".*" { return JetTokens.MAP ; } -// ".?" { return JetTokens.FILTER ; } - "*=" { return JetTokens.MULTEQ ; } - "/=" { return JetTokens.DIVEQ ; } - "%=" { return JetTokens.PERCEQ ; } - "+=" { return JetTokens.PLUSEQ ; } - "-=" { return JetTokens.MINUSEQ ; } - "->" { return JetTokens.ARROW ; } - "=>" { return JetTokens.DOUBLE_ARROW; } - ".." { return JetTokens.RANGE ; } - "@@" { return JetTokens.ATAT ; } - "[" { return JetTokens.LBRACKET ; } - "]" { return JetTokens.RBRACKET ; } - "{" { return JetTokens.LBRACE ; } - "}" { return JetTokens.RBRACE ; } - "(" { return JetTokens.LPAR ; } - ")" { return JetTokens.RPAR ; } - "." { return JetTokens.DOT ; } - "*" { return JetTokens.MUL ; } - "+" { return JetTokens.PLUS ; } - "-" { return JetTokens.MINUS ; } - "!" { return JetTokens.EXCL ; } - "/" { return JetTokens.DIV ; } - "%" { return JetTokens.PERC ; } - "<" { return JetTokens.LT ; } - ">" { return JetTokens.GT ; } - "?" { return JetTokens.QUEST ; } - ":" { return JetTokens.COLON ; } - ";" { return JetTokens.SEMICOLON ; } - "=" { return JetTokens.EQ ; } - "," { return JetTokens.COMMA ; } - "#" { return JetTokens.HASH ; } - "@" { return JetTokens.AT ; } - - . { return JetTokens.BAD_CHARACTER; } - diff --git a/confluence/src/main/java/org/jetbrains/jet/lexer/JetMacro.java b/confluence/src/main/java/org/jetbrains/jet/lexer/JetMacro.java index 21e93c4548c..b7c031d06b8 100644 --- a/confluence/src/main/java/org/jetbrains/jet/lexer/JetMacro.java +++ b/confluence/src/main/java/org/jetbrains/jet/lexer/JetMacro.java @@ -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 openTags = new HashMap(); + Map closeTags = new HashMap(); + for (String name : knownExtraTagNames) { + Pattern open = Pattern.compile("<" + name + "\\s*(desc=\\\"([^\n\"]*?)\\\")?>", Pattern.MULTILINE); + openTags.put(name, open); + closeTags.put(name, Pattern.compile("")); + } + + Stack tagStack = new Stack(); + List tags = new ArrayList(); + 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 "
Error: unmatched closing tag: " + closeMatcher.group() + "
"; + } + else { + ExtraTag tag = tagStack.pop(); + if (!tagName.equals(tag.name)) { + return "
Error: unmatched closing tag: " + closeMatcher.group() + "
"; + } + + 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 styleMap = new HashMap(); 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 iterator = tags.iterator(); + ExtraTag tag = iterator.hasNext() ? iterator.next() : null; while (true) { try { + if (tag != null) { + if (tag.start == jetLexer.getTokenEnd()) { + result.append("
"); + } + else if (tag.end == jetLexer.getTokenEnd()) { + result.append("
"); + 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("").append(yytext).append(""); - } catch (IOException e) { + } catch (Throwable e) { result.append("ERROR IN HIGHLIGHTER: ").append(e.getClass().getSimpleName()).append(" : ").append(e.getMessage()); } } diff --git a/confluence/src/main/java/org/jetbrains/jet/lexer/_JetLexer.java b/confluence/src/main/java/org/jetbrains/jet/lexer/_JetLexer.java index b2d384a2623..5f4033af787 100644 --- a/confluence/src/main/java/org/jetbrains/jet/lexer/_JetLexer.java +++ b/confluence/src/main/java/org/jetbrains/jet/lexer/_JetLexer.java @@ -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 * JFlex 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 * /Users/abreslav/work/jet/confluence/../idea/src/org/jetbrains/jet/lexer/Jet.flex */ class _JetLexer implements FlexLexer { diff --git a/confluence/src/main/resources/atlassian-plugin.xml b/confluence/src/main/resources/atlassian-plugin.xml index 8a806b9d89b..ab5b5bcca18 100644 --- a/confluence/src/main/resources/atlassian-plugin.xml +++ b/confluence/src/main/resources/atlassian-plugin.xml @@ -1,4 +1,4 @@ - + ${project.description} ${project.version} @@ -11,5 +11,6 @@      +      diff --git a/confluence/src/main/resources/jet.css b/confluence/src/main/resources/jet.css index ebdf70be7da..5a1144267aa 100644 --- a/confluence/src/main/resources/jet.css +++ b/confluence/src/main/resources/jet.css @@ -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; +} diff --git a/idea/src/org/jetbrains/jet/lexer/_JetLexer.java b/idea/src/org/jetbrains/jet/lexer/_JetLexer.java index 68b8a48275b..a92b1640d33 100644 --- a/idea/src/org/jetbrains/jet/lexer/_JetLexer.java +++ b/idea/src/org/jetbrains/jet/lexer/_JetLexer.java @@ -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 * JFlex 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 * /Users/abreslav/work/jet/idea/src/org/jetbrains/jet/lexer/Jet.flex */ class _JetLexer implements FlexLexer {