/*******************************************************************************
* Copyright (c) 2007, 2013 David Green 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:
* David Green - initial API and implementation
*******************************************************************************/
package org.eclipse.mylyn.internal.wikitext.ui;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionPoint;
import org.eclipse.core.runtime.ILog;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.util.IPropertyChangeListener;
import org.eclipse.jface.util.PropertyChangeEvent;
import org.eclipse.mylyn.internal.wikitext.ui.editor.assist.MarkupTemplateCompletionProcessor;
import org.eclipse.mylyn.internal.wikitext.ui.editor.assist.Templates;
import org.eclipse.mylyn.internal.wikitext.ui.editor.help.CheatSheetContent;
import org.eclipse.mylyn.internal.wikitext.ui.editor.help.HelpContent;
import org.eclipse.mylyn.internal.wikitext.ui.editor.preferences.Preferences;
import org.eclipse.mylyn.internal.wikitext.ui.registry.EclipseServiceLocator;
import org.eclipse.mylyn.wikitext.parser.markup.MarkupLanguage;
import org.eclipse.mylyn.wikitext.ui.WikiText;
import org.eclipse.mylyn.wikitext.util.ServiceLocator;
import org.eclipse.osgi.util.NLS;
import org.eclipse.swt.widgets.Text;
import org.eclipse.ui.plugin.AbstractUIPlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableMap;
/**
* @author David Green
*/
public class WikiTextUiPlugin extends AbstractUIPlugin {
private static final String EXTENSION_POINT_CHEAT_SHEET = "cheatSheet"; //$NON-NLS-1$
private static final String EXTENSION_POINT_CONTENT_ASSIST = "contentAssist"; //$NON-NLS-1$
private static final String EXTENSION_POINT_TEMPLATES = "templates"; //$NON-NLS-1$
private static final String EXTENSION_POINT_TEMPLATE = "template"; //$NON-NLS-1$
private static final String EXTENSION_POINT_RELATIVE_FILE_PATH_HYPERLINK_DECTOR = "relativeFilePathHyperlinkDetector"; //$NON-NLS-1$
private static final String EXTENSION_POINT_FILE_REF_REGEX = "regularExpression"; //$NON-NLS-1$
private static WikiTextUiPlugin plugin;
private SortedMap<String, HelpContent> cheatSheets;
private Map<String, Templates> templates;
private Preferences preferences;
private IPropertyChangeListener preferencesListener;
private Map<String, List<String>> fileRefRegexes;
public WikiTextUiPlugin() {
plugin = this;
ServiceLocator.setImplementation(EclipseServiceLocator.class);
}
@Override
public void start(BundleContext context) throws Exception {
super.start(context);
preferencesListener = new IPropertyChangeListener() {
public void propertyChange(PropertyChangeEvent event) {
preferences = null;
}
};
getPreferenceStore().addPropertyChangeListener(preferencesListener);
}
@Override
public void stop(BundleContext context) throws Exception {
plugin = null;
if (preferencesListener != null) {
getPreferenceStore().removePropertyChangeListener(preferencesListener);
preferencesListener = null;
}
super.stop(context);
}
/**
* Returns the shared instance
*
* @return the shared instance
*/
public static WikiTextUiPlugin getDefault() {
return plugin;
}
public void log(Throwable ce) {
if (ce instanceof CoreException) {
getLog().log(((CoreException) ce).getStatus());
} else {
log(IStatus.ERROR, ce.getMessage(), ce);
}
}
public void log(int severity, String message, Throwable exception) {
if (message == null) {
message = ""; //$NON-NLS-1$
}
ILog log = getLog();
IStatus status = null;
if (exception instanceof CoreException) {
status = ((CoreException) exception).getStatus();
}
if (status == null) {
status = new Status(severity, getPluginId(), severity, message, exception);
}
log.log(status);
}
public String getPluginId() {
return getBundle().getSymbolicName();
}
public IStatus createStatus(int statusCode, Throwable exception) {
return createStatus(null, statusCode, exception);
}
public IStatus createStatus(String message, int statusCode, Throwable exception) {
if (message == null && exception != null) {
message = exception.getClass().getName() + ": " + exception.getMessage(); //$NON-NLS-1$
}
Status status = new Status(statusCode, getPluginId(), statusCode, message, exception);
return status;
}
public Preferences getPreferences() {
if (preferences == null) {
Preferences prefs = new Preferences();
prefs.load(getPreferenceStore());
prefs.makeImmutable();
preferences = prefs;
}
return preferences;
}
public SortedMap<String, HelpContent> getCheatSheets() {
if (cheatSheets == null) {
SortedMap<String, HelpContent> cheatSheets = new TreeMap<>();
IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(getPluginId(),
EXTENSION_POINT_CHEAT_SHEET);
if (extensionPoint != null) {
IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements();
for (IConfigurationElement element : configurationElements) {
String declaringPluginId = element.getDeclaringExtension().getContributor().getName();
Bundle bundle = Platform.getBundle(declaringPluginId);
String markupLanguage = element.getAttribute("markupLanguage"); //$NON-NLS-1$
String contentLanguage = element.getAttribute("contentLanguage"); //$NON-NLS-1$
String resource = element.getAttribute("resource"); //$NON-NLS-1$
try {
if (markupLanguage == null) {
throw new Exception(Messages.WikiTextUiPlugin_markupLanguageRequired);
} else if (!WikiText.getMarkupLanguageNames().contains(markupLanguage)) {
throw new Exception(NLS.bind(Messages.WikiTextUiPlugin_invalidMarkupLanguage,
new Object[] { markupLanguage }));
}
if (resource == null || resource.length() == 0) {
throw new Exception(Messages.WikiTextUiPlugin_resourceRequired);
}
HelpContent cheatSheet = new CheatSheetContent(bundle, resource, contentLanguage,
markupLanguage);
HelpContent previous = cheatSheets.put(cheatSheet.getMarkupLanguageName(), cheatSheet);
if (previous != null) {
cheatSheets.put(previous.getMarkupLanguageName(), previous);
throw new Exception(NLS.bind(Messages.WikiTextUiPlugin_markupLanguageContentAlreadyDeclared,
new Object[] { previous.getMarkupLanguageName(),
previous.getProvider().getSymbolicName() }));
}
} catch (Exception e) {
log(IStatus.ERROR, NLS.bind(Messages.WikiTextUiPlugin_invalidExtension,
new Object[] { declaringPluginId, EXTENSION_POINT_CHEAT_SHEET, e.getMessage() }), e);
}
}
}
this.cheatSheets = Collections.unmodifiableSortedMap(cheatSheets);
}
return cheatSheets;
}
/**
* get templates mapped by their markup language name
*
* @return the templates
*/
public Map<String, Templates> getTemplates() {
if (templates == null) {
Map<String, Templates> templates = new HashMap<>();
IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(getPluginId(),
EXTENSION_POINT_CONTENT_ASSIST);
if (extensionPoint != null) {
IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements();
for (IConfigurationElement element : configurationElements) {
String declaringPluginId = element.getDeclaringExtension().getContributor().getName();
if (EXTENSION_POINT_TEMPLATES.equals(element.getName())) {
try {
String markupLanguage = element.getAttribute("markupLanguage"); //$NON-NLS-1$
if (markupLanguage == null) {
throw new Exception(Messages.WikiTextUiPlugin_markupLanguageRequired);
} else if (!WikiText.getMarkupLanguageNames().contains(markupLanguage)) {
throw new Exception(NLS.bind(Messages.WikiTextUiPlugin_invalidMarkupLanguage,
new Object[] { markupLanguage }));
}
Templates markupLanguageTemplates = new Templates();
markupLanguageTemplates.setMarkupLanguageName(markupLanguage);
for (IConfigurationElement templatesChild : element.getChildren()) {
if (EXTENSION_POINT_TEMPLATE.equals(templatesChild.getName())) {
try {
// process the template
String name = templatesChild.getAttribute("name"); //$NON-NLS-1$
String description = templatesChild.getAttribute("description"); //$NON-NLS-1$
String content = templatesChild.getAttribute("content"); //$NON-NLS-1$
String autoInsert = templatesChild.getAttribute("autoInsert"); //$NON-NLS-1$
String block = templatesChild.getAttribute("block"); //$NON-NLS-1$
if (name == null || name.length() == 0) {
throw new Exception(NLS.bind(Messages.WikiTextUiPlugin_nameRequired,
new Object[] { EXTENSION_POINT_TEMPLATE }));
}
if (description == null || description.length() == 0) {
throw new Exception(NLS.bind(Messages.WikiTextUiPlugin_descriptionRequired,
new Object[] { EXTENSION_POINT_TEMPLATE }));
}
if (content == null || content.length() == 0) {
throw new Exception(NLS.bind(Messages.WikiTextUiPlugin_contentRequired,
new Object[] { EXTENSION_POINT_TEMPLATE }));
}
content = content.replace("\\t", "\t"); //$NON-NLS-1$//$NON-NLS-2$
content = content.replace("\\r\\n", Text.DELIMITER) //$NON-NLS-1$
.replace("\\r", //$NON-NLS-1$
Text.DELIMITER)
.replace("\\n", Text.DELIMITER) //$NON-NLS-1$
.replace("\\\\", "\\"); //$NON-NLS-1$ //$NON-NLS-2$
if (content.endsWith("$") //$NON-NLS-1$
&& !(content.endsWith("\\$") || content.endsWith("$$"))) { //$NON-NLS-1$ //$NON-NLS-2$
content = content.substring(0, content.length() - 1);
}
if (content.startsWith("^")) { //$NON-NLS-1$
content = content.substring(1);
}
content = content.replace("\\$", "$$"); //$NON-NLS-1$ //$NON-NLS-2$
markupLanguageTemplates
.addTemplate(
new Template(name, description,
MarkupTemplateCompletionProcessor.CONTEXT_ID, content,
autoInsert == null
|| !"false".equalsIgnoreCase(autoInsert)), //$NON-NLS-1$
block != null && "true".equalsIgnoreCase(block)); //$NON-NLS-1$
} catch (Exception e) {
log(IStatus.ERROR,
NLS.bind(Messages.WikiTextUiPlugin_invalidExtension,
new Object[] { declaringPluginId,
EXTENSION_POINT_CONTENT_ASSIST, e.getMessage() }),
e);
}
} else {
log(IStatus.ERROR,
NLS.bind(Messages.WikiTextUiPlugin_unexpectedExtensionElement,
new Object[] { declaringPluginId, EXTENSION_POINT_CONTENT_ASSIST,
templatesChild.getName() }),
null);
}
}
Templates previous = templates.put(markupLanguageTemplates.getMarkupLanguageName(),
markupLanguageTemplates);
if (previous != null) {
markupLanguageTemplates.addAll(previous);
}
} catch (Exception e) {
log(IStatus.ERROR, NLS.bind(Messages.WikiTextUiPlugin_invalidExtension,
new Object[] { declaringPluginId, EXTENSION_POINT_TEMPLATES, e.getMessage() }), e);
}
} else {
log(IStatus.ERROR, NLS.bind(Messages.WikiTextUiPlugin_unexpectedExtensionElement,
new Object[] { declaringPluginId, EXTENSION_POINT_CONTENT_ASSIST, element.getName() }),
null);
}
}
}
// now that we have the basic templates, check for language extensions and connect the hierarchy
// first ensure that all language names have templates defined
Set<String> languageNames = WikiText.getMarkupLanguageNames();
for (String languageName : languageNames) {
Templates languageTemplates = templates.get(languageName);
if (languageTemplates == null) {
languageTemplates = new Templates();
templates.put(languageName, languageTemplates);
}
}
// next connect the hierarchy
for (String languageName : languageNames) {
MarkupLanguage markupLanguage = WikiText.getMarkupLanguage(languageName);
if (markupLanguage != null && markupLanguage.getExtendsLanguage() != null) {
Templates languageTemplates = templates.get(languageName);
Templates parentLanguageTemplates = templates.get(markupLanguage.getExtendsLanguage());
languageTemplates.setParent(parentLanguageTemplates);
}
}
this.templates = Collections.unmodifiableMap(templates);
}
return templates;
}
public Map<String, List<String>> getHyperlinkDectectorFileRefRegexes() {
if (fileRefRegexes == null) {
com.google.common.collect.ImmutableMap.Builder<String, List<String>> markupLanguageToFileRefRegexes = ImmutableMap
.builder();
IExtensionPoint extensionPoint = Platform.getExtensionRegistry().getExtensionPoint(getPluginId(),
EXTENSION_POINT_RELATIVE_FILE_PATH_HYPERLINK_DECTOR);
if (extensionPoint != null) {
IConfigurationElement[] configurationElements = extensionPoint.getConfigurationElements();
for (IConfigurationElement element : configurationElements) {
String declaringPluginId = element.getDeclaringExtension().getContributor().getName();
if (EXTENSION_POINT_RELATIVE_FILE_PATH_HYPERLINK_DECTOR.equals(element.getName())) {
try {
String markupLanguage = validateAndGetMarkupLanguage(element);
List<String> regexes = createFielRefRegexes(element, declaringPluginId);
markupLanguageToFileRefRegexes.put(markupLanguage, regexes);
} catch (Exception e) {
log(IStatus.ERROR,
NLS.bind(Messages.WikiTextUiPlugin_invalidExtension,
new Object[] { declaringPluginId,
EXTENSION_POINT_RELATIVE_FILE_PATH_HYPERLINK_DECTOR,
e.getMessage() }),
e);
}
} else {
log(IStatus.ERROR,
NLS.bind(Messages.WikiTextUiPlugin_unexpectedExtensionElement,
new Object[] { declaringPluginId,
EXTENSION_POINT_RELATIVE_FILE_PATH_HYPERLINK_DECTOR,
element.getName() }),
null);
}
}
}
fileRefRegexes = markupLanguageToFileRefRegexes.build();
}
return fileRefRegexes;
}
private List<String> createFielRefRegexes(IConfigurationElement element, String declaringPluginId) {
Builder<String> regexes = new ImmutableList.Builder<>();
for (IConfigurationElement fileRefRegexesChild : element.getChildren()) {
if (EXTENSION_POINT_FILE_REF_REGEX.equals(fileRefRegexesChild.getName())) {
try {
String fileRefRegex = fileRefRegexesChild.getAttribute(EXTENSION_POINT_FILE_REF_REGEX);
regexes.add(fileRefRegex);
} catch (Exception e) {
log(IStatus.ERROR, NLS.bind(Messages.WikiTextUiPlugin_invalidExtension, new Object[] {
declaringPluginId, EXTENSION_POINT_RELATIVE_FILE_PATH_HYPERLINK_DECTOR, e.getMessage() }),
e);
}
} else {
log(IStatus.ERROR,
NLS.bind(Messages.WikiTextUiPlugin_unexpectedExtensionElement, new Object[] { declaringPluginId,
EXTENSION_POINT_RELATIVE_FILE_PATH_HYPERLINK_DECTOR, fileRefRegexesChild.getName() }),
null);
}
}
return regexes.build();
}
private String validateAndGetMarkupLanguage(IConfigurationElement element) throws Exception {
String markupLanguage = element.getAttribute("markupLanguage"); //$NON-NLS-1$
if (markupLanguage == null) {
throw new Exception(Messages.WikiTextUiPlugin_markupLanguageRequired);
} else if (!WikiText.getMarkupLanguageNames().contains(markupLanguage)) {
throw new Exception(
NLS.bind(Messages.WikiTextUiPlugin_invalidMarkupLanguage, new Object[] { markupLanguage }));
}
return markupLanguage;
}
}