/******************************************************************************* * Copyright (c) 2009, 2016 IBM Corporation 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 * * Contributors: * IBM Corporation - initial API and implementation * Zend Technologies *******************************************************************************/ package org.eclipse.php.internal.ui.util; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.HashMap; import java.util.Map; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Platform; import org.eclipse.dltk.ast.declarations.Declaration; import org.eclipse.dltk.ast.declarations.MethodDeclaration; import org.eclipse.dltk.ast.declarations.ModuleDeclaration; import org.eclipse.dltk.ast.declarations.TypeDeclaration; import org.eclipse.dltk.core.*; import org.eclipse.jface.dialogs.IDialogConstants; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.php.core.compiler.ast.nodes.IPHPDocAwareDeclaration; import org.eclipse.php.core.compiler.ast.nodes.PHPDocBlock; import org.eclipse.php.core.compiler.ast.nodes.PHPDocTag; import org.eclipse.php.core.compiler.ast.nodes.PHPDocTag.TagKind; import org.eclipse.php.internal.core.typeinference.PHPModelUtils; import org.eclipse.php.internal.ui.Logger; import org.eclipse.php.internal.ui.PHPUIMessages; import org.eclipse.php.internal.ui.PHPUiPlugin; import org.eclipse.php.internal.ui.preferences.PreferenceConstants; import org.eclipse.ui.PartInitException; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.browser.IWebBrowser; import org.eclipse.ui.browser.IWorkbenchBrowserSupport; public class PHPManual { private static final String BROWSER_ID = "PHPManual.browser"; //$NON-NLS-1$ private static final Pattern HTTP_URL_PATTERN = Pattern.compile("http://[^\\p{javaWhitespace}]*"); //$NON-NLS-1$ private static int browserCount = 0; private PHPManualSite site; private static Map<String, String> phpEntityPathMap; public PHPManual(PHPManualSite site) { this.site = site; } public PHPManualSite getSite() { return site; } public void setSite(PHPManualSite site) { this.site = site; } private synchronized Map<String, String> getPHPEntityPathMap() { if (phpEntityPathMap == null) { phpEntityPathMap = new HashMap<>(); URL url = FileLocator.find(Platform.getBundle(PHPUiPlugin.getPluginId()), new Path("phpdoc.mapping"), null); //$NON-NLS-1$ if (url != null) { try { BufferedReader r = new BufferedReader(new InputStreamReader(url.openStream())); String line; while ((line = r.readLine()) != null) { int sepIdx = line.indexOf('='); if (sepIdx != -1) { phpEntityPathMap.put(line.substring(0, sepIdx).toLowerCase(), line.substring(sepIdx + 1)); } } } catch (IOException e) { } } } return phpEntityPathMap; } /** * XXX: support manual for keywords This method tries to determine PHP * manual URL for the specified PHP element * * @param codeData * PHP element code data * @return URL for the manual page */ public String getURLForManual(IModelElement modelElement) { if (modelElement == null) { throw new IllegalArgumentException(); } String path = null; if (modelElement instanceof IMethod) { try { IModelElement ancestor = ((IMethod) modelElement).getAncestor(IModelElement.TYPE); if (null != ancestor) { // if this is actually a method (not function), checking for // declaring class manual path = buildPathForClass((IType) ancestor); } else { path = buildPathForMethod((IMethod) modelElement); } } catch (ModelException e) { Logger.logException(e); } } else if (modelElement instanceof IType) { try { path = buildPathForClass((IType) modelElement); } catch (ModelException e) { Logger.logException(e); } } if (path != null) { StringBuilder url = new StringBuilder(); url.append(site.getUrl()); if (!site.getUrl().endsWith("/")) { //$NON-NLS-1$ url.append("/"); //$NON-NLS-1$ } url.append(path); url.append("."); //$NON-NLS-1$ url.append(site.getExtension()); return url.toString(); } return null; } private String getPHPDocLink(Declaration declaration) { String path = null; if (declaration instanceof IPHPDocAwareDeclaration) { IPHPDocAwareDeclaration phpDocDeclaration = (IPHPDocAwareDeclaration) declaration; PHPDocBlock docBlock = phpDocDeclaration.getPHPDoc(); if (docBlock != null) { for (PHPDocTag docTag : docBlock.getTags(TagKind.LINK)) { Matcher m = HTTP_URL_PATTERN.matcher(docTag.getValue().trim()); if (m.find()) { try { URL url = new URL(m.group()); path = new File(url.getFile()).getName(); int extIdx = path.lastIndexOf('.'); if (extIdx > 0) { path = path.substring(0, extIdx); } break; } catch (MalformedURLException e) { } } } } } return path; } protected String buildPathForClass(IType type) throws ModelException { String path = null; if (type != null) { ISourceModule sourceModule = type.getSourceModule(); ModuleDeclaration moduleDeclaration = SourceParserUtil.getModuleDeclaration(sourceModule); TypeDeclaration typeDeclaration = PHPModelUtils.getNodeByClass(moduleDeclaration, type); path = getPHPDocLink(typeDeclaration); if (path == null) { String className = type.getElementName(); path = (String) getPHPEntityPathMap().get(className.toLowerCase()); if (path == null) { path = buildPathForClass(type.getElementName()); } } } return path; } private String buildPathForClass(String className) { StringBuilder buf = new StringBuilder(); buf.append("class."); //$NON-NLS-1$ if (className != null) { buf.append(className); } return buf.toString().toLowerCase(); } protected String buildPathForMethod(IMethod method) { ISourceModule sourceModule = method.getSourceModule(); ModuleDeclaration moduleDeclaration = SourceParserUtil.getModuleDeclaration(sourceModule); MethodDeclaration methodDeclaration; try { methodDeclaration = PHPModelUtils.getNodeByMethod(moduleDeclaration, method); } catch (ModelException e) { return null; } String path = getPHPDocLink(methodDeclaration); if (path == null) { IType declaringType = method.getDeclaringType(); if (declaringType != null) { String functionName = declaringType.getElementName() + "::" //$NON-NLS-1$ + method.getElementName(); path = (String) getPHPEntityPathMap().get(functionName.toLowerCase()); if (path == null) { path = buildPathForMethod(declaringType.getElementName(), method.getElementName()); } } else { path = (String) getPHPEntityPathMap().get(method.getElementName().toLowerCase()); if (path == null) { path = buildPathForMethod(null, method.getElementName()); } } } return path; } protected String buildPathForMethod(String className, String methodName) { StringBuilder buf = new StringBuilder(); buf.append("function."); //$NON-NLS-1$ if (className != null) { buf.append(className); buf.append("-"); //$NON-NLS-1$ } buf.append(Pattern.compile("([A-Z])").matcher(methodName) //$NON-NLS-1$ .replaceAll("-$1").replaceAll("_", "-")); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ return buf.toString().toLowerCase().replaceAll("-+", "-"); //$NON-NLS-1$ //$NON-NLS-2$ } /** * This function launches browser and shows PHP manual page for the * specified URL */ public void showFunctionHelp(String url) { IWorkbenchBrowserSupport browserSupport = PlatformUI.getWorkbench().getBrowserSupport(); IWebBrowser browser; try { IPreferenceStore store = PHPUiPlugin.getDefault().getPreferenceStore(); if (store.getBoolean(PreferenceConstants.PHP_MANUAL_OPEN_IN_NEW_BROWSER)) { browser = browserSupport.createBrowser(BROWSER_ID + ++browserCount); } else { browser = browserSupport.createBrowser(BROWSER_ID); } if (url.startsWith("mk:")) { //$NON-NLS-1$ browser.openURL(new URL(null, url, new MkHandler())); } else if (url.startsWith("help://")) { //$NON-NLS-1$ // convert to help system URL String helpURL = url.substring("help://".length()); //$NON-NLS-1$ // open in Help System PlatformUI.getWorkbench().getHelpSystem().displayHelpResource(helpURL); } else { URL url2 = validateUrlExists(url); if (null == url2) { // need to open some kind of err dialog and return MessageDialog d = new MessageDialog(PlatformUI.getWorkbench().getActiveWorkbenchWindow().getShell(), PHPUIMessages.PHPManual_title, null, PHPUIMessages.PHPManual_noManual_msg, MessageDialog.INFORMATION, new String[] { IDialogConstants.OK_LABEL }, 0); d.open(); return; } browser.openURL(url2); } } catch (PartInitException e) { Logger.logException(e); } catch (MalformedURLException e) { Logger.logException(e); } } protected URL validateUrlExists(String url) throws MalformedURLException { URL url2 = new URL(url); if ("file".equals(url2.getProtocol())) { //$NON-NLS-1$ return validateFileUrlExists(url, url2); } // else if ("http".equals(url2.getProtocol())){ // return validateHttpUrlExists(url, url2); // } return url2; } private URL validateFileUrlExists(String url, URL url2) { File file = new File(url.substring("file://".length())); //$NON-NLS-1$ if (null != file && file.exists()) { return url2; } else { return null; } } private class MkHandler extends URLStreamHandler { @Override protected URLConnection openConnection(URL arg0) throws IOException { return null; } } }