blob: bf010bde4cb5c98cbfdd272a4196629788f23625 [file] [log] [blame]
/*=============================================================================#
# Copyright (c) 2009, 2019 Stephan Wahlbrink and others.
#
# This program and the accompanying materials are made available under the
# terms of the Eclipse Public License 2.0 which is available at
# https://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0
# which is available at https://www.apache.org/licenses/LICENSE-2.0.
#
# SPDX-License-Identifier: EPL-2.0 OR Apache-2.0
#
# Contributors:
# Stephan Wahlbrink <sw@wahlbrink.eu> - initial API and implementation
#=============================================================================*/
package org.eclipse.statet.internal.r.ui.editors;
import org.eclipse.jface.text.AbstractDocument;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.ITextViewer;
import org.eclipse.jface.text.TextPresentation;
import org.eclipse.jface.text.contentassist.IContextInformation;
import org.eclipse.jface.text.contentassist.IContextInformationPresenter;
import org.eclipse.jface.text.contentassist.IContextInformationValidator;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.StyleRange;
import org.eclipse.statet.jcommons.text.core.input.OffsetStringParserInput;
import org.eclipse.statet.ltk.ast.core.AstInfo;
import org.eclipse.statet.ltk.ui.sourceediting.assist.AssistCompletionInformationProposalWrapper;
import org.eclipse.statet.r.core.model.ArgsDefinition;
import org.eclipse.statet.r.core.rsource.ast.FCall;
import org.eclipse.statet.r.core.rsource.ast.FCall.Args;
import org.eclipse.statet.r.core.rsource.ast.RAst;
import org.eclipse.statet.r.core.rsource.ast.RAst.FCallArgMatch;
import org.eclipse.statet.r.core.rsource.ast.RScanner;
public class RContextInformationValidator implements IContextInformationValidator, IContextInformationPresenter {
private ITextViewer fViewer;
private int fStartOffset;
private IContextInformation fInfo;
private RArgumentListContextInformation fArgInfo;
private int fCurrentParameter;
// private RScanner scanner;
private long fScannedArgsStamp;
private Args fScannedArgs;
private int fLastPresentation = -2;
public RContextInformationValidator() {
}
@Override
public boolean isContextInformationValid(final int offset) {
if (fInfo == null) {
return false;
}
final IDocument document = fViewer.getDocument();
if (offset < fStartOffset || offset > document.getLength()) {
return false;
}
if (fArgInfo != null) {
final Args args = getScannedArgs();
if (args != null) {
return (offset <= args.getEndOffset());
}
}
return (offset == fStartOffset);
}
@Override
public void install(IContextInformation info, final ITextViewer viewer, final int offset) {
if (info instanceof AssistCompletionInformationProposalWrapper) {
info= ((AssistCompletionInformationProposalWrapper) info).getContextInformation();
}
fScannedArgs = null;
fLastPresentation = -2;
if (info instanceof RArgumentListContextInformation) {
fInfo = fArgInfo = (RArgumentListContextInformation) info;
fCurrentParameter = -1;
}
else {
fInfo = info;
fArgInfo = null;
return;
}
fViewer = viewer;
fStartOffset = offset;
}
@Override
public boolean updatePresentation(final int offset, final TextPresentation presentation) {
if (fArgInfo != null) {
final ArgsDefinition args = fArgInfo.getArguments();
if (args != null && args.size() > 0) {
final int argIndex = getCurrentArgInFDef(offset);
final int[] idxs = fArgInfo.getInformationDisplayStringArgumentIdxs();
if (argIndex >= 0 && argIndex < idxs.length) {
if (argIndex == fLastPresentation) {
return false;
}
final int start = idxs[argIndex];
final int stop = (argIndex+1 < idxs.length) ? idxs[argIndex+1] : fArgInfo.getInformationDisplayString().length();
presentation.clear();
presentation.addStyleRange(new StyleRange(start, stop-start, null, null, SWT.BOLD));
fLastPresentation = argIndex;
return true;
}
}
}
if (fLastPresentation == -1) {
return false;
}
presentation.clear();
presentation.addStyleRange(new StyleRange(0, fInfo.getInformationDisplayString().length(),
null, null, SWT.NORMAL));
fLastPresentation = -1;
return true;
}
private FCall.Args getScannedArgs() {
final AbstractDocument document = (AbstractDocument) fViewer.getDocument();
final long stamp = document.getModificationStamp();
if (fScannedArgs == null || fScannedArgsStamp != stamp) {
try {
final String text= document.get(fStartOffset, Math.min(0x800, document.getLength() - fStartOffset));
final RScanner scanner= new RScanner(AstInfo.LEVEL_MODEL_DEFAULT);
fScannedArgs= scanner.scanFCallArgs(
new OffsetStringParserInput(text, fStartOffset)
.init(fStartOffset, fStartOffset + text.length()),
true );
fScannedArgsStamp = stamp;
}
catch (final Exception e) {
fScannedArgs = null;
}
}
return fScannedArgs;
}
private int getCurrentArgInFDef(final int offset) {
final int callArgIdx= getCurrentArgInFCall(offset);
if (callArgIdx >= 0) {
final FCallArgMatch match= RAst.matchArgs(getScannedArgs(), fArgInfo.getArguments());
final ArgsDefinition.Arg argDef= match.getArgDef(callArgIdx);
if (argDef != null) {
return argDef.index;
}
}
return -1;
}
private int getCurrentArgInFCall(final int offset) {
final Args args = getScannedArgs();
if (args != null) {
final int last = args.getChildCount()-1;
if (last == -1) {
return 0;
}
for (int i = 0; i < last; i++) {
if (offset <= args.getSeparatorOffset(i)) {
return i;
}
}
return last;
}
return -1;
}
}