blob: 1f6e141a9358e0049701850d13eda4f9d2959aa7 [file] [log] [blame]
/*
* Copyright 2003-2007 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package groovy.ui.text;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.KeyStroke;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.Element;
import javax.swing.text.JTextComponent;
import javax.swing.text.Segment;
import javax.swing.text.Style;
import javax.swing.text.StyleConstants;
import javax.swing.text.StyledDocument;
import javax.swing.text.StyleContext;
/**
*
* @author Evan "Hippy" Slatis
*/
public class GroovyFilter extends StructuredSyntaxDocumentFilter {
// java tab policy action
private static final Action AUTO_TAB_ACTION = new AutoTabAction();
// Style names
public static final String COMMENT = "comment";
public static final String SLASH_STAR_COMMENT = "/\\*(?s:.)*?(?:\\*/|\\z)";
public static final String SLASH_SLASH_COMMENT = "//.*";
public static final String QUOTES =
"(?ms:\"{3}(?!\\\"{1,3}).*?(?:\"{3}|\\z))|(?:\"{1}(?!\\\").*?(?:\"|\\Z))";
public static final String SINGLE_QUOTES =
"(?ms:'{3}(?!'{1,3}).*?(?:'{3}|\\z))|(?:'[^'].*?(?:'|\\z))";
public static final String SLASHY_QUOTES = "/[^/*].*?/";
public static final String DIGIT = "\\d+?[efld]?";
public static final String IDENT = "[\\w\\$&&[\\D]][\\w\\$]*";
public static final String OPERATION = "[\\w\\$&&[\\D]][\\w\\$]* *\\(";
public static final String LEFT_PARENS = "\\(";
private static final Color COMMENT_COLOR =
Color.LIGHT_GRAY.darker().darker();
public static final String RESERVED_WORD = "reserved";
public static final String[] RESERVED_WORDS = {"\\babstract\\b",
"\\bassert\\b",
"\\bdefault\\b",
"\\bif\\b",
"\\bprivate\\b",
"\\bthis\\b",
"\\bboolean\\b",
"\\bdo\\b",
"\\bimplements\\b",
"\\bprotected\\b",
"\\bthrow\\b",
"\\bbreak\\b",
"\\bdouble\\b",
"\\bimport\\b",
"\\bpublic\\b",
"\\bthrows\\b",
"\\bbyte\\b",
"\\belse\\b",
"\\binstanceof\\b",
"\\breturn\\b",
"\\btransient\\b",
"\\bcase\\b",
"\\bextends\\b",
"\\bint\\b",
"\\bshort\\b",
"\\btry\\b",
"\\bcatch\\b",
"\\bfinal\\b",
"\\binterface\\b",
"\\benum\\b",
"\\bstatic\\b",
"\\bvoid\\b",
"\\bchar\\b",
"\\bfinally\\b",
"\\blong\\b",
"\\bstrictfp\\b",
"\\bvolatile\\b",
"\\bclass\\b",
"\\bfloat\\b",
"\\bnative\\b",
"\\bsuper\\b",
"\\bwhile\\b",
"\\bconst\\b",
"\\bfor\\b",
"\\bnew\\b",
"\\bswitch\\b",
"\\bcontinue\\b",
"\\bgoto\\b",
"\\bpackage\\b",
"\\bdef\\b",
"\\bas\\b",
"\\bin\\b",
"\\bsynchronized\\b",
"\\bnull\\b"};
/**
* Creates a new instance of GroovyFilter
*/
public GroovyFilter(DefaultStyledDocument doc) {
super(doc);
init();
}
private void init() {
StyleContext styleContext = StyleContext.getDefaultStyleContext();
Style defaultStyle = styleContext.getStyle(StyleContext.DEFAULT_STYLE);
Style comment = styleContext.addStyle(COMMENT, defaultStyle);
StyleConstants.setForeground(comment, COMMENT_COLOR);
StyleConstants.setItalic(comment, true);
Style quotes = styleContext.addStyle(QUOTES, defaultStyle);
StyleConstants.setForeground(quotes, Color.MAGENTA.darker().darker());
Style charQuotes = styleContext.addStyle(SINGLE_QUOTES, defaultStyle);
StyleConstants.setForeground(charQuotes, Color.GREEN.darker().darker());
Style slashyQuotes = styleContext.addStyle(SLASHY_QUOTES, defaultStyle);
StyleConstants.setForeground(slashyQuotes, Color.ORANGE.darker());
Style digit = styleContext.addStyle(DIGIT, defaultStyle);
StyleConstants.setForeground(digit, Color.RED.darker());
Style operation = styleContext.addStyle(OPERATION, defaultStyle);
StyleConstants.setBold(operation, true);
Style ident = styleContext.addStyle(IDENT, defaultStyle);
Style reservedWords = styleContext.addStyle(RESERVED_WORD, defaultStyle);
StyleConstants.setBold(reservedWords, true);
StyleConstants.setForeground(reservedWords, Color.BLUE.darker().darker());
Style leftParens = styleContext.addStyle(IDENT, defaultStyle);
getRootNode().putStyle(SLASH_STAR_COMMENT, comment);
getRootNode().putStyle(SLASH_SLASH_COMMENT, comment);
getRootNode().putStyle(QUOTES, quotes);
getRootNode().putStyle(SINGLE_QUOTES, charQuotes);
getRootNode().putStyle(SLASHY_QUOTES, slashyQuotes);
getRootNode().putStyle(DIGIT, digit);
getRootNode().putStyle(OPERATION, operation);
StructuredSyntaxDocumentFilter.LexerNode node = createLexerNode();
node.putStyle(RESERVED_WORDS, reservedWords);
node.putStyle(LEFT_PARENS, leftParens);
getRootNode().putChild(OPERATION, node);
getRootNode().putStyle(IDENT, ident);
node = createLexerNode();
node.putStyle(RESERVED_WORDS, reservedWords);
getRootNode().putChild(IDENT, node);
}
public static void installAutoTabAction(JTextComponent tComp) {
tComp.getActionMap().put("GroovyFilter-autoTab", AUTO_TAB_ACTION);
KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0, false);
tComp.getInputMap().put(keyStroke, "GroovyFilter-autoTab");
}
private static class AutoTabAction extends AbstractAction {
private StyledDocument doc;
private final Segment segment = new Segment();
private final StringBuffer buffer = new StringBuffer();
public void actionPerformed(ActionEvent ae) {
JTextComponent tComp = (JTextComponent)ae.getSource();
if (tComp.getDocument() instanceof StyledDocument) {
doc = (StyledDocument)tComp.getDocument();
try {
doc.getText(0, doc.getLength(), segment);
}
catch (Exception e) {
// should NEVER reach here
e.printStackTrace();
}
int offset = tComp.getCaretPosition();
int index = findTabLocation(offset);
buffer.delete(0, buffer.length());
buffer.append('\n');
if (index > -1) {
for (int i = 0; i < index + 4; i++) {
buffer.append(' ');
}
}
try {
doc.insertString(offset, buffer.toString(),
doc.getDefaultRootElement().getAttributes());
}
catch (BadLocationException ble) {
ble.printStackTrace();
}
}
}
public int findTabLocation(int offset) {
// find first {
boolean cont = true;
while (offset > -1 && cont) {
Element el = doc.getCharacterElement(offset);
Object color =
el.getAttributes().getAttribute(StyleConstants.Foreground);
if (!COMMENT_COLOR.equals(color)) {
cont = segment.array[offset] != '{' &&
segment.array[offset] != '}';
}
offset -= cont ? 1 : 0;
}
if (offset > -1 && segment.array[offset] == '{') {
while (offset > -1 &&
!Character.isWhitespace(segment.array[offset--])){
}
}
int index = offset < 0 || segment.array[offset] == '}' ? -4 : 0;
if (offset > -1) {
Element top = doc.getDefaultRootElement();
offset = top.getElement(top.getElementIndex(offset)).getStartOffset();
while (Character.isWhitespace(segment.array[offset++])) {
index++;
}
}
return index;
}
}
}