Eclipse CDT plugin - действие ограничено именем функции - PullRequest
0 голосов
/ 03 июля 2018

В настоящее время я разрабатываю плагин для 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>

Это успешно объявляет всплывающее действие, когда я щелкаю правой кнопкой мыши на редакторе, и я могу выбрать действие.

Тем не менее, я хотел бы добиться того, чтобы действие появлялось только тогда, когда я щелкаю правой кнопкой мыши на названии функции / объявлении функции. Есть ли способ, как этого добиться? Я пробовал тег XML filter в файле plugin.xml, но безуспешно.

Спасибо.

1 Ответ

0 голосов
/ 04 июля 2018

Я сам не пробовал, но я верю, что то, что вы хотите, выполнимо (по модулю проблема позиции щелчка и позиции каретки, описанная в комментариях). Вы на правильном пути, используя элемент <filter>, но для его работы требуются и другие элементы.


Первое, что нужно понять, это то, что контекстное меню относится к объекту , а в случае контекстного меню редактора этот объект - IEditorInput, представляющий содержимое вкладки редактора.

Любой механизм, который делает присутствие действия контекстного меню зависимым от некоторого условия, будет иметь только этот объект доступным в качестве ввода. Отсюда следует, что условие должно основываться на состоянии объекта (только). Вот почему мы можем основывать его на позиции каретки, а не на месте самого клика: «текущая позиция каретки в редакторе» является частью состояния IEditorInput, но «местоположение текущего клика в пределах редактор "не (что я знаю).


Документация элемента <filter> гласит:

Этот элемент используется для оценки состояния атрибута каждого объекта. в текущем выборе. Соответствует только если каждый объект в выборе имеет указанное состояние атрибута. Каждый объект в выборе должен внедрить или приспособиться к org.eclipse.ui.IActionFilter.

Причина, по которой это говорит о «выборе», заключается в том, что в некоторых представлениях контекстное меню может быть вызвано с несколькими выбранными объектами (например, в представлении Project Explorer с выбранными несколькими файлами / папками). В контексте редактора, который не применяется; в «выделении» будет только один объект типа 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>

где your.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() для сопоставления IEditorInput с IWorkingCopy, который реализует ITranslationUnit.
  • Получить текущую позицию курсора редактора, используя что-то вроде CUIPlugin.getActivePage().findEditor(editorInput).getEditorSite().getSelectionProvider().getSelection() (с соответствующими нулевыми проверками между ними). Там может быть более простой способ сделать это, но это то, что приходит на ум. Поскольку вы находитесь в редакторе, возвращаемое выделение должно иметь тип ITextSelection.
  • Используйте SharedASTJob, чтобы получить доступ к общедоступному редактору AST (IASTTranslationUnit). Обратите внимание, что вам нужно заблокировать работу, и фильтр действий (я полагаю) будет вызван в потоке пользовательского интерфейса, что не идеально. (Подробнее об этом ниже.)
  • Используйте IASTTranslationUnit.getNodeSelector(null).findEnclosingName(offset, length) со смещением и длиной от ITextSelection, чтобы получить IASTName, представляющее имя под кареткой (если есть).
  • Используйте IASTName.resolveBinding(), чтобы получить привязку (объект семантической модели C ++), к которой относится имя.
  • Проверьте, реализует ли привязка IFunction.

Все это пойдет в вашу реализацию IActionFilter.testAttribute(). Параметр target для этой функции будет IEditorInput. Прежде всего, вам следует убедиться, что параметры name и value соответствуют изобретенным вами именам атрибутов (selectedElementType и function), прежде чем делать что-либо из этого (изначально ваш фильтр действий будет вызываться только вашим Элемент <filter>, поэтому они всегда будут совпадать, но вы можете представить себе расширение этого механизма в будущем, например, для поддержки других выбранных типов элементов.)


Наконец, замечание о производительности: то, что вы здесь делаете, обусловливает отзывчивость элемента пользовательского интерфейса (появление всплывающего окна) на свойство кода C ++, которое может быть медленным для анализа и анализа. Это обязательно означает, что ваше всплывающее окно может появиться дольше в результате (что отражается в вашем фильтре действий, который необходимо заблокировать на SharedASTJob). Используя SharedASTJob, вы минимизируете этот эффект, повторно используя уже проанализированный AST, если он есть, но, например, если вы только что открыли редактор и щелкнули правой кнопкой мыши, а для создания первоначального AST потребуется несколько секунд, всплывающее окно будет отображаться в течение нескольких секунд. Будьте бдительны.

...