1

目前我正在为 Eclipse CDT 开发一个插件。我已经在我的 plugin.xml 文件中成功地做了一个动作声明。

<extension
     point="org.eclipse.ui.popupMenus">
  <objectContribution
        id="MyOwnPlugin.contribution1"
        nameFilter="*.c"
        objectClass="org.eclipse.ui.IEditorInput">
     <action
           class="myownplugin.popup.actions.DoTestsAction"
           enablesFor="1"
           id="myownplugin.doTests"
           label="Do Tests"
           menubarPath="additions">
     </action>
  </objectContribution>
</extension>

当我右键单击编辑器并且我可以选择该操作时,这成功地声明了一个弹出操作。

但是,我想要实现的是,只有当我右键单击函数名称/函数声明时才会出现该操作。有没有办法实现这一目标?我一直在 plugin.xml 中尝试过滤XML 标记,但没有成功。

谢谢。

4

1 回答 1

1

我自己没有尝试过,但我相信你想要的是可行的(以评论中描述的点击位置与插入符号位置问题为模)。您在使用该<filter>元素方面走在了正确的轨道上,但还需要其他一些部件才能使其正常工作。


首先要意识到上下文菜单与对象有关,在编辑器上下文菜单的情况下,该对象IEditorInput代表编辑器选项卡的内容。

任何使上下文菜单动作的存在依赖于某些条件的机制,都只会将该对象用作输入。因此,条件必须基于对象的状态(仅)。这就是为什么我们可以基于插入符号位置而不是单击本身的位置:“编辑器中的当前插入符号位置”是状态的一部分IEditorInput,但“编辑器中当前单击的位置”是从来没听说过)。


该元素的文档说:<filter>

此元素用于评估当前选择中每个对象的属性状态。A match only if each object in the selection has the specified attribute state. 选择中的每个对象都必须实现或适应,org.eclipse.ui.IActionFilter

这里谈论“选择”的原因是,在某些视图中,可以在选择多个对象的情况下调用上下文菜单(例如,在项目资源管理器视图中,选择多个文件/文件夹)。在不适用的编辑器上下文中;“选择”中只有一个对象,类型为IEditorInput

不幸的是,IEditorInput没有实现IActionFilter. 但是,它确实实现IAdaptable了 ,因此我们可以使用适配器机制让我们的插件支持将其适配到IActionFilter.

这将涉及将这样的内容添加到您的plugin.xml

  <extension point="org.eclipse.core.runtime.adapters">
     <factory 
        class="your.plugin.EditorInputAdapterFactory" 
        adaptableType="org.eclipse.ui.IEditorInput">
        <adapter type="org.eclipse.ui.IActionFilter"/>
     </factory>
  </extension>

whereyour.plugin.EditorInputAdapterFactory是您将在插件中编写的类型。它的实现看起来像这样:

public class EditorInputAdapterFactory implements IAdapterFactory {
    @Override
    public <T> T getAdapter(Object adaptable, Class<T> adapterType) {
        if (adaptable instanceof IEditorInput && adapterType.equals(IActionFilter.class)) {
            return new EditorInputActionFilter((IEditorInput) adaptable);
        }
        return null;
    }
}

又是EditorInputActionFilter一个我们要写的类型。


好的,现在我们有一个与IEditorInput对象一起使用的动作过滤器,使我们能够使用<filter>元素。

<filter>元素使用“属性名称”和“属性值”,它们将被传递给IActionFilter. 作为动作过滤器的作者,我们可以发明这些。例如,我们可以发明一个名为的属性名称selectedElementType(其中“选定元素”是指插入符号当前所在的 C++ 元素的类型)和一个名为function.

然后我们的过滤器声明将如下所示:

<filter name="selectedElementType" value="function" />

最后,我们需要实现我们的动作过滤器,以便它评估我们为IEditorInput对象定义的属性。我不会在这里写出完整的实现,但概括地说:

  • 用于CDTUITools.getWorkingCopyManager()将 映射IEditorInputIWorkingCopy实现ITranslationUnit.
  • 获取编辑器当前插入符号的位置,使用类似的东西CUIPlugin.getActivePage().findEditor(editorInput).getEditorSite().getSelectionProvider().getSelection()(中间有适当的空检查)。可能有一种更简单的方法可以做到这一点,但这就是我想到的。由于您在编辑器中,因此返回的选择应该具有 type ITextSelection
  • 用于SharedASTJob访问编辑器的共享 AST ( IASTTranslationUnit)。请注意,您需要阻止作业,并且(我假设)将在 UI 线程上调用操作过滤器,这并不理想。(更多内容如下。)
  • 使用IASTTranslationUnit.getNodeSelector(null).findEnclosingName(offset, length), 与 , 的偏移量和长度ITextSelection一起获得IASTName插入符号下的代表名称(如果有)。
  • 用于IASTName.resolveBinding()获取名称所指的绑定(C++ 语义模型对象)。
  • 检查绑定是否实现IFunction

所有这些都将用于您的IActionFilter.testAttribute(). 该target函数的参数将是IEditorInput. 为了更好地衡量,您应该在执行任何操作之前检查nameandvalue参数是否与您发明的属性名称 ( selectedElementTypeand function) 相对应(最初,您的操作过滤器只会由您的<filter>元素调用,因此它们将始终匹配,但您可以想象一下将来扩展这种机制以支持其他选定的元素类型。)


最后,关于性能的说明:您在这里所做的是将 UI 元素的响应能力(弹出窗口的外观)调整为 C++ 代码的属性,这可能会很慢地解析和分析。这必然意味着您的弹出窗口可能需要更长的时间才能显示出来(这反映在您需要阻止的操作过滤器中SharedASTJob)。通过使用SharedASTJob,您可以通过重新使用已经解析的 AST(如果有的话)来最小化这种影响,但是例如,如果您刚刚打开一个编辑器并右键单击,并且初始 AST 需要几秒钟来构建,您的弹出窗口将需要几秒钟才能显示。买者自负。

于 2018-07-04T00:23:23.097 回答