扩展NetBeans IDE 6.0中的C/C++编辑器以提供标志实例的高亮
副标题#e#
教程需求
在继承前,请确保您从头查抄了本节的需求。
先决条件
本 教程假设您已经有一些利用 IDE 的根基常识和 Java 编程履历。
本教程所需的软 件
在开始前,您需要安装 NetBeans 6.0。您将同时需要 C/C++ 和 Java SE 支持,所 以最佳选择是选择“下载全部”选项并在安装时解除 Base IDE、Java SE 和 C/C++ 包之外的所有模块。
筹备项目
对本教程,我们需要两个项目。一个是管 理我们的插件的源代码的 NetBeans 模块。另一个是用来测试它的 C++ 项目。
创 建 NetBeans 插件模块
选择“文件”>“新建项目”。在 “新建项目”领导中,选择“种别”下的“NetBeans 模块 ”和“项目”下的“模块”。单击“下一步”。
在“名称和位置”页,在“项目名称”字段中键入 MarkOccurrences,并把“项目位置”配置到磁盘上一个适当的文件夹里。请 选中“独立模块”和“配置为主项目”,假如没有选中的话。单击 “下一步”。
在“根基模块设置”页,在“代码名称 基”字段中键入 org.netbeans.modules.markoccurrences。单击“完成 ”。
在本项目中,我们需要一些依赖干系。在“项目”窗口,右 键单击“库”节点并在“添加模块依赖干系”对话框中选择 “库”,然后添加屏幕快照里列出的各个库。C/C++ 模块 API 正处于开拓中 ,所以您需要在对话框中选择“显示非-API 模块”,以便在模块列表中看到 它们。
右键 单击各个 C/C++ 模块,选择“编辑”,然后选择“实现版本”。
建设测试应用措施
选择“文件”>“新建项目”。选 择“样例”>“C/C++”>“C/C++”种别下的 Args 项目。单击“下一步”。
在“项目名称和位置”页, 把“项目位置”配置到磁盘上一个适当的文件夹里。单击“完成” 。
现已建设了 Args_1 项目。在编辑器中打开 arg.c 源文件。我们将利用这个文 件来测试我们的模块。
建设高亮基本布局
此刻我们将利用 NetBeans API 来向 C/C++ 编辑器添加高亮显示。
#p#副标题#e#
建设高亮提供者
在标志实例项目标“源包 ”节点中右键单击包 org.netbeans.modules.markoccurrences,然后选择“ 新建”>“Java 类”。
将新类定名为 MarkOccurrencesHighlighter 并单击“完成”。
用下面的代码替换新 类中的代码:package org.netbeans.modules.markoccurrences;
import java.awt.Color;
import java.lang.ref.WeakReference;
import javax.swing.JEditorPane;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.Document;
import javax.swing.text.StyleConstants;
import org.netbeans.api.editor.settings.AttributesUtilities;
import org.netbeans.modules.cnd.modelutil.CsmUtilities;
import org.netbeans.modules.editor.NbEditorUtilities;
import org.netbeans.spi.editor.highlighting.support.OffsetsBag;
import org.openide.cookies.EditorCookie;
import org.openide.loaders.DataObject;
public class MarkOccurrencesHighlighter implements CaretListener {
private static final AttributeSet defaultColors = AttributesUtilities.createImmutable(StyleConstants.Background, new Color(236, 235, 163));
public void caretUpdate(CaretEvent e) {
bag.clear();
bag.addHighlight(0, 5, defaultColors);
}
private final WeakReference<Document> weakDoc;
public MarkOccurrencesHighlighter(Document doc) {
bag = new OffsetsBag(doc);
weakDoc = new WeakReference<Document> ((Document) doc);
DataObject dobj = NbEditorUtilities.getDataObject(weakDoc.get());
JEditorPane[] panes = CsmUtilities.getOpenedPanesInEQ(dobj.getCookie (EditorCookie.class));
if (panes != null && panes.length > 0) {
panes[0].addCaretListener(this);
}
}
private final OffsetsBag bag;
public OffsetsBag getHighlightsBag() {
return bag;
}
}本类尚未 提供任何智能成果。它只是向光标事件注册了一个侦听器,并高亮显示文档开头的标记。
建设并注册 HighlightsLayerFactory
此刻我们建设 HighlightsLayerFactory ,来让 NetBeans 知道我们的高亮显示提供者。
向项目源文件添加一个新的 Java 类,并将其定名为 MarkOccurrencesHighlightsLayerFactory。
#p#分页标题#e#
用下面的代码替 换新类中的代码:package org.netbeans.modules.markoccurrences;
import javax.swing.text.Document;
import org.netbeans.spi.editor.highlighting.HighlightsLayer;
import org.netbeans.spi.editor.highlighting.HighlightsLayerFactory;
import org.netbeans.spi.editor.highlighting.ZOrder;
public class MarkOccurrencesHighlightsLayerFactory implements HighlightsLayerFactory {
public static MarkOccurrencesHighlighter getMarkOccurrencesHighlighter(Document doc) {
MarkOccurrencesHighlighter highlighter = (MarkOccurrencesHighlighter) doc.getProperty(MarkOccurrencesHighlighter.class);
if (highlighter == null) {
doc.putProperty (MarkOccurrencesHighlighter.class, highlighter = new MarkOccurrencesHighlighter(doc));
}
return highlighter;
}
public HighlightsLayer[] createLayers(Context context) {
return new HighlightsLayer[] {
HighlightsLayer.create(
MarkOccurrencesHighlighter.class.getName(),
ZOrder.CARET_RACK.forPosition(2000),
true,
getMarkOccurrencesHighlighter(context.getDocument ()).getHighlightsBag())
};
}
}
我们已 经提供了一个 HighlightsLayerFactory 的实现,它用 MarkOccurrencesHighlighte类提 供的数据建设了一个高亮显示层。此刻我们需要在 layer.xml 中注册这个类。打开 org.netbeans.modules.markoccurrences 包中的 layer.xml,并将其内容变动为以下内 容:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE filesystem PUBLIC "-//NetBeans//DTD Filesystem 1.1//EN" "http://www.netbeans.org/dtds/filesystem- 1_1.dtd">
<filesystem>
<folder name="Editors">
<folder name="text">
<folder name="x- c++">
<file name="org-netbeans-modules- markoccurrences-MarkOccurrencesHighlightsLayerFactory.instance" />
</folder>
<folder name="x- c">
<file name="org-netbeans-modules- markoccurrences-MarkOccurrencesHighlightsLayerFactory.instance" />
</folder>
</folder>
</folder>
</filesystem>
此刻我们已经筹备好第一次 运行我们的高亮显示器了。
生成项目。
项目乐成生成后,运行它。
打开我们在前一节中建设的 Args 项目。
在编辑器中打开 args.c 文件, 并单击文件中的任一位置。高亮显示看起来就会像下面的例子一样:
太棒 了。我们的高亮显示事情了。此刻我们来教它变得更有用。
从 C/C++ 语言模子收 集信息
在 MarkOccurrencesHighlighter.java 类中,删除我们大致实现的 caretUpdate() ,并添加以下代码:private WeakReference<CsmFile> weakFile;
public void caretUpdate(CaretEvent e) {
bag.clear ();
CsmFile file = getCsmFile();
if (file != null) {
CsmReference ref = CsmReferenceResolver.getDefault().findReference(file, e.getDot());
if (ref != null && ref.getReferencedObject() != null) {
Collection<CsmReference> out = CsmReferenceRepository.getDefault().getReferences(ref.getReferencedObject(), file, true);
for (CsmReference csmReference : out) {
bag.addHighlight(csmReference.getStartOffset(), csmReference.getEndOffset(), defaultColors);
}
}
}
}
private CsmFile getCsmFile() {
if (weakFile == null || weakFile.get() == null) {
if (weakDoc == null || weakDoc.get() == null) {
return null;
}
DataObject dobj = NbEditorUtilities.getDataObject(weakDoc.get ());
CsmFile file = CsmUtilities.getCsmFile(dobj, false);
if (file != null) {
weakFile = new WeakReference<CsmFile>(file);
} else {
return null;
}
}
return weakFile.get();
}
#p#分页标题#e#
在 caretUpdate() 要领中,我们利用 CsmReferenceResolver 来查找光标下对语 言实体的引用。假如存在有效的实体,我们就向 CsmReferenceRepository 询问文件中所 有沟通实体的呈现位置并存储它们的偏移量。getCsmFile() 要领是一段跟尾代码,用来 确保我们不保存任何语言模子数据。
按下 Ctrl-Shift-I 以修复导入(可能右键 单击,然后选择“修复导入”)。
生成并运行项目。
假如把鼠 标放到 main() 的 argc 参数上,您就将看到如下的高亮显示:
单击 文件的差异位置以查察标志实例是奈何事情的。您也许想实验更巨大的项目中以查察它怎 样与类、宏等等协同事情。
提高机能
对静态文原来说,我们当前的代码足够好 了,但将在编辑文件的进程中发生严重的延迟。呈现延迟的原因是我们每按下一个键,就 当即开始搜索。要办理这个问题,我们将推迟任务以阐明代码,假如鼠标位置在任务开始 前改变了,我们就打消并从头打算任务。
在 MarkOccurrencesHighlighter.java 类中,把先前的 caretUpdate() 实现变动为以下代码:
public void caretUpdate(CaretEvent e) {
bag.clear();
lastCaret = e.getDot();
scheduleUpdate();
}
private int lastCaret;
private RequestProcessor.Task task = null;
private final static int DELAY = 1000;
public void scheduleUpdate() {
if (task==null) {
task = RequestProcessor.getDefault().create(new Runnable() {
public void run() {
CsmFile file = getCsmFile();
if (file != null) {
CsmReference ref = CsmReferenceResolver.getDefault().findReference (file, lastCaret);
if (ref!=null && ref.getReferencedObject()!=null) {
Collection<CsmReference> out = CsmReferenceRepository.getDefault ().getReferences(ref.getReferencedObject(), file, true);
for (CsmReference csmReference : out) {
bag.addHighlight(csmReference.getStartOffset(), csmReference.getEndOffset (), defaultColors);
}
}
}
}
}, true);
task.setPriority(Thread.MIN_PRIORITY);
}
task.cancel();
task.schedule(DELAY);
}
在这个代码块中,我们利用 org.openide.util.RequestProcessor 来处理惩罚代码阐明任务。假如获得几个光标更新,我 们就打消先前的任务,记着鼠标位置,然后在稍后的时间从头打算任务。
修复导 入,然后生成并运行项目。
此刻您将留意到,在键入大块代码时没有延迟了。