Eclipse plugin to handle the same file extension using different editors

I am writing a plugin for Eclipse that provides syntax highlighting for a specific preprocessor directive that is used in our software stack. Before compiling the actual code, they are replaced by an external program (imagine a tag like <% FOO %> , which is replaced by something else, say a version string).

Thus, the plugin provides annotations for each tag so that they can be quickly identified. Instead of creating your own editor, annotations are provided to existing editors such as JavaEditor or PHP-Editor.

Now the problem is that files that are processed by an external program have the same file extension, for example .inc . They may contain Java code or PHP code (other languages ​​are possible in the future).

I have successfully added a content type to my plugin, and I can distinguish between different files based on some criteria. So, when I have a java .inc file and assign the content type to inc file (java) .

However, the user should be able to overwrite this automatic detection (also, automatic detection can sometimes be detected). So I want to open one file ( foo.inc ) with different editors (Java editor, PHP editor, ...) and save this association.

The approaches I'm thinking about right now are:

  • Overwrite the file open action to check the setting in my project and open the corresponding editor. I did not find a solution that describes how to overwrite the actions of the open all file (File β†’ Open file in the main menu, Open in the Project Navigator, ...)
  • Implementing your own editor, which then opens the corresponding editor. This is similar to a hacker approach, which may also cause some delay.
  • In the "open with" context menu in the file, the user can change the editor. A change programmatically would be fine, but I cannot find the API or file in which this selection is saved.
  • Implement different Natures for the project, and then map the file types differently in the context of each nature. Will only provide association specific to the project, and not for each file.

Are there any better solutions? Do you know more about any of the approaches I have listed?

+4
source share
2 answers

I learned how to overwrite the action of opening a file: by registering an actionProvider that overrides org.eclipse.ui.navigator.resources.OpenActions . I provide all the code because it is quite difficult to combine all these different things and make it work.

Let's start by writing plugin.xml:

 <!-- overwrite OpenActions --> <extension point="org.eclipse.ui.navigator.navigatorContent"> <actionProvider class="myplugin.navigator.OpenActionProvider" id="myplugin.navigator.actions.open" overrides="org.eclipse.ui.navigator.resources.OpenActions" priority="highest"> <enablement> <and> <instanceof value="org.eclipse.core.resources.IFile"> </instanceof> <test property="org.eclipse.core.resources.extension" value="frm"> </test> </and> </enablement> </actionProvider> </extension> <extension point="org.eclipse.ui.navigator.viewer"> <viewerActionBinding viewerId="org.eclipse.ui.navigator.ProjectExplorer"> <includes> <actionExtension pattern="myplugin.navigator.actions.open"> </actionExtension> </includes> </viewerActionBinding> </extension> 

OpenActionProvider is as follows:

 package myplugin.navigator; import org.eclipse.jface.action.IMenuManager; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IViewPart; import org.eclipse.ui.actions.ActionContext; import org.eclipse.ui.navigator.CommonActionProvider; import org.eclipse.ui.navigator.ICommonActionConstants; import org.eclipse.ui.navigator.ICommonActionExtensionSite; import org.eclipse.ui.navigator.ICommonViewerWorkbenchSite; public class OpenActionProvider extends CommonActionProvider { private OpenEditorActionGroup fOpenGroup; @Override public void init(ICommonActionExtensionSite site) { ICommonViewerWorkbenchSite workbenchSite = null; if (site.getViewSite() instanceof ICommonViewerWorkbenchSite) { workbenchSite = (ICommonViewerWorkbenchSite) site.getViewSite(); } if (workbenchSite != null) { if (workbenchSite.getPart() != null && workbenchSite.getPart() instanceof IViewPart) { IViewPart viewPart = (IViewPart) workbenchSite.getPart(); fOpenGroup = new OpenEditorActionGroup(viewPart); } } } @Override public void dispose() { if (fOpenGroup != null) { fOpenGroup.dispose(); fOpenGroup = null; } super.dispose(); } @Override public void fillActionBars(IActionBars actionBars) { if (fOpenGroup == null) return; fOpenGroup.updateActionBars(); actionBars.setGlobalActionHandler(ICommonActionConstants.OPEN, fOpenGroup.getOpenAction()); } @Override public void fillContextMenu(IMenuManager menu) { if (fOpenGroup == null) return; fOpenGroup.fillContextMenu(menu); } @Override public void setContext(ActionContext context) { super.setContext(context); if (fOpenGroup == null) return; fOpenGroup.setContext(context); } } 

OpenEditorActionGroup is as follows:

 package myplugin.navigator; import java.util.ArrayList; import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.core.runtime.IAdaptable; import org.eclipse.jface.action.IAction; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.action.MenuManager; import org.eclipse.jface.viewers.ISelection; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.StructuredSelection; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IViewPart; import org.eclipse.ui.actions.OpenFileAction; import org.eclipse.ui.actions.OpenWithMenu; import org.eclipse.ui.navigator.ICommonMenuConstants; public class OpenEditorActionGroup extends AbstractActionGroup { private OpenFileAction fOpenFileAction; public OpenEditorActionGroup(IViewPart viewPart) { super(viewPart); } @Override protected void makeActions() { fOpenFileAction= new OpenGenElementAction(getViewPart().getSite().getPage()); } public static IStructuredSelection convertSelectionToResources(ISelection s) { List<Object> converted = new ArrayList<Object>(); if (s instanceof StructuredSelection) { Object[] elements = ((StructuredSelection) s).toArray(); for (int i = 0; i < elements.length; i++) { Object e = elements[i]; if (e instanceof IResource) { converted.add(e); } else if (e instanceof IAdaptable) { IResource r = (IResource) ((IAdaptable) e).getAdapter(IResource.class); if (r != null) { converted.add(r); } } } } return new StructuredSelection(converted.toArray()); } @Override public void fillContextMenu(IMenuManager menu) { System.out.println("fillcontextmenu"); if (getContext() == null) return; IStructuredSelection celements = (IStructuredSelection)getContext().getSelection(); IStructuredSelection selection = convertSelectionToResources(celements); fOpenFileAction.selectionChanged(celements); if (!fOpenFileAction.isEnabled()) return; menu.appendToGroup(ICommonMenuConstants.GROUP_OPEN, fOpenFileAction); fillOpenWithMenu(menu, selection); } 

The AbstractActionGroup is just a wrapper if you want to implement more of them:

 package myplugin.navigator; import org.eclipse.core.runtime.Assert; import org.eclipse.jface.action.IMenuManager; import org.eclipse.jface.resource.ImageDescriptor; import org.eclipse.ui.IActionBars; import org.eclipse.ui.IViewPart; import org.eclipse.ui.actions.ActionGroup; public abstract class AbstractActionGroup extends ActionGroup { private final IViewPart fViewPart; public AbstractActionGroup(IViewPart viewPart) { Assert.isNotNull(viewPart); fViewPart = viewPart; makeActions(); } protected IViewPart getViewPart() { return fViewPart; } protected ImageDescriptor getImageDescriptor(String relativePath) { return ImageDescriptor.createFromURL(null); } protected abstract void makeActions(); @Override public abstract void fillContextMenu(IMenuManager menu); @Override public abstract void fillActionBars(IActionBars actionBars); @Override public abstract void updateActionBars(); } 

And finally, OpenGenElementAction itself:

 package myplugin.navigator; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IResource; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.ui.IEditorDescriptor; import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.actions.OpenFileAction; import org.eclipse.ui.editors.text.EditorsUI; import org.eclipse.ui.part.FileEditorInput; public class OpenGenElementAction extends OpenFileAction { private IFile selectedFile = null; private final IWorkbenchPage workbenchPage; public OpenGenElementAction(IWorkbenchPage page) { super(page); workbenchPage = page; } @Override public boolean isEnabled() { return true; } @Override public void run() { System.out.println("RUN"); } @Override protected boolean updateSelection(IStructuredSelection selection) { if (selection.size() != 1) return super.updateSelection(selection); Object element = selection.getFirstElement(); if (element instanceof IFile) { selectedFile = (IFile)element; } return selectedFile != null || super.updateSelection(selection); } } 
+3
source

You can directly attack IEditorRegistry programmatically by registering specific file names, not just extensions.

See: "IEditorRegistry Help"

http://help.eclipse.org/luna/index.jsp?topic=%2Forg.eclipse.platform.doc.isv%2Freference%2Fapi%2Forg%2Feclipse%2Fui%2FIEditorRegistry.html

Method:

 void setDefaultEditor(String fileNameOrExtension, String editorId) Sets the default editor id for the files that match that specified file name or extension. 

accepts full names and / or wildcards. Most openEditor calls (menus, toolbars, etc.) end with calls to this registry to get the appropriate editor. Set up the hook when you open the editor that registers this name.

This is not perfect if you have two files with the same name and a different language, but they are quick and easy to implement compared to your approaches.

0
source

All Articles