/*=============================================================================#
# Copyright (c) 2008-2016 Stephan Wahlbrink (WalWare.de) and others.
# All rights reserved. This program and the accompanying materials
# are 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:
# Stephan Wahlbrink - initial API and implementation
#=============================================================================*/
package de.walware.statet.r.ui.sourceediting;
import java.util.concurrent.TimeUnit;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jface.text.BadLocationException;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import de.walware.jcommons.collections.ImList;
import de.walware.ecommons.ltk.ui.sourceediting.assist.AssistInvocationContext;
import de.walware.ecommons.ltk.ui.sourceediting.assist.ContentAssist;
import de.walware.ecommons.ltk.ui.sourceediting.assist.ContentAssistComputerRegistry;
import de.walware.ecommons.ltk.ui.sourceediting.assist.ContentAssistProcessor;
import de.walware.ecommons.text.core.IFragmentDocument;
import de.walware.ecommons.text.core.IPartitionConstraint;
import de.walware.statet.r.console.core.util.LoadReferencesUtil;
import de.walware.statet.r.core.data.ICombinedRElement;
import de.walware.statet.r.core.source.IRDocumentConstants;
import de.walware.statet.r.core.source.RHeuristicTokenScanner;
import de.walware.statet.r.internal.ui.editors.RContextInformationValidator;
import de.walware.statet.r.ui.editors.IRSourceEditor;
public class RContentAssistProcessor extends ContentAssistProcessor {
private static IPartitionConstraint NO_R_COMMENT_CONSTRAINT = new IPartitionConstraint() {
@Override
public boolean matches(final String partitionType) {
return (partitionType != IRDocumentConstants.R_COMMENT_CONTENT_TYPE);
}
};
private class Context extends RAssistInvocationContext {
public Context(final int offset, final boolean isProposal,
final IProgressMonitor monitor) {
super((IRSourceEditor) RContentAssistProcessor.this.getEditor(),
offset, getContentType(),
isProposal,
RContentAssistProcessor.this.scanner,
monitor );
}
@Override
protected int getToolReferencesWaitTimeout() {
return (getAssistant().isCompletionProposalAutoRequest() ?
LoadReferencesUtil.MAX_AUTO_WAIT : LoadReferencesUtil.MAX_EXPLICITE_WAIT );
}
@Override
protected void toolReferencesResolved(final ImList<ICombinedRElement> resolvedElements) {
reloadPossibleCompletions(this);
}
}
private final RHeuristicTokenScanner scanner;
private int timeoutCounter;
public RContentAssistProcessor(final ContentAssist assistant, final String partition,
final ContentAssistComputerRegistry registry, final IRSourceEditor editor) {
super(assistant, partition, registry, editor);
this.scanner= RHeuristicTokenScanner.create(editor.getDocumentContentInfo());
}
@Override
protected AssistInvocationContext createCompletionProposalContext(final int offset,
final IProgressMonitor monitor) {
return new Context(offset, true, monitor);
}
@Override
protected AssistInvocationContext createContextInformationContext(final int offset,
final IProgressMonitor monitor) {
final Context context;
if (this.timeoutCounter <= 3) {
final long startTime= System.nanoTime();
context= new Context(offset, true, monitor);
if (TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime) > 50) {
this.timeoutCounter= Math.min(this.timeoutCounter + 1, 10);
}
else {
this.timeoutCounter= Math.max(this.timeoutCounter - 1, 0);
}
}
else {
context= new Context(offset, false, monitor);
}
return context;
}
@Override
protected IContextInformationValidator createContextInformationValidator() {
return new RContextInformationValidator();
}
@Override
protected boolean forceContextInformation(final AssistInvocationContext context) {
try {
int offset = context.getInvocationOffset();
if (context.getIdentifierPrefix().length() > 0
|| this.scanner == null) {
return false;
}
IDocument document = context.getSourceViewer().getDocument();
if (document instanceof IFragmentDocument) {
final IFragmentDocument inputDoc = (IFragmentDocument) document;
document = inputDoc.getMasterDocument();
offset = offset + inputDoc.getOffsetInMasterDocument();
}
if (offset < 2) {
return false;
}
this.scanner.configure(document, NO_R_COMMENT_CONSTRAINT);
final int previousOffset = this.scanner.findNonBlankBackward(offset, RHeuristicTokenScanner.UNBOUND, true);
if (previousOffset > 0) {
final char c = document.getChar(previousOffset);
if (c == '(' || c == ',') {
final String partitionType = this.scanner.getPartition(previousOffset).getType();
return (IRDocumentConstants.R_DEFAULT_CONTENT_CONSTRAINT.matches(partitionType));
}
}
}
catch (final BadLocationException e) {}
return false;
}
}