IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope: Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Open source  >

为 Perl、Python 和 PHP 构建 Eclipse 开发环境

使用 Dynamic Languages Toolkit (DLTK) 创建自己的 IDE

developerWorks
前一页第 4 页,共 11 页后一页

文档选项

样例代码


对本教程的评价

帮助我们改进这些内容


DLTK 编辑器中的语法着色

语法着色是任何专业源代码编辑器最引人注目的方面之一。颜色不仅让?码的阅读更加方便,并且使输入错误更明显。图 3 显示如何通过不同的颜色将注释、数字、关键字和字符串与普通的代码区分开来。


图 3. Octave IDE 中的语法着色
Octave IDE 中的语法着色

在 Octave 编辑器中配置语法着色

DLTK 通过 4 个步骤处理语法着色:

  1. ScriptSourceViewer 通过向文档的分区器(partitioner)发出通知来响应击键。
  2. 分区器根据规则对文档的文本分区。
  3. 分区结束之后,查看器通知显示调解器(presentation reconciler)分析修改后的分区。
  4. 调解器调用销毁器/修复器(damager/repairer)来分析受影响的区域,然后应用语法着色功能。

在这种方式下,编辑器使用分治(divide-and-conquer)策略来为文本添加颜色。首先,它将文档分为多个区域。然后,分析修改后的区域并确定需要更新语法颜色的地方。接下来的两个小节将更加深入地解释这个过程,并且演示如何在 Octave IDE 中实现语法着色。





回页首


文档分区

除了文本之外,IDocument 还存储一组 Position,它们用于确定文本内部的区域的界限。这些区域不仅使语法着色成为可能(注释和代码采用不同的颜色),并且使您能够在文本的不同区域上使用不同的工具。例如,不让脚本解析器分析注释行。通过分区,可以确保解析器仅分析包含实际代码的区域。

由两个中心对象来完成文档分区:一个实现 IDocumentPartitioner,另一个实现 IPartitionTokenScanner。分区器将文本提交给扫描器进行分析,然后生成 IToken。分区器使用这些标记(token)在文档的内部设置 Position

我们希望 OctaveEditor 能够在用户打开 *.m 时自动初始化分区器和扫描器。为此,必须使用 org.eclipse.core.filebuffers.documentSetup 扩展点的一个扩展在 plugin.xml 中显式地定义文档的配置。这个扩展在文档初始化期间识别用于配置文档的类。清单 3 给出了为 Octave IDE 插件定义的扩展。


清单 3. 配置文档
					
<extension point="org.eclipse.core.filebuffers.documentSetup">
   id="org.dworks.octaveide.editor.OctaveDocumentSetup"
   name="%documentSetupName"
   <participant
      extensions="m"
      class="org.dworks.octaveide.editor.OctaveDocumentSetup">
   </participant>
</extension>    

OctaveDocumentSetup 调用 DLTK ScriptTextTools 对象初始化 *.m 文档。默认情况下,这将创建一个用作文档分区器的 FastPartitioner

每个 DLTK 编辑器都必须创建自己的 IPartitionTokenScanner 对象来读取字符和生成与分区对应的标记。例如,如果想要为以 ‘/*’ 开始并以 ‘*/’ 结束的文本创建一个分区,则要配置扫描器,让它在遇到这种形式的文本时生成正确的标记。Octave 插件将文本分为 3 个区域:

注释
OCTAVE_COMMENT 识别,它等效于 "__octave_comment__"
字符串
OCTAVE_STRING 识别,它等效于 "__octave_string__"
普通脚本代码
IDocument.DEFAULT_CONTENT_TYPE 识别,它等效于 "__dftl_partition_content_type"

这些分区是在 IOctavePartititons 接口中定义的。这些分区用于初始化 FastPartitioner,后者将分区发送给分区扫描器。

可以使用一组逻辑规则识别 Octave 编辑器中的分区,因此 OctavePartitionScanner 将扩展 RuleBasedPartitionScanner 类。这个类中最重要的方法是 setPartitionRules,它接受一个 IPredicateRule 对象数组。规则的目标是将文本的各个部分转换成 IToken。从头编写规则是很困难的,庆幸的是 Eclipse 提供了 IPredicateRule 接口的许多有用实现。Octave IDE 使用其中两个来识别分区:SingleLineRuleMultiLineRule。这两个类具有类似的构造器,它们由以下信息(至少)初始化:

  • 开始分区的字符
  • 结束分区的字符
  • 对应于被识别分区的 IToken

例如,假设您希望创建这样一个规则,它在发现以单引号(')开始和结束的文本时生成一个字符串标记。这可以使用以下代码实现:

IToken stringToken = new Token(OctavePartitions.OCTAVE_STRING);
new SingleLineRule("'", "'", stringToken, '\\');

清单 4 给出了 OctavePartitionScanner 用于在 Octave 脚本中检测分区的完整代码。在遇到前面有一个百分号(%)并且后面跟着一个新行的文本时,Octave 编辑器将创建注释分区。字符串分区由单引号确定界限。


清单 4. Octave IDE 分区扫描器
					
// Declare the different tokens
IToken string = new Token(IOctavePartitions.OCTAVE_STRING);
IToken comment = new Token(IOctavePartitions.OCTAVE_COMMENT);

// Create the list of rules that produce tokens
List<IPredicateRule> rules = new ArrayList<IPredicateRule>();
rules.add(new SingleLineRule("%", "\n", comment));
rules.add(new SingleLineRule("'", "'", string));
IPredicateRule[] result = new IPredicateRule[rules.size()];
rules.toArray(result);
setPredicateRules(result);

创建 OctavePartitionScanner 并且初始化其规则之后,编辑器分区的配置就完成了。下一步就是告诉编辑器如何在分区内部扫描文本并为其添加颜色。





回页首


在分区内部扫描文本

如前所述,DLTK 编辑器依靠 ScriptSourceViewer 响应用户事件,比如击键。可以通过 ScriptSourceViewerConfiguration 对象来调整查看器的操作。像 ScriptTextTools 类一样,配置对象仅需完成少量工作。相反,它的方法识别协助源代码查看器操作的类。对于语法着色,这些 “帮助” 方法中最重要的两个是:

getPresentationReconciler()
返回在发生变更时控制文本如何显示的 IPresentationReconciler
initializeScanners()
返回一组 AbstractScriptScanner,它们像 RuleBasedPartitionScanner 在前面描述的那样执行同一类型的文本扫描

这两个方法是紧密相关的。下面的讨论解释 Octave IDE 如何实现它们,以提供文本颜色。

IPresentationReconciler

根据 Eclipse 的说法,调解器 是一个跟踪文档内容并对更改作出响应的对象。显示调解器 是通过改变文档的显示方式来响应文档更改的调解器。特别需要注意的是,IPresentationReconciler 通过调用两个对象来响应更改:

IPresentationDamager
决定文档修改的范围
IPresentationRepairer
创建一个 TextPresentation 对象来响应由 IPresentationDamager 识别到的更改

这两个对象按顺序操作。当用户在一个分区中修改文本时,IPresentationReconciler 会给 IPresentationDamager 一个分区名。在销毁器识别到修改后的区域之后,IPresentationRepairer 将分析这个区域,看看区域中文本显示的哪些地方需要更新,以及如何更新。

为简单起见,Eclipse 提供一个 DefaultDamagerRepairer 作为销毁器和修复器。Octave IDE 为这三个分区的每个分区构造一个 DefaultDamagerRepairer,并使用不同的扫描器初始化它们。清单 5 显示了这个调解器。


清单 5. 配置显示调解器
					
// Create a DefaultDamagerRepairer for the default partition (code)
DefaultDamagerRepairer dr = new DefaultDamagerRepairer(codeScanner);
reconciler.setDamager(dr, IDocument.DEFAULT_CONTENT_TYPE);
reconciler.setRepairer(dr, IDocument.DEFAULT_CONTENT_TYPE);

// Create a DefaultDamagerRepairer for string partitions
dr = new DefaultDamagerRepairer(stringScanner);
reconciler.setDamager(dr, OctavePartitions.OCTAVE_STRING);
reconciler.setRepairer(dr, OctavePartitions.OCTAVE_STRING);

// Create a DefaultDamagerRepairer for comment partitions
dr = new DefaultDamagerRepairer(commentScanner);
reconciler.setDamager(dr, OctavePartitions.OCTAVE_COMMENT);
reconciler.setRepairer(dr, OctavePartitions.OCTAVE_COMMENT);

就像分区扫描器使用规则识别分区一样,所有这些扫描器都根据类似的规则创建标记。下一小节详细讨论文本扫描器。

在分区内扫描文本

ScriptSourceViewerConfiguration 的构造器调用 initializeScanners() 创建分析文本所需的扫描器。清单 6 显示 OctaveSourceViewerConfiguration 类中 initializeScanners() 的完整实现。


清单 6. 创建脚本扫描器
					
private AbstractScriptScanner codeScanner, stringScanner, commentScanner;

protected void initializeScanners() {

   // Create a scanner for the script code
   codeScanner = new OctaveCodeScanner(getColorManager(), fPreferenceStore);
   
   // Create a scanner for string partitions
   stringScanner = new SingleTokenScriptScanner(getColorManager(), 
fPreferenceStore, IOctavePartitions.OCTAVE_STRING);
   
   // Create a scanner for comment partitions
   commentScanner = new SingleTokenScriptScanner(getColorManager(), 
fPreferenceStore, IOctavePartitions.OCTAVE_COMMENT);
}

由于分区扫描器已经识别字符串和注释,因此不需要重新分析这些分区。所以 stringScannercommentScanner 都是 SingleTokenScriptScanner。这个类并不根据规则做出决定,但通常返回相同类型的 IToken。例如,stringScanner 返回一个用 OctavePartitions.OCTAVE_STRING 初始化的标记,以及 commentScanner 返回一个用 OctavePartitions.OCTAVE_COMMENT 初始化的标记。稍后您将看到这些标记属性如何决定文本的颜色。

codeScanner 用得最多,并且是 IDE 文本分析的主力。这个扫描器是一个 OctaveCodeScanner,它像 PartitionTokenScanner 一样根据规则创建标记。它并不基于 MultiLineRuleSingleLineRule,而是基于两个 IRule 实现:

WordRule
当扫描器遇到特定的单词时返回一个标记
NumberRule
当扫描器遇到数字时返回一个标记

这些规则在 OctaveCodeScannercreateRules 方法中创建。清单 7 完整地显示了这个方法。


清单 7. 创建脚本扫描器
					
protected List<IRule> createRules() {

   // Create tokens
   IToken keywordToken = getToken(DLTKColorConstants.DLTK_KEYWORD);
   IToken numberToken = getToken(DLTKColorConstants.DLTK_NUMBER);
   IToken defaultToken = getToken(DLTKColorConstants.DLTK_DEFAULT);

   // Create and populate list
   List<IRule> ruleList = new ArrayList<IRule>();

   // Create word rule to detect keywords
   WordRule wordRule = new WordRule(new OctaveWordDetector(), defaultToken);
   for (int i = 0; i < IOctaveKeywords.keywords.length; i++)
      wordRule.addWord(IOctaveKeywords.keywords[i], keywordToken);
   ruleList.add(wordRule);

   // Create number rule to detect numbers
   NumberRule numberRule = new NumberRule(numberToken);
   ruleList.add(numberRule);

   // Set the token returned for default text
   setDefaultReturnToken(defaultToken);
   return ruleList;
}

必须将在清单 7 中创建的标记与清单 4 中的标记区分开来。Token 构造器可以以任何 Object 为参数,并且这个 Object 告诉标记接收者应该采取什么行动。在清单 4 中,使用告诉 FastPartitioner 如何更新文档分区的分区名初始化 Token。在清单 7 中,使用告诉 IDE 如何在编辑器中显示文本的 TextPresentation 对象初始化 Token

清单 7 通过调用 getToken 将每个 Token 与一个 TextPresentation 关联起来。这个方法搜索由用户首选项填充的 Map。要理解这个映射是如何更新的,必须先理解 DLTK 首选项是如何工作的。这就是接下来的讨论主题。





回页首



前一页第 4 页,共 11 页后一页
    关于 IBM 隐私条约 联系 IBM 使用条款