Я сам не пробовал, но я верю, что то, что вы хотите, выполнимо (по модулю проблема позиции щелчка и позиции каретки, описанная в комментариях). Вы на правильном пути, используя элемент <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 потребуется несколько секунд, всплывающее окно будет отображаться в течение нескольких секунд. Будьте бдительны.