站内搜索: 请输入搜索关键词

当前页面: 开发资料首页Eclipse 专题集成Log4j到Eclipse中—《Eclipse IN ACTION》第9章 (3)

集成Log4j到Eclipse中—《Eclipse IN ACTION》第9章 (3)

摘要: 集成Log4j到Eclipse中—《Eclipse IN ACTION》第9章 (3)

3、编辑器的语法颜色功能<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" />

1)基本概念

l 首先是定义各种Partition(文档中不重叠的文本),用以区分语法明显不同的部分

l 文档中的每个字符必须属于定义得某个Partition或缺省Partition(IDocument.DEFAULT_CONTENT_TYPE

l 注释应该属于独立的一种Partition

l 由于log4j.properties中除了注释,每行多是name=value形式,所以分成3种Partition

Ø 注释(以#开始)

Ø Value值(包括=)

Ø 缺省Partition(包括name)

l 需要提供一个Partition扫描器供TextEditor调用,来决定哪些文本属于哪个Partition

l 还需要提供Token扫描器供TextEditor调用

l Token是用来设置颜色的最小文本单元

l 每个Partition需要有唯一的Token扫描器

2Partition扫描器

l Partition扫描器通过提供的解析规则(定义Partition)进行解析,将文本区分成不同的Partition

l 本例使用JFace提供的基于规则的扫描器,所以需要在plugin.xml清单编辑器的Dependencies页中添加org.eclipse.jface.text插件

package org.xqtu.log4j.editor; 
 
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.rules.IPredicateRule;
import org.eclipse.jface.text.rules.RuleBasedPartitionScanner;
import org.eclipse.jface.text.rules.SingleLineRule;
import org.eclipse.jface.text.rules.Token;
 
public class PropertiesPartitionScanner extends RuleBasedPartitionScanner {
 
    public final static String LOG4J_COMMENT = "__log4j_comment";
 
    public final static String LOG4J_VALUE = "__log4j_value";
 
    public PropertiesPartitionScanner() {
        super();
 
        Token commentPartition = new Token(LOG4J_COMMENT);
        Token valuePartition = new Token(LOG4J_VALUE);
 
        SingleLineRule commentRule = new SingleLineRule("#", null,
                commentPartition, (char) 0, true);
        commentRule.setColumnConstraint(0);
        SingleLineRule valueRule = new SingleLineRule("=", null,
                valuePartition, (char) 0, true);
        setPredicateRules(new IPredicateRule[] { commentRule, valueRule });
    }
 
    public static String[] getLegalContentTypes() {
        return new String[] { IDocument.DEFAULT_CONTENT_TYPE,
                PropertiesPartitionScanner.LOG4J_COMMENT,
                PropertiesPartitionScanner.LOG4J_VALUE };
    }
}

l 这里扩展了RuleBasedPartitionScanner,通过读取文本,应用提供的Partition规则

l 在开始部分定义了Partition类型常量

l 在构造方法中定义了每种Partition类型(这里部包括缺省Partition类型)的规则

l 首先创建每种Partition自己唯一的Token对象

l 使用SingleLineRule定义Partition规则,SingleLineRule包括四个参数:

Ø 开始序列匹配模式

Ø 结束序列匹配模式

Ø Escape字符

Ø 设置为true表示当到达文件结束时终止

l setColumnConstraint()方法设置Partition规则的列限制:只返回匹配从指定列数开始的符合规则的Token

l setPredicateRules()方法告诉Partition扫描器定义的Partition规则

l 最后的getLegalContentTypes()方法返回该Partition扫描器支持的Partition类型

3Token管理器

l 颜色(SWT Color类的特定实例)是有限的系统资源,需要跟踪它们,对它们进行管理:不多分配,在用完之后释放它们

l Token管理器用于对Token和颜色都进行跟踪和管理,主要目的是支持允许用户在Preferences中设置颜色的功能

package org.xqtu.log4j.editor;
 
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
 
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.resource.StringConverter;
import org.eclipse.jface.text.TextAttribute;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.Token;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.swt.graphics.Color;
import org.eclipse.swt.graphics.RGB;
import org.eclipse.swt.widgets.Display;
 
public class TokenManager {
 
    private Map colorTable = new HashMap(10);
 
    private Map tokenTable = new HashMap(10);
 
    private final IPreferenceStore preferenceStore;
 
    public TokenManager(IPreferenceStore preferenceStore) {
        this.preferenceStore = preferenceStore;
    }
 
    public IToken getToken(String prefKey) {
        Token token = (Token) tokenTable.get(prefKey);
        if (token == null) {
            String colorName = preferenceStore.getString(prefKey);
            RGB rgb = StringConverter.asRGB(colorName);
            token = new Token(new TextAttribute(getColor(rgb)));
            tokenTable.put(prefKey, token);
        }
        return token;
    }
 
    public void dispose() {
        Iterator e = colorTable.values().iterator();
        while (e.hasNext()) {
            ((Color) e.next()).dispose();
        }
    }
 
    private Color getColor(RGB rgb) {
        Color color = (Color) colorTable.get(rgb);
        if (color == null) {
            color = new Color(Display.getCurrent(), rgb);
            colorTable.put(rgb, color);
        }
        return color;
    }
 
    public boolean affectsTextPresentation(PropertyChangeEvent event) {
        Token token = (Token) tokenTable.get(event.getProperty());
        return (token != null);
    }
 
    public void handlePreferenceStoreChanged(PropertyChangeEvent event) {
        String prefKey = event.getProperty();
        Token token = (Token) tokenTable.get(prefKey);
        if (token != null) {
            String colorName = preferenceStore.getString(prefKey);
            RGB rgb = StringConverter.asRGB(colorName);
            token.setData(new TextAttribute(getColor(rgb)));
        }
    }
}

l 开始部分定义了用于管理的Token和颜色的HashMap列表

l getToken()方法获得指定的Token:先在Token列表中查找,如果没有,就根据Preferences中获得的颜色,创建一个新的Token,并保存到Token列表中

l 在创建Token时调用getColor()方法,获得指定的颜色,其方法类似:先在颜色列表中查找,如果没有就分配一种新的颜色,并保存到颜色列表中

l TextAttribute对象用于描述文本的属性,本例只指定前景颜色,也可以指定背景颜色或式样,如粗体、斜体等

l dispose()方法用来释放所有的颜色资源

l 通常,编辑器通过注册在变化发生时调用的方法来监听Preferences的变化

Ø affectsTextPresentation()方法判断Preferences中属性的变化是否需要应用到编辑器中的文本,通常的方法只有属性是Token列表中某个Token的名字才需要应用

Ø handlePreferenceStoreChanged()方法在Preferences存储变化时应用属性变化到Toke;,同样,只有变化的属性名字是Token列表中某个Token,才会根据Preferences中指定的值替换Token的颜色

4)注释Token扫描器

l 每个Partition需要有一个对应的Token扫描器

package org.xqtu.log4j.editor.scanners;
 
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.RuleBasedScanner;
import org.xqtu.log4j.Log4jPlugin;
import org.xqtu.log4j.editor.TokenManager;
 
public class CommentScanner extends RuleBasedScanner {
 
    public CommentScanner(TokenManager tokenManager) {
        IToken commentToken = tokenManager
                .getToken(Log4jPlugin.PREF_COMMENT_COLOR);
        setDefaultReturnToken(commentToken);
    }
}

l 所有的Token扫描器都要扩展RuleBasedScanner

l 使用TokenManager的getToken()方法获得指定的Token

l Token被指派到Partition中文本的每个部分

l 由于注释Partition中的任何东西都是注释,所以不需要提供任何规则,只要指定返回的缺省Token

5)缺省Token扫描器

package org.xqtu.log4j.editor.scanners;
 
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.RuleBasedScanner;
import org.eclipse.jface.text.rules.WhitespaceRule;
import org.xqtu.log4j.Log4jPlugin;
import org.xqtu.log4j.editor.TokenManager;
 
public class DefaultScanner extends RuleBasedScanner {
 
    public DefaultScanner(TokenManager tokenManager) {
        IToken propertyToken = tokenManager
                .getToken(Log4jPlugin.PREF_PROPERTY_COLOR);
        setDefaultReturnToken(propertyToken);
        setRules(new IRule[] { new WhitespaceRule(new WhitespaceDetector()) });
    }
}

l 缺省Partition中除了空白字符以外的所有内容都被认为是属性名字,所以需要调用setRules()方法设置空白字符的规则

l 探测器WhitespaceDetector实现IWhitespaceDetector接口,决定当前内容中的字符是否为空白字符

package org.xqtu.log4j.editor.scanners;
 
import org.eclipse.jface.text.rules.IWhitespaceDetector;
 
public class WhitespaceDetector implements IWhitespaceDetector {
 
    public boolean isWhitespace(char c) {
        return Character.isWhitespace(c);
    }
 
}

6ValueToken扫描器

l Value值Token扫描器相对要复杂一些,因为需要处理关键字和象%m、%d{hh:mm:ss a}之类的格式

package org.xqtu.log4j.editor.scanners;
 
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.RuleBasedScanner;
import org.eclipse.jface.text.rules.SingleLineRule;
import org.eclipse.jface.text.rules.WhitespaceRule;
import org.eclipse.jface.text.rules.WordRule;
import org.xqtu.log4j.Log4jPlugin;
import org.xqtu.log4j.editor.TokenManager;
 
public class ValueScanner extends RuleBasedScanner {
 
       String[] keywords = { "ALL", "DEBUG", "ERROR", "FATAL", "INFO", "OFF",
                "WARN", "INHERITED", "INHERIT", "NULL", "true", "false", };
 
       public ValueScanner(TokenManager tokenManager) {
              IToken defaultToken = tokenManager
                       .getToken(Log4jPlugin.PREF_DEFAULT_COLOR);
              IToken formatToken = tokenManager
                       .getToken(Log4jPlugin.PREF_FORMAT_COLOR);
              IToken keywordToken = tokenManager
                       .getToken(Log4jPlugin.PREF_KEYWORD_COLOR);
 
              IRule braceRule = new SingleLineRule("{", "}", formatToken, (char) 0,
                       true);
 
              WordRule keywordRule = new WordRule(new WordDetector());
              for (int i = 0; i < keywords.length; i++) {
                keywordRule.addWord(keywords[i], keywordToken);
              }
 
              IRule formatRule = new FormatRule(formatToken);
 
              IRule whitespaceRule = new WhitespaceRule(new WhitespaceDetector());
 
              setDefaultReturnToken(defaultToken);
              setRules(new IRule[] { braceRule, formatRule, keywordRule,
                       whitespaceRule, });
       }
}

l Value值Token扫描器处理包括关键字、格式化和缺省三种Token

l 在开始部分定义了关键字列表,使用WordRule来探测所有关键字Token,并应用了WordDetector探测器

l WordDetector探测器实现IWordDetector接口,决定以字母开始,包含字母或数字的内容为Word

package org.xqtu.log4j.editor.scanners;
 
import org.eclipse.jface.text.rules.IWordDetector;
 
public class WordDetector implements IWordDetector {
 
    public boolean isWordStart(char c) {
        return Character.isLetter(c);
    }
 
    public boolean isWordPart(char c) {
        return Character.isLetterOrDigit(c);
    }
 
}

l {}内的内容是作为格式化Token,使用SingleLineRule定义Token规则

l 第三个规则是自定义的格式化Token规则,在后面讲述

l 同样,需要定义空白字符规则来匹配空白字符

l 其它文本作为缺省Token返回

l 最后设置应用的Token规则

7)自定义Token规则

l 由于Eclipse平台没有提供Log4j格式的规则,需要自定义规则

package org.xqtu.log4j.editor.scanners;
 
import org.eclipse.jface.text.rules.ICharacterScanner;
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.Token;
 
public class FormatRule implements IRule {
 
    private final IToken token;
 
    public FormatRule(IToken token) {
        this.token = token;
    }
 
    public IToken evaluate(ICharacterScanner scanner) {
        int c = scanner.read();
        if (c == '%') {
            do {
                c = scanner.read();
            } while (c != ICharacterScanner.EOF
                    && (Character.isLetterOrDigit((char) c) || c == '-' || c == '.'));
            scanner.unread();
 
            return token;
        }
        scanner.unread();
        return Token.UNDEFINED;
    }
 
}

l 自定义规则实现IRule接口,使用evaluate()方法逐个字符进行规则匹配

l 在构造方法中,先保存要匹配的Token

l evaluate()方法,使用IcharacterScanner逐个读取字符,进行规则匹配

l 如果以%开始就是格式化Token,读取包含字母、数字、“-”和“.”内容,作为Token返回

l 否则返回Token.UNDEFINED,表示Token没有匹配,以便Token扫描器进行下一条规则的匹配

l 其中,调用IcharacterScanner的unread()方法对没有匹配的内容进行回退读取操作



↑返回目录
前一篇: Eclipse主要插件Lomboz介绍(1)_ Introduction
后一篇: 几个重要的Eclipse插件!