package org.radrails.rails.internal.ui.console;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.StringTokenizer;
import org.eclipse.core.resources.IProject;
import org.eclipse.debug.core.ILaunchManager;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
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.swt.graphics.Image;
import org.radrails.rails.core.RailsLog;
import org.radrails.rails.ui.console.RailsShellCommandProvider;
import org.rubypeople.rdt.internal.ui.RubyPlugin;
import org.rubypeople.rdt.internal.ui.RubyPluginImages;
import org.rubypeople.rdt.ui.viewsupport.ImageDescriptorRegistry;
import com.aptana.rdt.rake.IRakeHelper;
import com.aptana.rdt.rake.RakePlugin;
public class RailsShellContentAssistProcessor implements IContentAssistProcessor
{
private IProject fProject;
public String getErrorMessage()
{
return null;
}
public IContextInformationValidator getContextInformationValidator()
{
return null;
}
public char[] getContextInformationAutoActivationCharacters()
{
return null;
}
public char[] getCompletionProposalAutoActivationCharacters()
{
return new char[] { ' ' };
}
public IContextInformation[] computeContextInformation(ITextViewer viewer, int offset)
{
return null;
}
public ICompletionProposal[] computeCompletionProposals(String prefix, int offset)
{
List<String> tokens = new ArrayList<String>();
StringTokenizer tokenizer = new StringTokenizer(prefix);
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
String token = null;
try
{
token = tokenizer.nextToken();
if (token.trim().startsWith(IRailsShellConstants.PROMPT))
{
token = token.trim().substring(IRailsShellConstants.PROMPT.length());
}
if (token.trim().length() == 0)
token = tokenizer.nextToken();
}
catch (NoSuchElementException e)
{
// ignore
token = "";
}
// Collect the command tokens
while (token.trim().length() > 0)
{
tokens.add(token);
token = nextToken(tokenizer);
}
if (tokens.isEmpty())
{
proposals.add(createProposal("debug", "Run the trailing command under the debugger", offset, ""));
proposals.add(createProposal("profile", "Run the trailing command under the profiler", offset, ""));
}
else
{
if (tokens.get(0).equals("debug") || tokens.get(0).equals("profile") || tokens.get(0).equals("ruby"))
{
tokens.remove(0);
}
}
String command = "";
if (!tokens.isEmpty())
command = tokens.get(0);
List<RailsShellCommandProvider> providers = getCommandProviders();
for (RailsShellCommandProvider railsShellCommandProvider : providers)
{
try
{
if (railsShellCommandProvider.projectNeedsToBeSelected() && fProject == null)
continue;
if (!commandMatches(railsShellCommandProvider, command))
continue;
proposals.addAll(railsShellCommandProvider.getCompletionProposals(prefix, tokens, offset));
}
catch (Exception e)
{
RailsLog.log(e);
}
}
// Remove null proposals
Iterator<ICompletionProposal> iter = proposals.iterator();
while (iter.hasNext())
{
ICompletionProposal prop = iter.next();
if (prop == null)
iter.remove();
}
// Sort proposals by key!
Collections.sort(proposals, new Comparator<ICompletionProposal>()
{
public int compare(ICompletionProposal o1, ICompletionProposal o2)
{
return o1.getDisplayString().compareTo(o2.getDisplayString());
}
});
return proposals.toArray(new ICompletionProposal[proposals.size()]);
}
public ICompletionProposal[] computeCompletionProposals(ITextViewer viewer, int offset)
{
String prefix = getLinePrefix(viewer, offset);
// If it's the first token and the user typed a space, replace the space too!
if (prefix.trim().length() == 0)
{ // just whitespace
offset -= prefix.length();
}
return computeCompletionProposals(prefix, offset);
}
private boolean commandMatches(RailsShellCommandProvider railsShellCommandProvider, String command)
{
for (String handledCommand : railsShellCommandProvider.commandsHandled())
{
if (handledCommand.startsWith(command))
return true;
}
return false;
}
private List<RailsShellCommandProvider> getCommandProviders()
{
// Run mode doesn't matter here for completions
return RailsShell.getCommandProviders(fProject, ILaunchManager.RUN_MODE);
}
protected IRakeHelper getRakeTasksHelper()
{
return RakePlugin.getDefault().getRakeHelper();
}
private String nextToken(StringTokenizer tokenizer)
{
try
{
return tokenizer.nextToken();
}
catch (NoSuchElementException e)
{
return "";
}
}
private String getLinePrefix(ITextViewer viewer, int offset)
{
String prefix = null;
try
{
IDocument doc = viewer.getDocument();
prefix = doc.get(0, offset);
int index = prefix.lastIndexOf("\n");
if (index > -1)
{
prefix = prefix.substring(index + 1);
}
}
catch (BadLocationException e)
{
// ignore
}
return prefix;
}
private ICompletionProposal createProposal(String string, String description, int offset, String token)
{
if (token != null && !string.startsWith(token))
return null;
if (token.equals(string))
return null;
ImageDescriptorRegistry registry = RubyPlugin.getImageDescriptorRegistry();
Image image = registry.get(RubyPluginImages.DESC_MISC_PUBLIC);
String display = string;
if (description != null && description.trim().length() > 0)
{
display += " - " + description;
}
return new RailsShellCompletionProposal(string, offset - token.length(), token.length(), string.length(),
image, display, null, description);
}
public void setProject(IProject project)
{
this.fProject = project;
}
}