/*
* Copyright 2015 Nokia Solutions and Networks
* Licensed under the Apache License, Version 2.0,
* see license.txt file for details.
*/
package org.robotframework.ide.eclipse.main.plugin.tableeditor.source.assist;
import static com.google.common.collect.Lists.newArrayList;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.Position;
import org.eclipse.jface.text.Region;
import org.eclipse.jface.text.contentassist.ICompletionProposal;
import org.robotframework.ide.eclipse.main.plugin.assist.AssistProposal;
import org.robotframework.ide.eclipse.main.plugin.assist.RedNewVariableProposal;
import org.robotframework.ide.eclipse.main.plugin.assist.RedNewVariableProposals;
import org.robotframework.ide.eclipse.main.plugin.tableeditor.source.DocumentUtilities;
import org.robotframework.ide.eclipse.main.plugin.tableeditor.source.SuiteSourcePartitionScanner;
import org.robotframework.ide.eclipse.main.plugin.tableeditor.source.assist.RedCompletionProposalAdapter.DocumentationModification;
import org.robotframework.red.jface.text.link.RedEditorLinkedModeUI;
import org.robotframework.red.swt.SwtThread;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
/**
* @author Michal Anglart
*
*/
public class VariablesDefinitionsAssistProcessor extends RedContentAssistProcessor {
public VariablesDefinitionsAssistProcessor(final SuiteSourceAssistantContext assist) {
super(assist);
}
@Override
protected String getProposalsTitle() {
return "Variable definitions";
}
@Override
protected List<String> getApplicableContentTypes() {
return newArrayList(SuiteSourcePartitionScanner.VARIABLES_SECTION);
}
@Override
protected boolean shouldShowProposals(final IDocument document, final int offset, final String lineContent)
throws BadLocationException {
final IRegion lineInfo = document.getLineInformationOfOffset(offset);
if (isInApplicableContentType(document, offset)) {
// we only want to show those proposals in first cell of the line
if (offset != lineInfo.getOffset()) {
final Optional<IRegion> cellRegion = DocumentUtilities.findLiveCellRegion(document, assist.isTsvFile(),
offset);
return cellRegion.isPresent() && lineInfo.getOffset() == cellRegion.get().getOffset();
} else {
return true;
}
}
return false;
}
@Override
protected List<? extends ICompletionProposal> computeProposals(final IDocument document, final int offset,
final int cellLength, final String prefix, final boolean atTheEndOfLine) throws BadLocationException {
final String separator = assist.getSeparatorToFollow();
final List<ICompletionProposal> proposals = newArrayList();
for (final AssistProposal newVarProposal : new RedNewVariableProposals().getNewVariableProposals()) {
final List<String> args = newVarProposal.getArguments();
final String additionalContent = atTheEndOfLine
? separator + (args.isEmpty() ? "" : Joiner.on(separator).join(args) + separator) : "";
final Position toSelect = new Position(offset - prefix.length() + 2,
newVarProposal.getContent().length() - 3);
final IRegion lineInfo = document.getLineInformationOfOffset(offset);
final Collection<IRegion> regions = atTheEndOfLine
? getLinkedModeRegions(lineInfo, (RedNewVariableProposal) newVarProposal)
: new ArrayList<IRegion>();
final Collection<Runnable> operations = createOperationsToPerformAfterAccepting(viewer, regions);
final DocumentationModification modification = new DocumentationModification(additionalContent,
new Position(offset - prefix.length(), cellLength), toSelect, operations);
proposals.add(new RedCompletionProposalAdapter(newVarProposal, modification));
}
return proposals;
}
private Collection<IRegion> getLinkedModeRegions(final IRegion lineInformation,
final RedNewVariableProposal proposal) {
final int startingOffset = lineInformation.getOffset();
final int separatorLength = assist.getSeparatorToFollow().length();
int offset = startingOffset + proposal.getContent().length() + separatorLength;
final Region nameRegion = new Region(startingOffset + 2, proposal.getContent().length() - 3);
final List<IRegion> linkedModeRegions = new ArrayList<>();
linkedModeRegions.add(nameRegion);
switch (proposal.getType()) {
case SCALAR:
case LIST:
for (final String arg : proposal.getArguments()) {
linkedModeRegions.add(new Region(offset, arg.length()));
offset += arg.length() + separatorLength;
}
linkedModeRegions.add(new Region(offset, 0));
break;
case DICTIONARY:
for (final String arg : proposal.getArguments()) {
final List<String> splittedKeyVal = Splitter.on('=').limit(2).splitToList(arg);
linkedModeRegions.add(new Region(offset, splittedKeyVal.get(0).length()));
linkedModeRegions.add(
new Region(offset + splittedKeyVal.get(0).length() + 1, splittedKeyVal.get(1).length()));
offset += arg.length() + separatorLength;
}
linkedModeRegions.add(new Region(offset, 0));
break;
default:
throw new IllegalStateException("Unknown variable def value: " + proposal.getType());
}
return linkedModeRegions;
}
private Collection<Runnable> createOperationsToPerformAfterAccepting(final ITextViewer viewer,
final Collection<IRegion> regionsToLinkedEdit) {
if (regionsToLinkedEdit.isEmpty()) {
return new ArrayList<>();
}
final Runnable operation = new Runnable() {
@Override
public void run() {
SwtThread.asyncExec(new Runnable() {
@Override
public void run() {
RedEditorLinkedModeUI.enableLinkedMode(viewer, regionsToLinkedEdit);
}
});
}
};
return newArrayList(operation);
}
}