/******************************************************************************* * Copyright (c) 2014, 2015 Cisco Systems, Inc. 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 com.cisco.yangide.editor.editors.text.help; import java.util.Objects; import org.eclipse.jdt.ui.PreferenceConstants; import org.eclipse.jface.internal.text.html.HTMLPrinter; import org.eclipse.jface.resource.JFaceResources; import org.eclipse.swt.graphics.FontData; import com.cisco.yangide.core.dom.ASTNamedNode; import com.cisco.yangide.core.dom.ASTNode; import com.cisco.yangide.core.dom.BaseReference; import com.cisco.yangide.core.dom.Module; import com.cisco.yangide.core.dom.ModuleImport; import com.cisco.yangide.core.dom.QName; import com.cisco.yangide.core.dom.SubModuleInclude; import com.cisco.yangide.core.dom.TypeReference; import com.cisco.yangide.core.dom.UsesNode; import com.cisco.yangide.core.indexing.ElementIndexInfo; import com.cisco.yangide.core.indexing.ElementIndexType; import com.cisco.yangide.core.model.YangModelManager; import com.cisco.yangide.editor.YangEditorPlugin; import com.cisco.yangide.editor.editors.text.help.YangLanguageHelpLoader.DefinitionKind; /** * Utilities aimed to be used in different context-oriented help providers for YANG source * code text editor. These providers include hover, quick-fix, content-assist and the like. * * @author Kirill Karmakulov * @date Oct 13, 2014 */ @SuppressWarnings("restriction") public class HelpCompositionUtils { private static String styleSheet = null; /** * Gets quick help related to the provided {@code node}. * * @return a {@link String} containing the help */ public static String getNodeHelp(ASTNode node) { if (node.getDescription() != null && node.getDescription().length() > 0) { return getLocalInfo(node); } String info = getIndexedInfo(node); if (info == null) info = getLanguageHelp(node); return info; } /** * Gets quick help related to the provided {@code node}. The information * returned as the result is taken from the index and matches the given {@code node}. */ public static String getIndexedInfo(ASTNode node) { QName name = null; ElementIndexType indexType = null; if (node instanceof TypeReference) { name = ((TypeReference) node).getType(); indexType = ElementIndexType.TYPE; } else if (node instanceof UsesNode) { name = ((UsesNode) node).getGrouping(); indexType = ElementIndexType.GROUPING; } else if (node instanceof ModuleImport) { ModuleImport mImport = (ModuleImport) node; name = new QName(mImport.getName(), mImport.getPrefix(), mImport.getName(), mImport.getRevision()); indexType = ElementIndexType.MODULE; } else if (node instanceof SubModuleInclude) { SubModuleInclude include = (SubModuleInclude) node; name = new QName(null, null, include.getName(), include.getRevision()); indexType = ElementIndexType.SUBMODULE; } else if (node instanceof BaseReference) { name = ((BaseReference) node).getType(); indexType = ElementIndexType.IDENTITY; } return name != null ? getIndexedInfo(name.getName(), name.getModule(), name.getRevision(), indexType) : null; } /** * Gets quick help related to the provided {@code nodeName}, {@code module}, {@code revision}. The information * returned as the result is taken from the index and matches the given fields. */ public static String getIndexedInfo(String nodeName, String module, String revision, ElementIndexType indexType) { ElementIndexInfo[] search = YangModelManager.search(module, revision, nodeName, indexType, null, null); if (indexType == ElementIndexType.TYPE && search.length == 0) { search = YangModelManager.search(module, revision, nodeName, ElementIndexType.IDENTITY, null, null); } if (search.length == 0) return null; ElementIndexInfo info = search[0]; StringBuffer buffer = new StringBuffer(); HTMLPrinter.addSmallHeader(buffer, info.getName()); if (info.getDescription() != null) { HTMLPrinter.addParagraph(buffer, formatValue(info.getDescription())); } buffer.append("<dl>"); if (info.getType() != ElementIndexType.MODULE && info.getType() != ElementIndexType.SUBMODULE) { addValue(buffer, "Module", info.getModule()); } addValue(buffer, "Reference", info.getReference()); addValue(buffer, "Status", info.getStatus()); addValue(buffer, "Revision", info.getRevision()); addValue(buffer, "Namespace", info.getNamespace()); addValue(buffer, "Organization", info.getOrganization()); addValue(buffer, "Contact", info.getContact()); buffer.append("</dl>"); return finish(buffer); } /** * Gets quick help related to the provided {@code node}. The information * returned as the result is retrieved from the node itself. */ public static String getLocalInfo(ASTNode node) { StringBuffer buffer = new StringBuffer(); String name = node.getNodeName(); if (node instanceof ASTNamedNode) { name += ":" + ((ASTNamedNode) node).getName(); } HTMLPrinter.addSmallHeader(buffer, name); HTMLPrinter.addParagraph(buffer, formatValue(node.getDescription())); buffer.append("<dl>"); if (node instanceof Module) { Module module = (Module) node; addValue(buffer, "Namespace", module.getNamespace() != null ? module.getNamespace() : null); addValue(buffer, "Organization", module.getOrganization() != null ? module.getOrganization().getValue() : null); addValue(buffer, "Contact", module.getContact() != null ? module.getContact().getValue() : null); } addValue(buffer, "Reference", node.getReference()); addValue(buffer, "Status", node.getStatus()); buffer.append("</dl>"); return finish(buffer); } public static String getLanguageHelp(ASTNode node) { if (node instanceof TypeReference) return new LanguageProposalHelpGenerator(((TypeReference) node).getName(), DefinitionKind.TYPE).get(null); else return new LanguageProposalHelpGenerator(node.getNodeName(), DefinitionKind.KEYWORD).get(null); } /** * Adds standard HTML header and footer to a partial HTML given in {@code text}. * Adds the given {@code title} if one is specified. * * @param text the wrapped HTML text * @param title an optional title * @return a String that contains fully equipped HTML text */ public static String wrapHtmlText(String text, String title) { Objects.requireNonNull(text, "The wrapped HTML content must not be null"); StringBuffer buffer = new StringBuffer(); if (title != null && !title.isEmpty()) { HTMLPrinter.addSmallHeader(buffer, title); } if (text.contains("<")) // has formatting buffer.append(text); else HTMLPrinter.addParagraph(buffer, text); return finish(buffer); } private static String formatValue(String source) { return source.replaceAll("\\n", "<br>"); } private static void addValue(StringBuffer buffer, String key, String value) { if (value != null && value.length() > 0) { HTMLPrinter.addParagraph(buffer, "<dt>" + key + ":</dt><dd>" + formatValue(value) + "</dd>"); } } private static String finish(StringBuffer buffer) { HTMLPrinter.insertPageProlog(buffer, 0, getStyleSheet()); HTMLPrinter.addPageEpilog(buffer); return buffer.toString(); } /** * Returns a stylesheet used among quick-help infopopups. */ private static String getStyleSheet() { if (styleSheet == null) { styleSheet = YangEditorPlugin.getDefault().getBundleFileContent( "/resources/HoverStyleSheet.css"); } String css = styleSheet; if (css != null) { FontData fontData = JFaceResources.getFontRegistry().getFontData( PreferenceConstants.APPEARANCE_JAVADOC_FONT)[0]; css = HTMLPrinter.convertTopLevelFont(css, fontData); } return css; } }