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

类别:Java 点击:0 评论:0 推荐:

3、编辑器的语法颜色功能

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()方法对没有匹配的内容进行回退读取操作

本文地址:http://com.8s8s.com/it/it14026.htm