| author | mclay | 2008-12-08 15:31:47 (EST) |
|---|---|---|
| committer | sefftinge | 2008-12-08 15:31:47 (EST) |
| commit | 7140ccb354c7a073c2ac52ae38942379f961f472 (patch) (side-by-side diff) | |
| tree | 707a224e7ec086f9b36ce3ee2d857de4aa65f531 | |
| parent | 980d213e4ee9ccbcddc7ce521662f1d89b7b4a7a (diff) | |
| download | org.eclipse.xtext-7140ccb354c7a073c2ac52ae38942379f961f472.zip org.eclipse.xtext-7140ccb354c7a073c2ac52ae38942379f961f472.tar.gz org.eclipse.xtext-7140ccb354c7a073c2ac52ae38942379f961f472.tar.bz2 | |
ASSIGNED - bug 256402: [UI] Goto declaration
https://bugs.eclipse.org/bugs/show_bug.cgi?id=256402
2 files changed, 190 insertions, 1 deletions
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 new file mode 100644 index 0000000..ec3ff47 --- a/dev/null +++ b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/XtextHyperlinkDetector.java @@ -0,0 +1,151 @@ +/******************************************************************************* + * Copyright (c) 2008 itemis AG (http://www.itemis.eu) and others. + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + * + *******************************************************************************/ +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.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.ui.core.editor.model.IXtextDocument; +import org.eclipse.xtext.ui.core.editor.model.UnitOfWork; + +/** + * Represents an implementation of interface {@link IHyperlinkDetector} to find + * and convert {@link CrossReference elements}, at a given location, to + * <code>IHyperlink</code>. + * + * @author Michael Clay - Initial contribution and API + * @see org.eclipse.jface.text.hyperlink.IHyperlinkDetector + * @see org.eclipse.jface.text.hyperlink.IHyperlink + */ +public class XtextHyperlinkDetector implements IHyperlinkDetector { + + // logger available to subclasses + protected final Logger logger = Logger.getLogger(getClass()); + + private ILinkingService linkingService; + + public XtextHyperlinkDetector(ILinkingService linkingService) { + this.linkingService = linkingService; + } + + /* + * (non-Javadoc) + * + * @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) { + + CompositeNode rootNode = getRootNode(textViewer.getDocument()); + LeafNode currentNode = (LeafNode) ParseTreeUtil.getCurrentNodeByOffset(rootNode, region.getOffset()); + + if (currentNode.getGrammarElement() instanceof CrossReference) { + + EObject semanticModel = NodeUtil.getNearestSemanticObject(currentNode); + EReference eReference = GrammarUtil.getReference((CrossReference) currentNode.getGrammarElement(), + semanticModel.eClass()); + List<EObject> linkedObjects = this.linkingService.getLinkedObjects(semanticModel, eReference, currentNode); + + if (!linkedObjects.isEmpty()) { + return createXtextHyperlink(currentNode, linkedObjects.iterator().next()); + } + + } + + 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; + } + + 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 (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/XtextSourceViewerConfiguration.java b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/XtextSourceViewerConfiguration.java index abeb18a..d63ba88 100644 --- a/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/XtextSourceViewerConfiguration.java +++ b/plugins/org.eclipse.xtext.ui.core/src/org/eclipse/xtext/ui/core/editor/XtextSourceViewerConfiguration.java @@ -1,9 +1,16 @@ package org.eclipse.xtext.ui.core.editor; +import java.util.LinkedList; +import java.util.List; + import org.eclipse.jface.text.IDocument; +import org.eclipse.jface.text.IRegion; +import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.contentassist.ContentAssistant; import org.eclipse.jface.text.contentassist.IContentAssistProcessor; import org.eclipse.jface.text.contentassist.IContentAssistant; +import org.eclipse.jface.text.hyperlink.IHyperlink; +import org.eclipse.jface.text.hyperlink.IHyperlinkDetector; import org.eclipse.jface.text.presentation.IPresentationReconciler; import org.eclipse.jface.text.presentation.PresentationReconciler; import org.eclipse.jface.text.reconciler.IReconciler; @@ -11,6 +18,7 @@ import org.eclipse.jface.text.rules.DefaultDamagerRepairer; import org.eclipse.jface.text.rules.ITokenScanner; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.ui.editors.text.TextSourceViewerConfiguration; +import org.eclipse.xtext.crossref.ILinkingService; import org.eclipse.xtext.service.Inject; import org.eclipse.xtext.ui.core.editor.reconciler.XtextDocumentReconcileStrategy; import org.eclipse.xtext.ui.core.editor.reconciler.XtextReconciler; @@ -19,10 +27,12 @@ public class XtextSourceViewerConfiguration extends TextSourceViewerConfiguratio @Inject(optional = true) private IContentAssistant contentAssistant; - @Inject(optional = true) private IContentAssistProcessor contentAssistProcessor; + + @Inject(optional = true) + private ILinkingService linkingService; @Inject(optional = true) private ITokenScanner tokenScanner; @@ -45,6 +55,8 @@ public class XtextSourceViewerConfiguration extends TextSourceViewerConfiguratio xtextReconciler.setDelay(500); return xtextReconciler; } + + @Override public IPresentationReconciler getPresentationReconciler(ISourceViewer sourceViewer) { @@ -59,5 +71,31 @@ public class XtextSourceViewerConfiguration extends TextSourceViewerConfiguratio return super.getPresentationReconciler(sourceViewer); } } + + @Override + public IHyperlinkDetector[] getHyperlinkDetectors(ISourceViewer sourceViewer) { + List<IHyperlinkDetector> detectors = new LinkedList<IHyperlinkDetector>(); + IHyperlinkDetector[] inheritedDetectors = super.getHyperlinkDetectors(sourceViewer); + if (inheritedDetectors != null) { + for (final IHyperlinkDetector detector : inheritedDetectors) { + detectors.add(new IHyperlinkDetector() { + public IHyperlink[] detectHyperlinks(ITextViewer textViewer, IRegion region, + boolean canShowMultipleHyperlinks) { + try { + return detector.detectHyperlinks(textViewer, region, canShowMultipleHyperlinks); + } + catch (Throwable e) { + // fail safe hyperlink detector - prevent others + // from failing + } + return null; + } + + }); + } + } + detectors.add(new XtextHyperlinkDetector(this.linkingService)); + return detectors.toArray(new IHyperlinkDetector[detectors.size()]); + } } |

