// Copyright (c) 2006 by Leif Frenzel <himself@leiffrenzel.de>
// All rights reserved.
package net.sf.eclipsefp.haskell.ui.internal.editors.cabal.ca;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import net.sf.eclipsefp.haskell.core.cabalmodel.CabalSyntax;
import net.sf.eclipsefp.haskell.ui.util.HaskellUIImages;
import net.sf.eclipsefp.haskell.ui.util.IImageNames;
import net.sf.eclipsefp.haskell.util.PlatformUtil;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextSelection;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.CompletionProposal;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.eclipse.jface.text.contentassist.IContentAssistProcessor;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.jface.text.templates.ContextTypeRegistry;
import org.eclipse.jface.text.templates.DocumentTemplateContext;
import org.eclipse.jface.text.templates.Template;
import org.eclipse.jface.text.templates.TemplateContext;
import org.eclipse.jface.text.templates.TemplateContextType;
import org.eclipse.jface.text.templates.TemplateException;
import org.eclipse.jface.text.templates.TemplateProposal;
import org.eclipse.jface.text.templates.persistence.TemplateStore;
import org.eclipse.jface.viewers.ISelection;
import org.eclipse.jface.viewers.ISelectionProvider;
import org.eclipse.swt.graphics.Image;
/** <p>the completion processor for content assist on the Cabal editor.</p>
*
* @author Leif Frenzel
*/
public class CabalCompletionProcessor implements IContentAssistProcessor {
private static final String ID_CONTEXT
= "cabalPackageDescriptionTemplates"; //$NON-NLS-1$
// interface methods of IContentAssistProcessor
///////////////////////////////////////////////
@Override
public ICompletionProposal[] computeCompletionProposals( final ITextViewer tv,
final int offset ) {
//ICompletionProposal[] result = new ICompletionProposal[ 0 ];
List<ICompletionProposal> icps=new LinkedList<>();
ISelection selection = tv.getSelectionProvider().getSelection();
if( selection instanceof ITextSelection ) {
ITextSelection tsel = ( ITextSelection )selection;
int realOffset = adjustOffset( offset, tsel );
String prefix = getPrefix( tv, realOffset );
Region region= new Region( realOffset - prefix.length(),
prefix.length() + tsel.getLength() );
icps.addAll( computeTemplateProposals( tv, region ));
for (CabalSyntax cs:CabalSyntax.values()){
if (cs.getCabalName().toLowerCase().startsWith( prefix.toLowerCase() )){
StringBuilder sb=new StringBuilder();
sb.append( cs.getCabalName() );
if (cs.isSectionHeader()){
if (CabalSyntax.SECTION_LIBRARY.equals( cs )){
sb.append( PlatformUtil.NL );
} else {
sb.append(" "); //$NON-NLS-1$
}
} else if (CabalSyntax.CabalSyntaxType.FIELD.equals( cs.getType() )){
sb.append(":"); //$NON-NLS-1$
}
String rep=sb.toString();
CompletionProposal cp=new CompletionProposal( rep, offset-prefix.length() , prefix.length(), rep.length(),null,cs.getCabalName(),null,null );
icps.add( cp );
}
}
}
return icps.toArray( new ICompletionProposal[icps.size()] );
}
@Override
public IContextInformation[] computeContextInformation( final ITextViewer viewer,
final int offset ) {
// unused
return null;
}
@Override
public char[] getCompletionProposalAutoActivationCharacters() {
// unused
return null;
}
@Override
public char[] getContextInformationAutoActivationCharacters() {
// unused
return null;
}
@Override
public IContextInformationValidator getContextInformationValidator() {
// unused
return null;
}
@Override
public String getErrorMessage() {
// unused
return null;
}
// helping methods
//////////////////
private List<ICompletionProposal> computeTemplateProposals( final ITextViewer viewer,
final IRegion region ) {
TemplateContext context = createContext( viewer, region );
if( context != null ) {
ISelectionProvider selectionProvider = viewer.getSelectionProvider();
ISelection selection = selectionProvider.getSelection();
if( selection instanceof ITextSelection ) {
ITextSelection textSel = ( ITextSelection )selection;
// name of the selection variables {line, word}_selection
context.setVariable( "selection", textSel.getText() ); //$NON-NLS-1$
Template[] templates = getTemplates( context );
List<ICompletionProposal> matches = new ArrayList<>();
for( int i= 0; i < templates.length; i++ ) {
Template template= templates[ i ];
try {
context.getContextType().validate( template.getPattern() );
Image img = HaskellUIImages.getImage( IImageNames.TEMPLATE );
matches.add( new TemplateProposal( template,
context,
region,
img ) );
} catch( final TemplateException tex ) {
// ignored
}
}
return matches;
}
}
return Collections.emptyList();
}
private Template[] getTemplates( final TemplateContext context ) {
String id = context.getContextType().getId();
TemplateStore templateStore = TemplateProvider.getTemplateStore();
Template[] templates = templateStore.getTemplates( id );
return templates;
}
private TemplateContext createContext( final ITextViewer viewer,
final IRegion region ) {
TemplateContext result = null;
ContextTypeRegistry reg = TemplateProvider.getContextTypeRegistry();
TemplateContextType contextType = reg.getContextType( ID_CONTEXT );
if( contextType != null ) {
result = new DocumentTemplateContext( contextType,
viewer.getDocument(),
region.getOffset(),
region.getLength() );
}
return result;
}
private int adjustOffset( final int offset, final ITextSelection tsel ) {
int result;
if( tsel.getOffset() != offset ) {
result = tsel.getOffset();
} else {
result = offset;
}
return result;
}
private String getPrefix( final ITextViewer viewer, final int offset ) {
String result = ""; //$NON-NLS-1$
int index = offset;
IDocument document = viewer.getDocument();
if( index <= document.getLength() ) {
try {
while( index > 0 ) {
char ch = document.getChar( index - 1 );
// - is valid in cabal field names
if (! Character.isLetterOrDigit(ch) && ch!='-') {
break;
}
index--;
}
result = document.get( index, offset - index );
} catch( BadLocationException e ) {
// ignore
}
}
return result;
}
}