| author | mclay | 2008-12-10 17:26:29 (EST) |
|---|---|---|
| committer | sefftinge | 2008-12-10 17:26:29 (EST) |
| commit | 20de41ac1e8f0a7a991fbebd1868f664eb606a1e (patch) (side-by-side diff) | |
| tree | 38ed35f464973882071e5fec26e93b5b646d42a3 | |
| parent | 2bed6d8b200271e61344b22c0b176b7e24b8d143 (diff) | |
| download | org.eclipse.xtext-20de41ac1e8f0a7a991fbebd1868f664eb606a1e.zip org.eclipse.xtext-20de41ac1e8f0a7a991fbebd1868f664eb606a1e.tar.gz org.eclipse.xtext-20de41ac1e8f0a7a991fbebd1868f664eb606a1e.tar.bz2 | |
ASSIGNED - bug 256402: [UI] Goto declaration
https://bugs.eclipse.org/bugs/show_bug.cgi?id=256402
4 files changed, 224 insertions, 102 deletions
diff --git a/plugins/org.eclipse.xtext.ui.core/plugin.xml b/plugins/org.eclipse.xtext.ui.core/plugin.xml index 829b444..d194ace 100644 --- a/plugins/org.eclipse.xtext.ui.core/plugin.xml +++ b/plugins/org.eclipse.xtext.ui.core/plugin.xml @@ -12,6 +12,14 @@ label="Syntax"> </keyword> </extension> + <extension + point="org.eclipse.ui.commands"> + <command + id="org.eclipse.xtext.ui.core.editor.handler.openDeclaration" + name="Open Declaration" + description="Opens the declaration for the currently selected CrossReference"> + </command> + </extension> <extension point="org.eclipse.ui.handlers"> <handler @@ -23,6 +31,15 @@ </reference> </activeWhen> </handler> + <handler + class="org.eclipse.xtext.ui.core.editor.handler.OpenDeclarationHandler" + commandId="org.eclipse.xtext.ui.core.editor.handler.openDeclaration"> + <activeWhen> + <reference + definitionId="isActiveEditorAnInstanceOfXtextEditor"> + </reference> + </activeWhen> + </handler> </extension> <extension point="org.eclipse.core.expressions.definitions"> @@ -38,10 +55,9 @@ </extension> <extension point="org.eclipse.ui.menus"> - <menuContribution + <menuContribution locationURI="popup:#TextEditorContext?after=additions"> - <command - commandId="org.eclipse.ui.edit.text.contentAssist.proposals" + <command commandId="org.eclipse.ui.edit.text.contentAssist.proposals" style="push"> <visibleWhen checkEnabled="false"> @@ -51,8 +67,23 @@ </visibleWhen> </command> </menuContribution> + <menuContribution locationURI="popup:#TextEditorContext?after=group.open"> + <command commandId="org.eclipse.xtext.ui.core.editor.handler.openDeclaration"> + <visibleWhen checkEnabled="false"> + <reference definitionId="isActiveEditorAnInstanceOfXtextEditor"/> + </visibleWhen> + </command> + </menuContribution> + </extension> + <extension + point="org.eclipse.ui.bindings"> + <key + contextId="org.eclipse.ui.textEditorScope" + schemeId="org.eclipse.ui.defaultAcceleratorConfiguration" + sequence="F3" + commandId="org.eclipse.xtext.ui.core.editor.handler.openDeclaration"> + </key> </extension> - <!--extension point="org.eclipse.ui.workbench.texteditor.hyperlinkDetectors"> <hyperlinkDetector diff --git a/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/OpenDeclarationAction.java b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/OpenDeclarationAction.java new file mode 100644 index 0000000..a105d28 --- a/dev/null +++ b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/OpenDeclarationAction.java @@ -0,0 +1,134 @@ +package org.eclipse.xtext.ui.core.editor; + +import java.util.List; + +import org.apache.log4j.Logger; +import org.eclipse.core.resources.IFile; +import org.eclipse.core.resources.ResourcesPlugin; +import org.eclipse.core.runtime.Assert; +import org.eclipse.core.runtime.Path; +import org.eclipse.emf.ecore.EObject; +import org.eclipse.emf.ecore.EReference; +import org.eclipse.jface.action.Action; +import org.eclipse.jface.text.IDocument; +import org.eclipse.swt.custom.StyledText; +import org.eclipse.swt.widgets.Control; +import org.eclipse.ui.IEditorPart; +import org.eclipse.ui.IWorkbenchPage; +import org.eclipse.ui.PartInitException; +import org.eclipse.ui.PlatformUI; +import org.eclipse.ui.ide.IDE; +import org.eclipse.ui.texteditor.ITextEditor; +import org.eclipse.xtext.CrossReference; +import org.eclipse.xtext.GrammarUtil; +import org.eclipse.xtext.crossref.ILinkingService; +import org.eclipse.xtext.parser.IParseResult; +import org.eclipse.xtext.parsetree.CompositeNode; +import org.eclipse.xtext.parsetree.LeafNode; +import org.eclipse.xtext.parsetree.NodeAdapter; +import org.eclipse.xtext.parsetree.NodeUtil; +import org.eclipse.xtext.parsetree.ParseTreeUtil; +import org.eclipse.xtext.resource.XtextResource; +import org.eclipse.xtext.service.ServiceRegistry; +import org.eclipse.xtext.ui.core.editor.model.IXtextDocument; +import org.eclipse.xtext.ui.core.editor.model.UnitOfWork; + +/** + * This action opens a <code>XtextEditor</code> on a selected <code>CrossReference</code> element. + * + * @author Michael Clay - Initial contribution and API + * + * @see org.eclipse.jface.action.Action + */ +public class OpenDeclarationAction extends Action { + + // logger available to subclasses + protected final Logger logger = Logger.getLogger(getClass()); + + private XtextEditor xtextEditor; + + private LeafNode currentNode; + + public OpenDeclarationAction(XtextEditor xtextEditor) { + this.xtextEditor = xtextEditor; + } + + public OpenDeclarationAction(LeafNode currentNode) { + this.currentNode = currentNode; + this.xtextEditor = (XtextEditor) PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage() + .getActiveEditor(); + } + + @Override + public void run() { + + if (currentNode == null) { + + StyledText styledText = (StyledText) this.xtextEditor.getAdapter(Control.class); + + int caretOffset = styledText.getCaretOffset(); + + IXtextDocument document = this.xtextEditor.getDocument(); + + CompositeNode rootNode = getRootNode(document); + + this.currentNode = (LeafNode) ParseTreeUtil.getCurrentOrFollowingNodeByOffset(rootNode, caretOffset); + } + + if (currentNode != null && currentNode.getGrammarElement() instanceof CrossReference) { + + ILinkingService linkingService = ServiceRegistry.getService(this.xtextEditor.getScope(), + ILinkingService.class); + + EObject semanticModel = NodeUtil.getNearestSemanticObject(currentNode); + + EReference eReference = GrammarUtil.getReference((CrossReference) currentNode.getGrammarElement(), + semanticModel.eClass()); + + List<EObject> linkedObjects = linkingService.getLinkedObjects(semanticModel, eReference, currentNode); + + if (!linkedObjects.isEmpty()) { + + EObject referenceEObject = linkedObjects.iterator().next(); + + IFile targetFile = ResourcesPlugin.getWorkspace().getRoot().getFile( + new Path(referenceEObject.eResource().getURI().toPlatformString(true))); + + if (targetFile != null) { + + IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); + + try { + IEditorPart openEditor = IDE.openEditor(page, targetFile); + + if (openEditor instanceof ITextEditor) { + + NodeAdapter nodeAdapter = NodeUtil.getNodeAdapter(referenceEObject); + ((ITextEditor) openEditor).selectAndReveal(nodeAdapter.getParserNode().getOffset(), + nodeAdapter.getParserNode().getLength()); + } + } + catch (PartInitException partInitException) { + logger.error("Error while opening editor part from workbench with file '" + targetFile + "'", + partInitException); + } + } + } + + } + + } + + private CompositeNode getRootNode(IDocument document) { + + CompositeNode rootNode = ((IXtextDocument) document).readOnly(new UnitOfWork<CompositeNode>() { + public CompositeNode exec(XtextResource resource) throws Exception { + IParseResult parseResult = resource.getParseResult(); + Assert.isNotNull(parseResult); + return parseResult.getRootNode(); + } + }); + + return rootNode; + } +} diff --git a/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/XtextHyperlinkDetector.java b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/XtextHyperlinkDetector.java index 6b199ed..4fd8837 100644 --- a/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/XtextHyperlinkDetector.java +++ b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/XtextHyperlinkDetector.java @@ -8,34 +8,17 @@ *******************************************************************************/ package org.eclipse.xtext.ui.core.editor; -import java.util.List; - import org.apache.log4j.Logger; -import org.eclipse.core.resources.IFile; -import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; -import org.eclipse.core.runtime.Path; -import org.eclipse.emf.ecore.EObject; -import org.eclipse.emf.ecore.EReference; -import org.eclipse.jface.text.IDocument; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.Region; import org.eclipse.jface.text.hyperlink.IHyperlink; import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; -import org.eclipse.ui.IEditorPart; -import org.eclipse.ui.IWorkbenchPage; -import org.eclipse.ui.PartInitException; -import org.eclipse.ui.PlatformUI; -import org.eclipse.ui.ide.IDE; -import org.eclipse.ui.texteditor.ITextEditor; import org.eclipse.xtext.CrossReference; -import org.eclipse.xtext.GrammarUtil; import org.eclipse.xtext.parser.IParseResult; import org.eclipse.xtext.parsetree.CompositeNode; import org.eclipse.xtext.parsetree.LeafNode; -import org.eclipse.xtext.parsetree.NodeAdapter; -import org.eclipse.xtext.parsetree.NodeUtil; import org.eclipse.xtext.parsetree.ParseTreeUtil; import org.eclipse.xtext.resource.XtextResource; import org.eclipse.xtext.ui.core.editor.model.IXtextDocument; @@ -57,99 +40,44 @@ public class XtextHyperlinkDetector implements IHyperlinkDetector { /* * (non-Javadoc) - * - * @see - * org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks( - * org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion, - * boolean) + * @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector#detectHyperlinks(org.eclipse.jface.text.ITextViewer, org.eclipse.jface.text.IRegion, boolean) */ public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, boolean canShowMultipleHyperlinks) { // TODO: should all of this be part of the read transaction? - CompositeNode rootNode = getRootNode(textViewer.getDocument()); - LeafNode currentNode = (LeafNode) ParseTreeUtil.getCurrentOrFollowingNodeByOffset(rootNode, region.getOffset()); - - if (currentNode.getGrammarElement() instanceof CrossReference) { - - EObject semanticModel = NodeUtil.getNearestSemanticObject(currentNode); - EReference eReference = GrammarUtil.getReference((CrossReference) currentNode.getGrammarElement(), - semanticModel.eClass()); - EObject linkMe = null; - if (eReference.isMany()) { - List<?> values = (List<?>) semanticModel.eGet(eReference); - if (!values.isEmpty() && values.get(0) instanceof EObject) - linkMe = (EObject) values.get(0); - } else { - Object value = semanticModel.eGet(eReference); - if (value instanceof EObject) - linkMe = (EObject) value; - } -// List<EObject> linkedObjects = this.linkingService.getLinkedObjects(semanticModel, eReference, currentNode); - - if (linkMe != null) { - return createXtextHyperlink(currentNode, linkMe); - } - - } - - return null; - } - - private IHyperlink[] createXtextHyperlink(final LeafNode currentNode, final EObject referenceEObject) { - - return new IHyperlink[] { new IHyperlink() { - - public IRegion getHyperlinkRegion() { - return new Region(currentNode.getTotalOffset(), currentNode.getTotalLength()); - } - - public String getHyperlinkText() { - return currentNode.getText(); - } - - public String getTypeLabel() { - return null; + CompositeNode rootNode = ((IXtextDocument) textViewer.getDocument()).readOnly(new UnitOfWork<CompositeNode>() { + public CompositeNode exec(XtextResource resource) throws Exception { + IParseResult parseResult = resource.getParseResult(); + Assert.isNotNull(parseResult); + return parseResult.getRootNode(); } + }); + + final LeafNode currentNode = + (LeafNode) ParseTreeUtil.getCurrentOrFollowingNodeByOffset(rootNode, region.getOffset()); - public void open() { - - IFile targetFile = ResourcesPlugin.getWorkspace().getRoot().getFile( - new Path(referenceEObject.eResource().getURI().toPlatformString(true))); - - if (targetFile != null) { - - IWorkbenchPage page = PlatformUI.getWorkbench().getActiveWorkbenchWindow().getActivePage(); - - try { - IEditorPart openEditor = IDE.openEditor(page, targetFile); + if (currentNode.getGrammarElement() instanceof CrossReference) { + return new IHyperlink[] { new IHyperlink() { - if (openEditor instanceof ITextEditor) { + public IRegion getHyperlinkRegion() { + return new Region(currentNode.getTotalOffset(), currentNode.getTotalLength()); + } - NodeAdapter nodeAdapter = NodeUtil.getNodeAdapter(referenceEObject); - ((ITextEditor) openEditor).selectAndReveal(nodeAdapter.getParserNode().getOffset(), - nodeAdapter.getParserNode().getLength()); - } - } - catch (PartInitException partInitException) { - logger.error("Error while opening editor part from workbench with file '" + targetFile + "'", - partInitException); - } + public String getHyperlinkText() { + return currentNode.getText(); } - } - } }; - } - private CompositeNode getRootNode(IDocument document) { + public String getTypeLabel() { + return null; + } - CompositeNode rootNode = ((IXtextDocument) document).readOnly(new UnitOfWork<CompositeNode>() { - public CompositeNode exec(XtextResource resource) throws Exception { - IParseResult parseResult = resource.getParseResult(); - Assert.isNotNull(parseResult); - return parseResult.getRootNode(); - } - }); + public void open() { + new OpenDeclarationAction(currentNode).run(); + } + } }; + } - return rootNode; + return null; } } diff --git a/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/handler/OpenDeclarationHandler.java b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/handler/OpenDeclarationHandler.java new file mode 100644 index 0000000..63ecfc2 --- a/dev/null +++ b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/handler/OpenDeclarationHandler.java @@ -0,0 +1,29 @@ +package org.eclipse.xtext.ui.core.editor.handler; + +import org.eclipse.core.commands.AbstractHandler; +import org.eclipse.core.commands.ExecutionEvent; +import org.eclipse.core.commands.ExecutionException; +import org.eclipse.ui.handlers.HandlerUtil; +import org.eclipse.xtext.ui.core.editor.OpenDeclarationAction; +import org.eclipse.xtext.ui.core.editor.XtextEditor; + +/** + * Represents a declarative handler contributed with the 'org.eclipse.ui.handlers' + * extension-point which simply delegates to {@link OpenDeclarationAction}. + * <p/> + * Note: this handler should only be enabled if the current active editor is an instance of <code>XtextEditor</code>. + * + * @author Michael Clay - Initial contribution and API + * + * @see org.eclipse.core.commands.AbstractHandler + */ +public class OpenDeclarationHandler extends AbstractHandler { + /* + * (non-Javadoc) + * @see org.eclipse.core.commands.AbstractHandler#execute(org.eclipse.core.commands.ExecutionEvent) + */ + public Object execute(ExecutionEvent event) throws ExecutionException { + new OpenDeclarationAction((XtextEditor) HandlerUtil.getActiveEditor(event)).run(); + return this; + } +} |

