/*
* Copyright 2008-2009 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*/
package visagepad;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.*;
import javax.swing.text.*;
import javax.swing.event.*;
import java.awt.Color;
import java.awt.Graphics;
import java.util.*;
import java.awt.Shape;
import org.visage.tools.antlr.v3Lexer;
import com.sun.tools.javac.util.Context;
import java.awt.Font;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.Token;
public class VisageEditorKit extends DefaultEditorKit {
public static class VisageScanner {
private static Color KEYWORD_COLOR =
new Color(127, 0, 85);
private static Color STRING_COLOR =
new Color(42, 0, 255);
private static Color COMMENT_COLOR =
new Color(63, 127, 95);
private static Color TEXT_COLOR =
Color.black;
static Set keywords = new HashSet();
final static String[] keywordArray = new String[]{
"abstract",
"after",
"and",
"as",
"assert",
"at",
"attribute",
"before",
"bind",
"bound",
"break",
"catch",
"class",
"continue",
"delete",
"else",
"exclusive",
"extends",
"false",
"finally",
"first",
"for",
"from",
"function",
"if",
"import",
"in",
"indexof",
"init",
"insert",
"instanceof",
"into",
"inverse",
"last",
"lazy",
"let",
"new",
"not",
"null",
"on",
"or",
"override",
"package",
"postinit",
"private",
"protected",
"public",
"readonly",
"replace",
"return",
"reverse",
"sizeof",
"static",
"step",
"super",
"then",
"this",
"throw",
"true",
"try",
"tween",
"typeof",
"var",
"where",
"while",
"with"
};
static {
for (int i = 0; i < keywordArray.length; i++) {
keywords.add(keywordArray[i]);
}
}
v3Lexer lexer;
int[] lineMap;
int offset;
int length;
class TokenImpl {
Token token; // antlr token
Color foreground = Color.BLACK;
Color background;
int fontStyle = -1;
int off;
TokenImpl(Token token) {
this.token = token;
switch(token.getType()) {
case v3Lexer.WS:
break;
case v3Lexer.COMMENT:
case v3Lexer.LINE_COMMENT:
case v3Lexer.DOC_COMMENT:
foreground = COMMENT_COLOR;
fontStyle = Font.ITALIC;
break;
case v3Lexer.STRING_LITERAL:
case v3Lexer.EMPTY_FORMAT_STRING:
case v3Lexer.FORMAT_STRING_LITERAL:
case v3Lexer.RBRACE_QUOTE_STRING_LITERAL:
case v3Lexer.QUOTE_LBRACE_STRING_LITERAL:
case v3Lexer.RBRACE_LBRACE_STRING_LITERAL:
foreground = STRING_COLOR;
break;
default:
if(keywords.contains(token.getText())) {
foreground =KEYWORD_COLOR;
fontStyle = Font.BOLD;
}
}
if(token.getLine() > 0)
off = offset + lineMap[token.getLine()-1] + token.getCharPositionInLine();
else
off = offset + length;
}
public Token getToken() {
return token;
}
public // antlr token
Color getForeground() {
return foreground;
}
public Color getBackground() {
return background;
}
public int getFontStyle() {
return fontStyle;
}
public int getLineNumber() {
return token.getLine();
}
public int getColumnNumber() {
return token.getCharPositionInLine();
}
public int getTokenLength() {
String text = token.getText();
if(text != null) {
switch (token.getType()) {
case v3Lexer.STRING_LITERAL:
return text.length() + 2;
case v3Lexer.EMPTY_FORMAT_STRING:
return 2;
case v3Lexer.FORMAT_STRING_LITERAL:
return text.length() + 2;
case v3Lexer.RBRACE_QUOTE_STRING_LITERAL:
return text.length() + 1;
case v3Lexer.QUOTE_LBRACE_STRING_LITERAL:
return text.length() + 1;
case v3Lexer.RBRACE_LBRACE_STRING_LITERAL:
return text.length() + 2;
default:
return text.length();
}
}else {
return 0;
}
}
public int getOffset() {
return off;
}
public boolean isEOF() {
return token.getType() == v3Lexer.EOF;
}
}
void tokenize(int offset, int length, String content) {
Context context = new Context();
ANTLRStringStream input = new ANTLRStringStream(content.toString());
lexer = new v3Lexer(context, input);
ArrayList offsets = new ArrayList();
offsets.add(new Integer(0));
char[] chs = content.toCharArray();
for (int i = 0; i < chs.length; i++) {
if (chs[i] == '\n') {
offsets.add(new Integer(i+1));
}
}
lineMap = new int[offsets.size()];
for (int i = 0; i < lineMap.length; i++) {
lineMap[i] = ((Integer)offsets.get(i)).intValue();
}
this.offset = offset;
this.length = length;
}
TokenImpl nextToken() {
try {
Token t = lexer.nextToken();
if(t.getType() != v3Lexer.EOF)
return new TokenImpl(t);
}catch(Throwable th) {
}
return null;
}
public void setRange(Document document, int offset, int length) {
try {
String range = document.getText(offset, length);
tokenize(offset, length, range);
} catch (BadLocationException ex) {
Logger.getLogger(VisageEditorKit.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
VisageScanner mLexer = new VisageScanner();
DocumentListener mDocumentListener = null;
class VisageView extends /*Wrapped*/PlainView {
VisageView(Element elem) {
super(elem);
}
@Override
public void paint(Graphics g, Shape a) {
super.paint(g, a);
}
@Override
protected int drawUnselectedText(Graphics g, int x, int y,
int p0, int p1)
throws BadLocationException {
//TODO
Document doc = getDocument();
mLexer.setRange(doc, p0, p1-p0);
Color last = null;
int lastFontStyle = -1;
int startPos = p0;
int mark = p0;
VisageScanner.TokenImpl tok;
Font saveFont = g.getFont();
Color saveColor = g.getColor();
int defaultFontStyle = saveFont.getStyle();
boolean first = true;
while ((tok = mLexer.nextToken()) != null) {
first = false;
if (tok.getOffset() + tok.getTokenLength() < startPos) {
continue;
}
if (tok.getOffset() > p1) {
break;
}
int p = Math.min(tok.getOffset() + tok.getTokenLength(), p1);
p = (p <= p0) ? p1 : p;
Color fg = tok.getForeground();
int fontStyle = tok.getFontStyle();
if (fontStyle < 0) {
fontStyle = defaultFontStyle;
}
if ((fg != last || fontStyle != lastFontStyle) && last != null) {
// color change, flush what we have
g.setColor(last);
if (lastFontStyle != defaultFontStyle) {
g.setFont(saveFont.deriveFont(lastFontStyle));
} else {
g.setFont(saveFont);
}
Segment text = getLineBuffer();
//System.out.println("drawing text: " + doc.getText(mark, p0- mark));
doc.getText(mark, p0 - mark, text);
x = Utilities.drawTabbedText(text, x, y, g, this, mark);
mark = p0;
}
last = fg;
lastFontStyle = fontStyle;
p0 = p;
}
if (first) {
// must have been a lexical error
last = Color.black; // hack
lastFontStyle = defaultFontStyle;
}
// flush remaining
g.setColor(last);
if (lastFontStyle != defaultFontStyle) {
g.setFont(saveFont.deriveFont(lastFontStyle));
} else {
g.setFont(saveFont);
}
Segment text = getLineBuffer();
//System.out.println("drawing text: " + doc.getText(mark, p1- mark));
doc.getText(mark, p1 - mark, text);
x = Utilities.drawTabbedText(text, x, y, g, this, mark);
g.setFont(saveFont);
g.setColor(saveColor);
return x;
}
}
@Override
public String getContentType() {
return "text/visage";
}
@Override
public final ViewFactory getViewFactory() {
return new ViewFactory() {
public View create(Element elem) {
return new VisageView(elem);
}
};
}
}