开发 Eclipse 插件的最佳实践

使用标记、注释和修饰符

本教程着重介绍使用标记将信息标记为资源的最佳实践,接着介绍用于在工作台内突出标记的注释和修饰符。通过扩展扩展点,您可以重用和改编 Eclipse 插件的内置函数,并且执行高级资源标记,比如在编辑文本时移动一个文本标记。我们将讨论利用插件模型的方法,创建一个有效、高性能且具有综合外观的插件。

Andy Flatt, 软件开发人员, IBM

Mickael Maison, 软件开发人员, IBM

2011 年 11 月 14 日

  • +内容

简介

在为 IDE Eclipse 环境开发插件时,您要考虑到几个设计要素,这些要素确保您:

  • 不用锁定用户界面线程。
  • 在不影响性能的情况下修饰用户界面。
  • 在后台处理数据。

本教程将讨论如何使用这些设计要素来处理和显示那些与存储在工作区中的资源相关的数据。我们将检查 Eclipse 如何提供一个标记界面来存储和处理与资源相关的信息。

我们将提供处理资源数据标记的最佳实践。首先,我们展示如何标记数据,然后构建知识来在用户界面上表示标记,最后在资源变更时更新标记。在本文中,资源为 Eclipse 对象,可实现 IResource 界面,比如项目、文件、文件夹以及 Java ™ 对象(其中包括包、类以及源)。

本教程是针对那些可以编写基本插件并且又想学习处理 Eclipse 资源的最佳实践的开发人员。

Eclipse.org 记录了许多独特的扩展点和界面。本文将帮助您选择结合使用这些扩展点和界面的最佳实践。 进一步学习如何利用现有的 Eclipse 函数来提供新的功能。

第 1 部分:创建您自己的标记

标记是什么?

标记用于在不更改资源的情况下将信息链接到资源上。被标记信息的常见示例有断点、书签和编译错误。以编译错误为例,每一次执行编译作业,作业会通过创建一个新的标记来浏览源并突出错误。

扩展标记

在本教程的第一部分,我们将创建我们自己的标记。只要通过标记扩展点,并且只要编写一行代码即可完成此项工作。

您可以通过扩展 IMarker 扩展点 org.eclipse.core.resources.markers 来创建您自己的标记。首先,在 plugin.xml 文件中添加 清单 1 中的代码。也就是说,您将以 id 为 com.ibm.mymarkers.mymarker 创建一个名为 My Marker 的标记。它的超类型为 org.eclipse.core.resources.marker。这是最基本的标记类型。您可以扩展其他提供稍微更具体的功能的超类型。其他的超类型有:

  • org.eclipse.core.resources.problemmarker
  • org.eclipse.core.resources.textmarker

注意:您可以随需使用任意多的这些超类型。

清单 1. 清单 1 来自 plugin.xml 的标记扩展定义
<extension point="org.eclipse.core.resources.markers" id="com.ibm.mymarkers.mymarker"
  name="My Marker">
	<super type="org.eclipse.core.resources.marker"/>
	<persistent value="false"/><attribute name="description"/>
</extension>

注意清单 1 中的两个要素 persistent 和 attribute。这些都是分配给 mymarker 标记的属性。 Persistent 指明标记是否应该存储在工作区中。还有另外一个分配给 mymarker 的新属性 description

使用新标记

您可以通过调用所需资源上的 createMarker 方法来创建一个标记。同时,您也可以为其设置属性。

清单 2 中所示的方法也可以用来创建标记。只需输入 IResource,将其链接到标记。创建后,您就可以设置其属性。

清单 2. 清单 2 创建新标记类型的 Java 代码
public static IMarker createMarker(IResource res)
throws CoreException {
       IMarker marker = null;
       //note: you use the id that is defined in your plugin.xml
       marker = res.createMarker("com.ibm.mymarkers.mymarker");
       marker.setAttribute("description," "this is one of my markers");
       //note: you can also use attributes from your supertype
       marker.setAttribute(IMarker.MESSAGE, "My Marker");
       return marker;
}

查找您的标记

要查找与 IResource 相关的标记,您可以查询资源来获取所有具有指定 id 的标记,并指定是否搜索相关资源。要搜索标记,调用资源上的findMarkers 方法。指定诸如标记类型和搜索深度的参数。

清单 3 中的代码使用 IResource.DEPTH_ZERO 参数查找直接与该资源链接的标记。

清单 3. 查找新标记类型的 Java 代码
public static final String MARKER = "com.ibm.mymarkers.mymarker";

public static List<IMarker> findMarkers(IResource resource) {
        try {
               return Arrays.asList(resource.findMarkers(MARKER, true, 
	IResource.DEPTH_ZERO));
        } catch (CoreException e) {
               return new ArrayList<IMarker>();
        }
    }

将资源深度更改为 IResource.DEPTH_INFINITE 会返回与其相关的标记或任何子资源。例如,您可以传入包,并获取与包中资源相链接的所有标记。

第 2 部分:使用注释来显示和更新标记

注释是什么?

注释用于标记编辑器内的一个文本区域。它们广泛用于在 Eclipse 中显示信息,比如错误、警告、构建问题、任务或断点。注释在编辑器标尺上和文本上都可看到。图 1 列出显示语法错误的注释。

图 1. 图 1 注释的示例
屏幕截图显示编辑窗口中一些 Java 代码左边的注释栏有一个绿色三角形,一个里面带有白色 X 符号的红色圆圈

常见的注释实现是,在解析文件并且挑选出诸如错误和 “todo” 标签时生成标记。这通常在构建时完成。将其他的链接到持久标记,如断点。该示例所使用的是持久标记。

用户查看注释的方法可以使用菜单 General > Editors > Text Editors > Annotations 下的首选项面板进行定制。也就是说用户自定义注释不需要执行额外的工作。

图 2. 图 2 注释首选项面板的屏幕截图
屏幕截图显示了注释首选项列表,其中包含符号及其含义

查看 大图

标记扩展点的属性

在本教程的第 1 部分中,标记只扩展了默认的标记类型。在第 2 部分,我们将扩展文本标记类型,以标记文本位置。此类型定义了两个关键属性: charStart 和 charEnd。我们也希望标记在会话间能持久,所以我们将 persistent 值改为 true。为此,我们需要更新 清单 4 中所定义的标记。

清单 4. 清单 4 来自 plugin.xml 的标记扩展定义
<extension point="org.eclipse.core.resources.markers" id="com.ibm.mymarkers.mymarker"
  name="My Marker">
	<super type="org.eclipse.core.resources.textmarker"/>
	<super type="org.eclipse.core.resources.marker"/>
	<persistent value="true"/>
</extension>

定义您的注释规范扩展

要创建您自己的注释,使用扩展点 org.eclipse.ui.editors.markerAnnotationSpecification(参见 清单 5)。它定义了注释的属性以及其默认显示选项。

清单 5. 清单 5 来自 plugin.xml 的注释扩展定义
<extension point="org.eclipse.ui.editors.markerAnnotationSpecification"
		id="myannotationspecification" name="MyAnnotation">
	<specification annotationType="com.ibm.example.myannotation"
			label="MyAnnotation"
			icon="icons/sample.gif"
			overviewRulerPreferenceKey="clruler"
			overviewRulerPreferenceValue="true"
			colorPreferenceKey="clcolor"
			colorPreferenceValue="255,255,0"
			textPreferenceKey="cltext"
			textPreferenceValue="true"
			verticalRulerPreferenceKey="clvertical"
			verticalRulerPreferenceValue="true"
			textStylePreferenceKey="clstyle"
			textStylePreferenceValue="BOX">
	</specification>
</extension>

XML 中我们将用来链接到规范的部分是 id 和 annotationType 属性。Eclipse.org 记录了用于自定义的其他属性(参见 参考资料)。

下一步是使用扩展点 org.eclipse.ui.editors.annotationTypes 把现有的标记链接到新的注释规范中。我们使用来自规范的注释类型和来自标记定义的 id 来链接规范。

清单 6. 清单 6 来自 plugin.xml 的注释类型定义

点击查看代码清单

请参阅 参考资料,在 Eclipse.org 上查找更多关于此扩展点的信息。

创建并添加一个注释到编辑器

清单 7 中的代码用于创建并添加注释到编辑器。

清单 7. 清单 7 向编辑器添加一个新的注释
public static void addAnnotation(IMarker marker, ITextSelection selection, 
							ITextEditor editor) {
      //The DocumentProvider enables to get the document currently loaded in the editor
      IDocumentProvider idp = editor.getDocumentProvider();

      //This is the document we want to connect to. This is taken from 
      //the current editor input.
      IDocument document = idp.getDocument(editor.getEditorInput());

      //The IannotationModel enables to add/remove/change annotation to a Document 
      //loaded in an Editor
      IAnnotationModel iamf = idp.getAnnotationModel(editor.getEditorInput());

      //Note: The annotation type id specify that you want to create one of your 
      //annotations
      SimpleMarkerAnnotation ma = new SimpleMarkerAnnotation(
				“com.ibm.example.myannotation”,marker);

      //Finally add the new annotation to the model
      iamf.connect(document);
      iamf.addAnnotation(ma,newPosition(selection.getOffset(),selection.getLength()));
      iamf.disconnect(document);
}

保持标记和注释同步

注释模式负责在文档被编辑时移动注释。然而,在注释移动时,它并不更新标记的属性。在这种情况下,我们要更新标记的 charStart 和charEnd 属性。最后的扩展点为标记更新器(updater)。它定义了一个类,用于在移动注释时更新标记。

清单 8. 清单 8 来自 plugin.xml 的标记更新器定义
<extension point="org.eclipse.ui.editors.markerUpdaters"> 
               <updater
                       id="com.ibm.example.MarkerUpdater"
                       class="com.ibm.example.mymarker.MarkerUpdater"
                       markerType="com.ibm.mymarkers.mymarker">
               </updater>
</extension>:

我们使用 IMarkerUpdater 界面来提供我们在移动注释时想要执行的代码。清单 9 中显示的类是我们的标记更新器。我们感兴趣的代码在updateMarker 方法中。 此处,我们用它来更新标记的 charStart 和 charEnd 属性。

清单 9. 清单 9 标记更新器代码
public class MarkerUpdater implements IMarkerUpdater {
       /*
       *Returns the attributes for which this updater is responsible.
       *If the result is null, the updater assumes responsibility for any attributes.
       */
       @Override
       public String[] getAttribute() {
            return null;
       }

       @Override
       public String getMarkerType() {
             //returns the marker type that we are interested in updating
            return "com.ibm.mymarkers.mymarker";
       }

       @Override
       public boolean updateMarker(IMarker marker, IDocument doc, Position position) {
             try {
                 int start = position.getOffset();
                   int end = position.getOffset() + position.getLength();
                   marker.setAttribute(IMarker.CHAR_START, start);
                   marker.setAttribute(IMarker.CHAR_END, end);
                   return true;
             } catch (CoreException e) {
                   return false;
             }
       }
}

修饰符是什么?

在 Eclipse 中,修饰符用于为工作区中的对象添加视觉信息。他们通常显示对象类型以及目前与该对象相关的任何重要属性。图 3 显示了如何在包资源管理器中将修饰符显示给用户。该修饰符显示了哪些项为 Java 源文件,或哪些项为包,并且显示了包含警告或错误的源和包的标记图标。这里,修饰符也用来添加细节,比如文件是否与存储库同步。

图 3. 图 3 用符号图标修饰的包和源
屏幕截图显示一些小符号,比如黄色圆圈和蓝色箭头,被添加到了文件图标

定义您自己的修饰符

添加我们的修饰符的第一步是扩展 org.eclipse.ui.decorators 扩展点。它启用新修饰符的定义,并且选择它将要修饰哪种对象。

此处重要的字段是:

  • class,它必须是实现 ILightweightLabelDecorator 的类的完全限定名(将 lightweight 设置为 true)。
  • enablement,它包含修饰符所应用的 Eclipse 对象列表。
清单 10. 清单 10 来自 plugin.xml 的修饰符定义
<extension point="org.eclipse.ui.decorators">  
	<decorator   id="com.ibm.example.filedecorator"   
			label="MyMarker Decorator"   
			state="true"   
			class= "com.ibm.example.mymarker.FileDecorator"   
			adaptable="true"   
			lightweight="true">   
		<enablement>
			<objectClass name="org.eclipse.core.resources.IResource"/>   
		</enablement>  
	</decorator>
</extension>

请参阅 参考资料,在 Eclipse.org 上查找更多关于扩展点的文件。

注意:轻量级与非轻量级:根据 API, 非轻量级修饰符可能会在新版本的 Eclipe 中被弃用。

我们的文件修饰符类

我们需要实现 FileDecorator 类来决定修饰符的行为。这一类必须实现 ILightweightLabelDecorator。用它来扩展 LabelProvider的想法非常好,因为它可以让我们只重写我们感兴趣的方法,即 decorate()

decorate() 的基本实现如 清单 11 所示。

清单 11. 清单 11 decorate() 的简单实现
public void decorate(Object resource, IDecoration decoration)  {
	decoration.addOverlay(ImageDescriptor.createFromFile(FileDecorator.class, 
					"/icons/sample.gif"), IDecoration.TOP_RIGHT);
	decoration.addPrefix("My Prefix ");
	decoration.addSuffix(" My Suffix");
}

IDecoration 对象也可用于自定义字体、文本或背景颜色。

图 4. 图 4 清单 11 中用来修饰 IResources 的代码屏幕截图
屏幕截图显示了已执行代码的结果,将修饰符放置于文件图标上。

decorate() 的第一个参数可以用来筛选我们要修饰的资源。如果我们只想要修饰包含指定标记的资源,就使用如 清单 12 所示的代码。

清单 12. 清单 12 使用指定标记修饰资源
public void decorate(Object resource, IDecoration decoration) {
	if(resource instanceof IResource){
		List<IMarker> markers = MyMarkerFactory.findMarkers((IResource) resource);
		if (markers.size() > 0) {
			decoration.addSuffix("  Marker !!");
		}
	}
}

您已经遵循了本教程的步骤,接下来该做什么?

进一步的改进包括:

  • 为标记添加可编辑的属性。允许用户更改标记的状态。
  • 自动创建和删除标记。 使用后台处理作业来自动创建、更新和删除标记。
  • 自定义标记的 hover。使用高级标记 hover 来支持 HTML 或多媒体内容。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章