package org.radrails.rails.internal.ui.console.commands;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.debug.core.ILaunch;
import org.eclipse.debug.core.ILaunchConfiguration;
import org.eclipse.debug.core.ILaunchConfigurationWorkingCopy;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.radrails.rails.internal.core.RailsPlugin;
import org.radrails.rails.internal.ui.console.IRailsShellConstants;
import org.radrails.rails.ui.console.RailsShellCommandProvider;
import org.rubypeople.rdt.launching.IRubyLaunchConfigurationConstants;
import org.rubypeople.rdt.launching.ITerminal;
import com.aptana.rdt.AptanaRDTPlugin;
import com.aptana.rdt.core.gems.Gem;
import com.aptana.rdt.core.gems.IGemManager;
public class GemCommandProvider extends RailsShellCommandProvider
{
private static final String COMMAND = IRailsShellConstants.GEM;
@Override
public Set<String> commandsHandled()
{
Set<String> commands = new HashSet<String>();
commands.add(COMMAND);
return commands;
}
@Override
public List<ICompletionProposal> getCompletionProposals(String prefix, List<String> tokens, int offset)
{
List<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
String token = getLastToken(prefix, tokens);
if (tokens.size() <= 1)
{
if (!tokens.contains(IRailsShellConstants.GEM))
{
proposals.add(createProposal(IRailsShellConstants.GEM, "Run the rubygems utility", offset, token));
}
}
if (tokens.isEmpty())
return proposals;
int nonSwitchTokens = getNonSwitchTokenCount(tokens);
if (nonSwitchTokens == 1 || (nonSwitchTokens == 2 && !prefix.endsWith(" "))) // they've typed "gem", or are
// typing something after "gem "
{
proposals.add(createProposal("install", "Install a gem", offset, token));
proposals.add(createProposal("uninstall", "Remove a gem", offset, token));
proposals.add(createProposal("update", "Update gem(s)", offset, token));
proposals.add(createProposal("cleanup", "Remove old versions of gems", offset, token));
proposals.add(createProposal("sources",
"Manage the sources and cache file RubyGems uses to search for gems", offset, token));
}
if (subCommandIs(tokens, "sources"))
{
Map<String, String> switches = new HashMap<String, String>();
switches.put("-a", "Add source");
switches.put("-l", "List sources");
switches.put("-r", "Remove source");
switches.put("-c", "Remove all the sources (clear cache)");
switches.put("-u", "Update source cache");
proposals.addAll(createIncompatibleSwitches(switches, tokens, offset, token));
}
else if ((subCommandIs(tokens, "update") || subCommandIs(tokens, "uninstall"))
&& ((nonSwitchTokens < 3) || (nonSwitchTokens == 3 && token.length() > 1)))
{
Set<Gem> localGems = AptanaRDTPlugin.getDefault().getGemManager().getGems();
Set<String> gemNames = new HashSet<String>();
for (Gem gem : localGems)
{
gemNames.add(gem.getName());
}
for (String gemName : gemNames)
{
proposals.add(createProposal(gemName, offset, token));
}
}
else if (!tokens.contains("-l") && !tokens.contains("-r"))
{
proposals.add(createProposal("-l", "Local operation", offset, token));
proposals.add(createProposal("-r", "Remote operations", offset, token));
}
if (!tokens.contains("-h"))
proposals.add(createProposal("-h", "Show help and quit", offset, token));
return proposals;
}
private Collection<? extends ICompletionProposal> createIncompatibleSwitches(Map<String, String> switches,
List<String> tokens, int offset, String token)
{
Collection<ICompletionProposal> proposals = new ArrayList<ICompletionProposal>();
for (Map.Entry<String, String> switchEntry : switches.entrySet())
{
if (tokens.contains(switchEntry.getKey()))
return Collections.emptyList();
ICompletionProposal proposal = createProposal(switchEntry.getKey(), switchEntry.getValue(), offset, token);
if (proposal != null)
proposals.add(proposal);
}
return proposals;
}
private boolean subCommandIs(List<String> tokens, String subCommand)
{
if (tokens == null || tokens.isEmpty())
return false;
String actualSubCommand = getActualSubCommand(tokens);
if (actualSubCommand == null)
return false;
return actualSubCommand.equals(subCommand);
}
private String getActualSubCommand(List<String> tokens)
{
boolean takeNextNonSwitchToken = false;
for (String token : tokens)
{
if (takeNextNonSwitchToken && !token.startsWith("-"))
return token;
if (token.equals(COMMAND))
{
takeNextNonSwitchToken = true;
}
}
return null;
}
private int getNonSwitchTokenCount(List<String> tokens)
{
int count = 0;
for (String string : tokens)
{
if (string.startsWith("-"))
continue;
count++;
}
return count;
}
@Override
public void run(final ITerminal shell, final String command)
{
final IGemManager gemManager = RailsPlugin.getInstance().getGemManager();
// just run the command straight up
Job job = new Job(command)
{
@Override
protected IStatus run(IProgressMonitor monitor)
{
try
{
ILaunchConfiguration config = gemManager.run(getArgs(command));
if (monitor.isCanceled())
{
return Status.CANCEL_STATUS;
}
ILaunchConfigurationWorkingCopy wc = config.getWorkingCopy();
wc.setAttribute(IRubyLaunchConfigurationConstants.ATTR_USE_TERMINAL,
IRailsShellConstants.TERMINAL_ID);
wc.setAttribute(IRubyLaunchConfigurationConstants.ATTR_TERMINAL_COMMAND, (String) null);
config = wc.doSave();
final ILaunch launch = config.launch(getRunMode(), monitor);
while (!launch.isTerminated())
{
if (monitor.isCanceled())
{
launch.terminate();
return Status.CANCEL_STATUS;
}
Thread.yield();
}
gemManager.refresh(monitor);
monitor.done();
return Status.OK_STATUS;
}
catch (CoreException e)
{
return e.getStatus();
}
}
};
job.schedule();
}
}