/*******************************************************************************
* Copyright (c) 2007 Business Objects Software Limited and others.
* All rights reserved.
* This file is 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:
* Business Objects Software Limited - initial API and implementation
*******************************************************************************/
package org.openquark.cal.eclipse.ui.templates;
import java.util.ArrayList;
import java.util.List;
import org.eclipse.core.resources.IStorage;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.templates.TemplateContext;
import org.eclipse.jface.text.templates.TemplateVariable;
import org.eclipse.jface.text.templates.TemplateVariableResolver;
import org.openquark.cal.compiler.CompilerMessageLogger;
import org.openquark.cal.compiler.DataConstructor;
import org.openquark.cal.compiler.FieldName;
import org.openquark.cal.compiler.Function;
import org.openquark.cal.compiler.IdentifierInfo;
import org.openquark.cal.compiler.IdentifierOccurrence;
import org.openquark.cal.compiler.LocalFunctionIdentifier;
import org.openquark.cal.compiler.MessageLogger;
import org.openquark.cal.compiler.ModuleName;
import org.openquark.cal.compiler.ModuleTypeInfo;
import org.openquark.cal.compiler.SearchManager;
import org.openquark.cal.compiler.SourceModel;
import org.openquark.cal.compiler.IdentifierInfo.TopLevel.FunctionOrClassMethod;
import org.openquark.cal.compiler.IdentifierOccurrence.Binding.Definition;
import org.openquark.cal.eclipse.core.CALModelManager;
import org.openquark.cal.eclipse.ui.caleditor.CALEditor;
import org.openquark.cal.eclipse.ui.caleditor.PartiallySynchronizedDocument;
import org.openquark.cal.eclipse.ui.caleditor.CALEditor.AdaptedSourceViewer;
import org.openquark.cal.eclipse.ui.text.CompletionProcessor;
import org.openquark.cal.eclipse.ui.text.CompletionProcessor.ViewTemplateContext;
import org.openquark.cal.eclipse.ui.util.CoreUtility;
/**
* A variable resolver for the CAL doc variables.
*
* @author Greg McClement
*/
public class CALTemplateVariableResolver extends TemplateVariableResolver {
private final CALModelManager modelManager;
public CALTemplateVariableResolver(){
super();
modelManager = CALModelManager.getCALModelManager();
}
@Override
public void resolve(TemplateVariable variable, TemplateContext context) {
if (variable.getName().equals("context_keyword")){
// variable.setResolved(true); 3.3 feature
final String[] values = {"", "module =", "function =", "typeClass =", "typeConstructor =", "dataConstructor ="};
variable.setValues(values);
return;
}
else if (variable.getName().startsWith("scope")){
// variable.setResolved(true); 3.3 feature
final String[] values = {"", "private", "protected", "public"};
variable.setValues(values);
return;
}
if (variable.getName().equals("argument_name")){
CompletionProcessor.ViewTemplateContext dtc = (ViewTemplateContext) context;
CALEditor.AdaptedSourceViewer asv = (AdaptedSourceViewer) dtc.getViewer();
CALEditor calEditor = asv.getEditor();
final IStorage storage = calEditor.getStorage();
ModuleName moduleName;
try{
moduleName = modelManager.getModuleName(storage);
}
catch(IllegalArgumentException ex){
return; // not found
}
if (moduleName == null){
return; // not found
}
PartiallySynchronizedDocument psd = (PartiallySynchronizedDocument) dtc.getDocument();
final int startOffset = dtc.getStart();
final IDocument document = psd.getOriginalDocument();
final int offset = psd.estimateOriginalOffset(startOffset);
try {
final int firstLine = document.getLineOfOffset(offset);
final int column = CoreUtility.getColumn(firstLine, offset, document);
final String[] arguments = getArguments(moduleName, firstLine, column);
if (arguments != null){
variable.setValues(arguments);
}
} catch (BadLocationException e) {
}
return;
}
super.resolve(variable, context);
}
/**
*
* @param moduleName
* @param firstLine zero based line offset (document co-ordinates)
* @param column zero based column offset (document co-ordinates)
* @return an array containing the argument names of the scoped entity. This returns null when there are no arguments.
*/
public static String[] getArguments(final ModuleName moduleName, final int firstLine, final int column){
final CALModelManager modelManager = CALModelManager.getCALModelManager();
final SearchManager searchManager = modelManager.getSearchManager();
CompilerMessageLogger messageLogger = new MessageLogger();
List<IdentifierOccurrence<?>> identifiers = searchManager.findSymbolsAfter(moduleName, firstLine + 1, column + 1, messageLogger);
IdentifierInfo identifierInfo = null;
for(IdentifierOccurrence<?> identifier : identifiers){
if (identifier instanceof Definition){
if (identifier.getIdentifierInfo() instanceof IdentifierInfo.Local.Parameter){
// keep going
/*
* This can happen for cases like
*
* /**
* * <cursor is here>
* * @arg x the fancy arg
* *
* *\/
* foobar a = (Prelude.undefined :: (a->b->c));
*/
}
else if (identifier.getIdentifierInfo() instanceof IdentifierInfo.TypeVariable){
// keep going
/*
* This can happen for cases like
*
* /**
* * <cursor is here>
* *
* *\/
* t3 :: Prelude.Num a => a;
* t3 = t2;
*/
}
else{
// done.
identifierInfo = identifier.getIdentifierInfo();
break;
}
}
else if (identifier instanceof IdentifierOccurrence.Reference.NonQualifiable){
if (identifier.getSourceElement() instanceof SourceModel.FunctionTypeDeclaration ||
identifier.getSourceElement() instanceof SourceModel.LocalDefn.Function.TypeDeclaration
){
// type declaration.
identifierInfo = identifier.getIdentifierInfo();
break;
}
}
}
if (identifierInfo == null){
return null;
}
ModuleTypeInfo mti = modelManager.getModuleTypeInfo(moduleName);
if (identifierInfo instanceof IdentifierInfo.TopLevel.FunctionOrClassMethod){
IdentifierInfo.TopLevel.FunctionOrClassMethod fcm = (FunctionOrClassMethod) identifierInfo;
Function function = mti.getFunction(fcm.getResolvedName().getUnqualifiedName());
if (function != null){
return getValues(function);
}
}
else if (identifierInfo instanceof IdentifierInfo.TopLevel.DataCons){
IdentifierInfo.TopLevel.DataCons localName =
(IdentifierInfo.TopLevel.DataCons) identifierInfo;
DataConstructor dataConstructor = mti.getDataConstructor(localName.getResolvedName().getUnqualifiedName());
if (dataConstructor != null){
return getValues(dataConstructor);
}
}
else if (identifierInfo instanceof IdentifierInfo.Local.Function){
IdentifierInfo.Local.Parameter.Function localName =
(IdentifierInfo.Local.Parameter.Function) identifierInfo;
final LocalFunctionIdentifier localFunctionIdentifier = localName.getLocalFunctionIdentifier();
Function topLevelFunction = mti.getFunction(localFunctionIdentifier.getToplevelFunctionName().getUnqualifiedName());
if (topLevelFunction != null){
Function localFunction = topLevelFunction.getLocalFunction(localFunctionIdentifier);
if (localFunction != null){
return getValues(localFunction);
}
}
}
return null;
}
private static String[] getValues(Function function) {
int nArgs = function.getNArgumentNames();
if (nArgs > 0){
ArrayList<String> args = new ArrayList<String>(nArgs);
for(int i = 0; i < nArgs; ++i){
args.add(function.getArgumentName(i));
}
return args.toArray(new String[nArgs]);
}
return null;
}
public static String[] getValues(DataConstructor dataConstructor) {
int nArgs = dataConstructor.getNArgumentNames();
if (nArgs > 0){
ArrayList<String> args = new ArrayList<String>(nArgs);
for(int i = 0; i < nArgs; ++i){
FieldName fieldName = dataConstructor.getNthFieldName(i);
args.add(fieldName.getCalSourceForm());
}
return args.toArray(new String[nArgs]);
}
return null;
}
}