/*=============================================================================#
# Copyright (c) 2012-2016 Stephan Wahlbrink (WalWare.de) 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:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.statet.r.internal.console.ui.snippets;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.eclipse.core.commands.ExecutionEvent;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.variables.IDynamicVariable;
import org.eclipse.core.variables.IStringVariable;
import org.eclipse.core.variables.IStringVariableManager;
import org.eclipse.core.variables.VariablesPlugin;
import org.eclipse.jface.text.templates.ContextTypeRegistry;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.persistence.TemplateStore;
import org.eclipse.ui.PlatformUI;
import org.eclipse.ui.commands.ICommandService;
import org.eclipse.ui.editors.text.templates.ContributionContextTypeRegistry;
import org.eclipse.ui.editors.text.templates.ContributionTemplateStore;
import org.eclipse.ui.statushandlers.StatusManager;
import de.walware.ecommons.ltk.ui.util.LTKWorkbenchUIUtil;
import de.walware.ecommons.text.TextUtil;
import de.walware.ecommons.ui.util.UIAccess;
import de.walware.ecommons.ui.workbench.ResourceVariableUtil;
import de.walware.ecommons.variables.core.DynamicVariable;
import de.walware.ecommons.variables.core.StaticVariable;
import de.walware.ecommons.variables.core.StringVariable;
import de.walware.ecommons.variables.core.UnresolvedVariable;
import de.walware.ecommons.variables.core.VariableText2;
import de.walware.statet.r.core.RUtil;
import de.walware.statet.r.internal.console.ui.RConsoleUIPlugin;
import de.walware.statet.r.launching.RCodeLaunching;
import de.walware.statet.r.ui.rtool.RElementNameVariableResolver;
import de.walware.statet.r.ui.rtool.RResourceEncodingVariableResolver;
public class RSnippets {
public static final String SUBMIT_SNIPPET_COMMAND_ID = "de.walware.statet.r.commands.SubmitRSnippet"; //$NON-NLS-1$
public static final String SUBMIT_LAST_COMMAND_ID = "de.walware.statet.r.commands.SubmitLastRSnippet"; //$NON-NLS-1$
public static final String SNIPPET_PAR = "snippet"; //$NON-NLS-1$
public static final IStringVariable RESOURCE_ENCODING_VARIABLE = new StringVariable(
"resource_encoding", Messages.Variable_ResourceEncoding_description ); //$NON-NLS-1$
public static final IStringVariable ECHO_ENABLED_VARIABLE = new StringVariable(
"echo", Messages.Variable_Echo_description ); //$NON-NLS-1$
private static final String[] PRECHECKED_NAMES = new String[] {
"selected_text", //$NON-NLS-1$
RElementNameVariableResolver.R_OBJECT_NAME_NAME,
};
private static void add(final Map<String, IStringVariable> map, final IStringVariable var) {
map.put(var.getName(), var);
}
private ContextTypeRegistry fTemplatesContextTypeRegistry;
private TemplateStore fTemplatesStore;
private String fLastSnippetName;
private final Runnable fLastSnippetRunnable = new Runnable() {
@Override
public void run() {
final ICommandService service = (ICommandService) PlatformUI.getWorkbench()
.getService(ICommandService.class);
service.refreshElements(SUBMIT_LAST_COMMAND_ID, null);
}
};
public RSnippets() {
}
public List<IStringVariable> getVariables() {
final IStringVariable[] variables = VariablesPlugin.getDefault()
.getStringVariableManager().getVariables();
final List<IStringVariable> all= new ArrayList<>(variables.length + 2);
for (int i = 0; i < variables.length; i++) {
all.add(variables[i]);
}
all.add(RESOURCE_ENCODING_VARIABLE);
all.add(ECHO_ENABLED_VARIABLE);
return all;
}
private synchronized void initTemplates() {
if (fTemplatesContextTypeRegistry == null) {
fTemplatesContextTypeRegistry = new ContributionContextTypeRegistry();
fTemplatesContextTypeRegistry.addContextType(new RSnippetTemplatesContextType());
fTemplatesStore = new ContributionTemplateStore(fTemplatesContextTypeRegistry,
RConsoleUIPlugin.getDefault().getPreferenceStore(),
RSnippetTemplatesContextType.TEMPLATES_KEY );
try {
fTemplatesStore.load();
}
catch (final IOException e) {
RConsoleUIPlugin.log(new Status(IStatus.ERROR, RConsoleUIPlugin.PLUGIN_ID, -1,
"An error occured when loading 'R snippet' template store.", e )); //$NON-NLS-1$
}
}
}
/**
* Returns the template context type registry for the R snippets.
*
* @return the template context type registry
*/
public synchronized ContextTypeRegistry getTemplateContextRegistry() {
if (fTemplatesContextTypeRegistry == null) {
initTemplates();
}
return fTemplatesContextTypeRegistry;
}
/**
* Returns the template store for the R snippets.
*
* @return the template store
*/
public synchronized TemplateStore getTemplateStore() {
if (fTemplatesStore == null) {
initTemplates();
}
return fTemplatesStore;
}
private Map<String, IStringVariable> createResolveVariables() {
final ResourceVariableUtil util = new ResourceVariableUtil();
final Map<String, IStringVariable> variables= new HashMap<>();
add(variables, new DynamicVariable.ResolverVariable(
RSnippets.RESOURCE_ENCODING_VARIABLE, new RResourceEncodingVariableResolver(util)));
add(variables, new EchoEnabledVariable());
return variables;
}
private void addPrechecked(final Map<String, IStringVariable> variables) {
final IStringVariableManager manager = VariablesPlugin.getDefault().getStringVariableManager();
for (int i = 0; i < PRECHECKED_NAMES.length; i++) {
final IDynamicVariable real = manager.getDynamicVariable(PRECHECKED_NAMES[i]);
if (real == null) {
continue;
}
try {
final String value = real.getValue(null);
add(variables, new StaticVariable(real, value));
}
catch (final CoreException e) {
add(variables, new UnresolvedVariable(real, e));
}
}
}
public String resolve(final Template template) throws CoreException {
final VariableText2 text = new VariableText2(createResolveVariables()) {
@Override
protected String checkValue(final IStringVariable variable, final String value) {
if (!"selected_text".equals(variable.getName()) //$NON-NLS-1$
&& !RElementNameVariableResolver.R_OBJECT_NAME_NAME.equals(variable.getName()) ) {
return RUtil.escapeCompletely(value);
}
return value;
}
};
return text.performStringSubstitution(template.getPattern(), null);
}
public IStatus validate(final TemplateContextType contextType, final String template) {
try {
final VariableText2 text = new VariableText2(createResolveVariables());
text.validate(template, VariableText2.Severities.CHECK_SYNTAX, null);
return Status.OK_STATUS;
}
catch (final CoreException e) {
return e.getStatus();
}
}
public List<Template> validate(final Template[] templates) {
final Map<String, IStringVariable> variables = createResolveVariables();
addPrechecked(variables);
final VariableText2 text = new VariableText2(variables);
final List<Template> tested = new ArrayList<>(templates.length);
for (final Template template : templates) {
try {
text.validate(template.getPattern(), VariableText2.Severities.RESOLVE, null);
tested.add(template);
}
catch (final CoreException e) {}
}
return tested;
}
public void setLastSnippet(final String name) {
synchronized (fLastSnippetRunnable) {
if ((fLastSnippetName != null) ? fLastSnippetName.equals(name) : null == name) {
return;
}
fLastSnippetName = name;
}
UIAccess.getDisplay().asyncExec(fLastSnippetRunnable);
}
public String getLastSnippet() {
synchronized (fLastSnippetRunnable) {
return fLastSnippetName;
}
}
public void run(final Template template, final ExecutionEvent event) {
setLastSnippet(template.getName());
try {
final String snippet = resolve(template);
final List<String> lines = TextUtil.toLines(snippet);
RCodeLaunching.runRCodeDirect(lines, false, null);
return;
}
catch (final CoreException e) {
StatusManager.getManager().handle(new Status(IStatus.ERROR,
RConsoleUIPlugin.PLUGIN_ID, 0,
"An error occurred while submitting code snippet to R.\n" +
"Template pattern:\n" + template.getPattern(), e ));
LTKWorkbenchUIUtil.indicateStatus(e.getStatus(), event);
}
}
}