/******************************************************************************* * Copyright (c) 2014 Bruno Medeiros and other Contributors. * 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: * Bruno Medeiros - initial API and implementation *******************************************************************************/ package dtool.engine.operations; import static melnorme.utilbox.core.Assert.AssertNamespace.assertNotNull; import static melnorme.utilbox.core.Assert.AssertNamespace.assertTrue; import dtool.ast.definitions.ICallableElement; import dtool.ast.definitions.IFunctionParameter; import dtool.parser.structure.DeeLabelInfoProvider; import melnorme.lang.tooling.CompletionProposalKind; import melnorme.lang.tooling.ElementAttributes; import melnorme.lang.tooling.ElementLabelInfo; import melnorme.lang.tooling.ToolCompletionProposal; import melnorme.lang.tooling.ast.SourceRange; import melnorme.lang.tooling.completion.CompletionLocationInfo; import melnorme.lang.tooling.engine.OverloadedNamedElement; import melnorme.lang.tooling.symbols.INamedElement; import melnorme.lang.tooling.toolchain.ops.OperationSoftFailure; import melnorme.utilbox.collections.ArrayList2; import melnorme.utilbox.collections.Collection2; public class DeeSymbolCompletionResult { public final ECompletionResultStatus resultCode; public final CompletionLocationInfo locationInfo; public final int replaceLength; public final Collection2<INamedElement> results; public DeeSymbolCompletionResult(ECompletionResultStatus resultCode) { assertTrue(resultCode != ECompletionResultStatus.RESULT_OK); this.resultCode = resultCode; this.replaceLength = 0; this.results = null; this.locationInfo = null; } public DeeSymbolCompletionResult(CompletionLocationInfo locationInfo, Collection2<INamedElement> results) { this.resultCode = ECompletionResultStatus.RESULT_OK; this.locationInfo = assertNotNull(locationInfo); this.replaceLength = locationInfo.rplLen; this.results = results; } public ECompletionResultStatus getResultCode() { return resultCode; } public boolean isFailure() { return resultCode != ECompletionResultStatus.RESULT_OK; } public int getReplaceLength() { return replaceLength; } public Collection2<INamedElement> getElementResults() { return results; } public ArrayList2<ToolCompletionProposal> convertToCompletionResult() throws OperationSoftFailure { if(isFailure()) { throw new OperationSoftFailure(resultCode.getMessage()); } ArrayList2<ToolCompletionProposal> proposals = new ArrayList2<>(); for (INamedElement result : getElementResults()) { if(result instanceof OverloadedNamedElement) { OverloadedNamedElement overload = (OverloadedNamedElement) result; for (INamedElement namedElement : overload.getOverloadedElements()) { proposals.add(createProposal(locationInfo, getReplaceLength(), namedElement)); } } else { proposals.add(createProposal(locationInfo, getReplaceLength(), result)); } } return proposals; } public static ToolCompletionProposal createProposal(CompletionLocationInfo invocationInfo, int replaceLength, INamedElement namedElem) { int rplOffset = invocationInfo.offset - invocationInfo.namePrefixLen; replaceLength = replaceLength + invocationInfo.namePrefixLen; String rplName = namedElem.getName(); String rplString = rplName; String moduleName = namedElem.getModuleFullName(); String baseLabel = DeeNamedElementLabelProvider.getLabelForContentAssistPopup(namedElem); String fullReplaceString = rplString; ArrayList2<SourceRange> subElements = null; if(namedElem instanceof ICallableElement) { ICallableElement callableElement = (ICallableElement) namedElem; subElements = new ArrayList2<SourceRange>(); fullReplaceString = getFullReplaceString(rplString, callableElement, subElements); } ElementLabelInfo elementLabelInfo = new DeeLabelInfoProvider().getLabelInfo(namedElem); CompletionProposalKind kind = elementLabelInfo.proposalKind; ElementAttributes attributes = elementLabelInfo.elementAttribs; return new ToolCompletionProposal(rplOffset, replaceLength, rplString, baseLabel, kind, attributes, null, moduleName, null, fullReplaceString, subElements, namedElem); } public static String getFullReplaceString(String rplString, ICallableElement callableElement, ArrayList2<SourceRange> subElements) { StringBuilder sb = new StringBuilder(); sb.append(rplString); sb.append("("); boolean first = true; for (IFunctionParameter param : callableElement.getParameters()) { if(!first) { sb.append(", "); } String paramName = getParamNameSuggestion(param); subElements.add(new SourceRange(sb.length(), paramName.length())); sb.append(paramName); first = false; } sb.append(")"); return sb.toString(); } protected static String getParamNameSuggestion(IFunctionParameter param) { if(param instanceof INamedElement) { INamedElement namedParam = (INamedElement) param; return namedParam.getName(); } else { return "__"; } } public enum ECompletionResultStatus { RESULT_OK("ok", null), INVALID_TOKEN_LOCATION("invalid_token", "Invalid location (inside unmodifiable token)"), INVALID_TOKEN_LOCATION_FLOAT("after_float_point", "Invalid location (after float decimal point)"), ; protected final String id; protected final String message; private ECompletionResultStatus(String id, String message) { this.id = assertNotNull(id); this.message = message; } public String getId() { return id; } public String getMessage() { return message; } public static ECompletionResultStatus fromId(String statusId) { for (ECompletionResultStatus status : values()) { if(status.id.equals(statusId)) { return status; } } return null; } } }