/* * Copyright (c) 2012, the Dart project authors. * * Licensed under the Eclipse Public License v1.0 (the "License"); you may not use this file except * in compliance with the License. You may obtain a copy of the License at * * http://www.eclipse.org/legal/epl-v10.html * * Unless required by applicable law or agreed to in writing, software distributed under the License * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express * or implied. See the License for the specific language governing permissions and limitations under * the License. */ package com.google.dart.tools.ui.internal.text.editor; import com.google.dart.engine.ast.AstNode; import com.google.dart.engine.ast.Expression; import com.google.dart.engine.ast.visitor.ElementLocator; import com.google.dart.engine.element.Element; import com.google.dart.engine.services.util.DartDocUtilities; import com.google.dart.engine.type.Type; import com.google.dart.tools.ui.internal.actions.NewSelectionConverter; import com.google.dart.tools.ui.text.DartSourceViewerConfiguration; import org.eclipse.jface.text.DefaultTextHover; import org.eclipse.jface.text.IInformationControlCreator; import org.eclipse.jface.text.IRegion; import org.eclipse.jface.text.ITextHover; import org.eclipse.jface.text.ITextHoverExtension; import org.eclipse.jface.text.ITextHoverExtension2; import org.eclipse.jface.text.ITextViewer; import org.eclipse.jface.text.source.Annotation; import org.eclipse.jface.text.source.ISourceViewer; import org.eclipse.ui.texteditor.ITextEditor; import java.util.ArrayList; import java.util.List; /** * An implementation of ITextHover for Dart documentation. Other ITextHover implementations can * register themselves using {@link #addContributer(ITextHover)} and they will be invoked before the * default dart doc hover tool tip. */ public class DartTextHover extends DefaultTextHover implements ITextHoverExtension, ITextHoverExtension2 { private static List<ITextHover> hoverContributors = new ArrayList<ITextHover>(); /** * Register a ITextHover tooltip contributor * * @param hoverContributor */ public static void addContributer(ITextHover hoverContributor) { hoverContributors.add(hoverContributor); } public static String getElementDocumentationHtml(String textSummary, String dartdoc) { if (textSummary != null) { StringBuffer docs = new StringBuffer(); docs.append("<b>" + textSummary + "</b>"); if (dartdoc != null) { docs.append("<br><br>"); docs.append(dartdoc); } return docs.toString().trim(); } return null; } public static String getElementDocumentationHtml(Type type, Element element) { if (element != null) { String textSummary = DartDocUtilities.getTextSummaryAsHtml(type, element); if (textSummary != null) { StringBuffer docs = new StringBuffer(); docs.append("<b>" + textSummary + "</b>"); String dartdoc = DartDocUtilities.getDartDocAsHtml(element); if (dartdoc != null) { docs.append("<br><br>"); docs.append(dartdoc); } return docs.toString().trim(); } } return null; } /** * Remove a hover contributor * * @param hoverContributor */ public static void removeContributer(ITextHover hoverContributor) { hoverContributors.remove(hoverContributor); } private static StringBuilder append(StringBuilder buffer, String s) { if (buffer.length() != 0) { buffer.append("<br><br>"); } if (s != null) { buffer.append(s); } return buffer; } private CompilationUnitEditor editor; private DartSourceViewerConfiguration sourceViewerConfiguration; private ITextHover lastReturnedHover; public DartTextHover(ITextEditor editor, ISourceViewer sourceViewer, DartSourceViewerConfiguration sourceViewerConfiguration) { super(sourceViewer); if (editor instanceof CompilationUnitEditor) { this.editor = (CompilationUnitEditor) editor; } this.sourceViewerConfiguration = sourceViewerConfiguration; } @Override public IInformationControlCreator getHoverControlCreator() { if (lastReturnedHover instanceof ITextHoverExtension) { return ((ITextHoverExtension) lastReturnedHover).getHoverControlCreator(); } else { return null; } } @SuppressWarnings("deprecation") @Override public String getHoverInfo(ITextViewer textViewer, IRegion region) { // Return any annotation info - i.e. errors and warnings. String annotationHover = super.getHoverInfo(textViewer, region); if (annotationHover != null) { return escapeHtmlEntities(annotationHover); } // Check through the contributed hover providers. for (ITextHover hoverContributer : hoverContributors) { String hoverText = hoverContributer.getHoverInfo(textViewer, region); if (hoverText != null) { lastReturnedHover = hoverContributer; return hoverText; } } // Check for a dartdoc contribution. return getDartDocHover(region); } @Override public Object getHoverInfo2(ITextViewer textViewer, IRegion region) { // Overridden from ITextHoverExtension2. We try and return the richest help available; this // means trying to call getHoverInfo2() on any contributors, and falling back on getHoverInfo(). lastReturnedHover = null; StringBuilder buffer = new StringBuilder(); // Append any annotation info - i.e. errors and warnings. String annotationHover = super.getHoverInfo(textViewer, region); if (annotationHover != null) { append(buffer, escapeHtmlEntities(annotationHover)); } // Check through the contributed hover providers. for (ITextHover hoverContributer : hoverContributors) { if (hoverContributer instanceof ITextHoverExtension2) { Object hoverInfo = ((ITextHoverExtension2) hoverContributer).getHoverInfo2( textViewer, region); if (hoverInfo != null) { lastReturnedHover = hoverContributer; return hoverInfo; } } else { String hoverText = hoverContributer.getHoverInfo(textViewer, region); if (hoverText != null) { lastReturnedHover = hoverContributer; return hoverText; } } } // Check for a dartdoc contribution. String dartDocHover = getDartDocHover(region); return append(buffer, dartDocHover).toString(); } @Override protected boolean isIncluded(Annotation annotation) { return sourceViewerConfiguration.isShownInText(annotation); } private String escapeHtmlEntities(String str) { str = str.replace("&", "&").replace("<", "<").replace(">", ">"); return str; } /** * Return the associated DartDoc hover, if any. */ private String getDartDocHover(IRegion region) { if (editor != null) { int offset = region.getOffset(); AstNode node = NewSelectionConverter.getNodeAtOffset(editor, offset); if (node == null) { return null; } Type type = node instanceof Expression ? ((Expression) node).getBestType() : null; Element element = ElementLocator.locateWithOffset(node, offset); return getElementDocumentationHtml(type, element); } return null; } }