Skip to content

Commit

Permalink
Merge pull request #20748 from nadeeshaan/completion-engine-revamp
Browse files Browse the repository at this point in the history
Revamp Language Server Completions Engine
  • Loading branch information
nadeeshaan authored Jan 31, 2020
2 parents 47791e1 + d8c7efd commit ba5cefb
Show file tree
Hide file tree
Showing 69 changed files with 1,528 additions and 1,284 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/*
* Copyright (c) 2020, WSO2 Inc. (http://www.wso2.org) All Rights Reserved.
*
* WSO2 Inc. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.ballerinalang.langserver.commons.completion;

import org.eclipse.lsp4j.CompletionItem;

/**
* Wrapper interface for a Completion item.
*
* @since 1.2.0
*/
public interface LSCompletionItem {
CompletionItem getCompletionItem();
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@

import org.ballerinalang.langserver.commons.LSContext;
import org.ballerinalang.langserver.commons.completion.LSCompletionException;
import org.eclipse.lsp4j.CompletionItem;
import org.ballerinalang.langserver.commons.completion.LSCompletionItem;

import java.util.List;
import java.util.Optional;
Expand Down Expand Up @@ -48,7 +48,7 @@ enum Precedence {
* @return {@link List} List of calculated Completion Items
* @throws LSCompletionException when completion fails
*/
List<CompletionItem> getCompletions(LSContext context) throws LSCompletionException;
List<LSCompletionItem> getCompletions(LSContext context) throws LSCompletionException;

/**
* Get the attachment points where the current provider attached to.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@
import org.ballerinalang.langserver.compiler.format.FormattingVisitorEntry;
import org.ballerinalang.langserver.compiler.format.TextDocumentFormatUtil;
import org.ballerinalang.langserver.compiler.sourcegen.FormattingSourceGen;
import org.ballerinalang.langserver.completions.SymbolInfo;
import org.ballerinalang.langserver.completions.exceptions.CompletionContextNotSupportedException;
import org.ballerinalang.langserver.completions.util.CompletionUtil;
import org.ballerinalang.langserver.diagnostic.DiagnosticsHelper;
Expand Down Expand Up @@ -89,6 +88,7 @@
import org.eclipse.lsp4j.WorkspaceEdit;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.lsp4j.services.TextDocumentService;
import org.wso2.ballerinalang.compiler.semantics.model.Scope;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol;
import org.wso2.ballerinalang.compiler.tree.BLangCompilationUnit;
import org.wso2.ballerinalang.compiler.tree.BLangPackage;
Expand All @@ -113,7 +113,7 @@
import static org.ballerinalang.langserver.compiler.LSClientLogger.logError;
import static org.ballerinalang.langserver.compiler.LSClientLogger.notifyUser;
import static org.ballerinalang.langserver.compiler.LSCompilerUtil.getUntitledFilePath;
import static org.ballerinalang.langserver.signature.SignatureHelpUtil.getFuncSymbolInfo;
import static org.ballerinalang.langserver.signature.SignatureHelpUtil.getFuncScopeEntry;
import static org.ballerinalang.langserver.signature.SignatureHelpUtil.getFunctionInvocationDetails;

/**
Expand Down Expand Up @@ -240,22 +240,21 @@ public CompletableFuture<SignatureHelp> signatureHelp(TextDocumentPositionParams
SignatureTreeVisitor signatureTreeVisitor = new SignatureTreeVisitor(context);
bLangPackage.accept(signatureTreeVisitor);
int activeParamIndex = 0;
List<SymbolInfo> visibleSymbols = context.get(CommonKeys.VISIBLE_SYMBOLS_KEY);
List<Scope.ScopeEntry> visibleSymbols = context.get(CommonKeys.VISIBLE_SYMBOLS_KEY);
if (visibleSymbols == null) {
throw new Exception("Couldn't find the symbol, visible symbols are NULL!");
}
// Search function invocation symbol
List<SignatureInformation> signatures = new ArrayList<>();
List<SymbolInfo> symbols = new ArrayList<>(visibleSymbols);
List<Scope.ScopeEntry> symbols = new ArrayList<>(visibleSymbols);
Pair<Optional<String>, Integer> funcPathAndParamIndexPair = getFunctionInvocationDetails(context);
Optional<String> funcPath = funcPathAndParamIndexPair.getLeft();
activeParamIndex = funcPathAndParamIndexPair.getRight();
funcPath.ifPresent(pathStr -> {
Optional<SymbolInfo> searchSymbol = getFuncSymbolInfo(context, pathStr,
symbols);
searchSymbol.ifPresent(s -> {
if (s.getScopeEntry().symbol instanceof BInvokableSymbol) {
BInvokableSymbol symbol = (BInvokableSymbol) s.getScopeEntry().symbol;
Optional<Scope.ScopeEntry> searchSymbol = getFuncScopeEntry(context, pathStr, symbols);
searchSymbol.ifPresent(entry -> {
if (entry.symbol instanceof BInvokableSymbol) {
BInvokableSymbol symbol = (BInvokableSymbol) entry.symbol;
signatures.add(SignatureHelpUtil.getSignatureInformation(symbol, context));
}
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@ public String getLabel() {
return label;
}

public SnippetType getSnippetType() {
return snippetType;
}

/**
* Represents Snippet Types in B7a LS.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
package org.ballerinalang.langserver.common;

import org.ballerinalang.langserver.commons.LSContext;
import org.ballerinalang.langserver.completions.SymbolInfo;
import org.wso2.ballerinalang.compiler.semantics.model.Scope;

import java.util.List;

Expand Down Expand Up @@ -61,5 +61,5 @@ private CommonKeys() {

public static final String SLASH_KEYWORD_KEY = "/";

public static final LSContext.Key<List<SymbolInfo>> VISIBLE_SYMBOLS_KEY = new LSContext.Key<>();
public static final LSContext.Key<List<Scope.ScopeEntry>> VISIBLE_SYMBOLS_KEY = new LSContext.Key<>();
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,12 @@
import org.ballerinalang.jvm.util.BLangConstants;
import org.ballerinalang.langserver.common.CommonKeys;
import org.ballerinalang.langserver.commons.LSContext;
import org.ballerinalang.langserver.commons.completion.LSCompletionItem;
import org.ballerinalang.langserver.compiler.DocumentServiceKeys;
import org.ballerinalang.langserver.compiler.common.modal.BallerinaPackage;
import org.ballerinalang.langserver.completions.SymbolInfo;
import org.ballerinalang.langserver.completions.FieldCompletionItem;
import org.ballerinalang.langserver.completions.StaticCompletionItem;
import org.ballerinalang.langserver.completions.SymbolCompletionItem;
import org.ballerinalang.langserver.completions.util.ItemResolverConstants;
import org.ballerinalang.langserver.completions.util.Priority;
import org.ballerinalang.model.elements.Flag;
Expand Down Expand Up @@ -147,37 +150,6 @@ public class CommonUtil {
private CommonUtil() {
}

/**
* Get the package URI to the given package name.
*
* @param pkgName Name of the package that need the URI for
* @param pkgPath String URI of the current package
* @param currentPkgName Name of the current package
* @return String URI for the given path.
*/
public static String getPackageURI(String pkgName, String pkgPath, String currentPkgName) {
String newPackagePath;
// If current package path is not null and current package is not default package continue,
// else new package path is same as the current package path.
if (pkgPath != null && !currentPkgName.equals(".")) {
int indexOfCurrentPkgName = pkgPath.lastIndexOf(currentPkgName);
if (indexOfCurrentPkgName >= 0) {
newPackagePath = pkgPath.substring(0, indexOfCurrentPkgName);
} else {
newPackagePath = pkgPath;
}

if (pkgName.equals(".")) {
newPackagePath = Paths.get(newPackagePath).toString();
} else {
newPackagePath = Paths.get(newPackagePath, pkgName).toString();
}
} else {
newPackagePath = pkgPath;
}
return newPackagePath;
}

/**
* Calculate the user defined type position.
*
Expand Down Expand Up @@ -286,11 +258,11 @@ private static Optional<Token> getDefaultTokenToLeftOrRight(TokenStream tokenStr
* @param annotationSymbol BLang annotation to extract the completion Item
* @param ctx LS Service operation context, in this case completion context
* @param pkgAlias LS Service operation context, in this case completion context
* @return {@link CompletionItem} Completion item for the annotation
* @return {@link LSCompletionItem} Completion item for the annotation
*/
public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol,
LSContext ctx, CommonToken pkgAlias,
Map<String, String> pkgAliasMap) {
public static LSCompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol,
LSContext ctx, CommonToken pkgAlias,
Map<String, String> pkgAliasMap) {
PackageID currentPkgID = ctx.get(DocumentServiceKeys.CURRENT_PACKAGE_ID_KEY);
String currentProjectOrgName = currentPkgID == null ? "" : currentPkgID.orgName.value;

Expand All @@ -314,10 +286,10 @@ public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BA
annotationItem.setKind(CompletionItemKind.Property);
if (currentPkgID != null && currentPkgID.name.value.equals(packageID.name.value)) {
// If the annotation resides within the current package, no need to set the additional text edits
return annotationItem;
return new SymbolCompletionItem(ctx, annotationSymbol, annotationItem);
}
List<BLangImportPackage> imports = ctx.get(DocumentServiceKeys.CURRENT_DOC_IMPORTS_KEY);
Optional pkgImport = imports.stream()
Optional<BLangImportPackage> pkgImport = imports.stream()
.filter(bLangImportPackage -> {
String orgName = bLangImportPackage.orgName.value;
String importPkgName = (orgName.equals("") ? currentProjectOrgName : orgName) + "/"
Expand All @@ -335,7 +307,7 @@ public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BA
annotationItem.setAdditionalTextEdits(getAutoImportTextEdits(packageID.orgName.getValue(),
packageID.name.getValue(), ctx));
}
return annotationItem;
return new SymbolCompletionItem(ctx, annotationSymbol, annotationItem);
}

/**
Expand All @@ -347,7 +319,7 @@ public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BA
* @param pkgAliasMap Package alias map for the file
* @return {@link CompletionItem} Completion item for the annotation
*/
public static CompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol,
public static LSCompletionItem getAnnotationCompletionItem(PackageID packageID, BAnnotationSymbol annotationSymbol,
LSContext ctx, Map<String, String> pkgAliasMap) {
return getAnnotationCompletionItem(packageID, annotationSymbol, ctx, null, pkgAliasMap);
}
Expand Down Expand Up @@ -535,11 +507,12 @@ public static boolean listContainsPackage(String pkg, List<BallerinaPackage> pkg
/**
* Get completion items list for struct fields.
*
* @param context Language server operation context
* @param fields List of struct fields
* @return {@link List} List of completion items for the struct fields
*/
public static List<CompletionItem> getRecordFieldCompletionItems(List<BField> fields) {
List<CompletionItem> completionItems = new ArrayList<>();
public static List<LSCompletionItem> getRecordFieldCompletionItems(LSContext context, List<BField> fields) {
List<LSCompletionItem> completionItems = new ArrayList<>();
fields.forEach(field -> {
String insertText = getRecordFieldCompletionInsertText(field, 0);
CompletionItem fieldItem = new CompletionItem();
Expand All @@ -549,7 +522,7 @@ public static List<CompletionItem> getRecordFieldCompletionItems(List<BField> fi
fieldItem.setDetail(ItemResolverConstants.FIELD_TYPE);
fieldItem.setKind(CompletionItemKind.Field);
fieldItem.setSortText(Priority.PRIORITY120.toString());
completionItems.add(fieldItem);
completionItems.add(new FieldCompletionItem(context, field, fieldItem));
});

return completionItems;
Expand All @@ -558,10 +531,11 @@ public static List<CompletionItem> getRecordFieldCompletionItems(List<BField> fi
/**
* Get the completion item to fill all the struct fields.
*
* @param context Language Server Operation Context
* @param fields List of struct fields
* @return {@link CompletionItem} Completion Item to fill all the options
* @return {@link LSCompletionItem} Completion Item to fill all the options
*/
public static CompletionItem getFillAllStructFieldsItem(List<BField> fields) {
public static LSCompletionItem getFillAllStructFieldsItem(LSContext context, List<BField> fields) {
List<String> fieldEntries = new ArrayList<>();

for (BField bStructField : fields) {
Expand All @@ -580,7 +554,7 @@ public static CompletionItem getFillAllStructFieldsItem(List<BField> fields) {
completionItem.setKind(CompletionItemKind.Property);
completionItem.setSortText(Priority.PRIORITY110.toString());

return completionItem;
return new StaticCompletionItem(context, completionItem);
}

/**
Expand Down Expand Up @@ -613,6 +587,18 @@ public static String getBTypeName(BType bType, LSContext ctx, boolean doSimplify
return getShallowBTypeName(bType, ctx);
}

/**
* Get the Symbol Name.
*
* @param bSymbol BSymbol to evaluate
* @return captured symbol name
*/
public static String getSymbolName(BSymbol bSymbol) {
String nameValue = bSymbol.name.getValue();
String[] split = nameValue.split("\\.");
return split[split.length - 1];
}

private static String getShallowBTypeName(BType bType, LSContext ctx) {
if (bType.tsymbol == null) {
return bType.toString();
Expand Down Expand Up @@ -983,10 +969,10 @@ public static Pair<String, String> getFunctionInvocationSignature(BInvokableSymb
* @param context Language Server operation conext
* @return {@link List} filtered visible symbols
*/
public static List<SymbolInfo> getWorkerSymbols(LSContext context) {
List<SymbolInfo> visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY));
return visibleSymbols.stream().filter(symbolInfo -> {
BType bType = symbolInfo.getScopeEntry().symbol.type;
public static List<Scope.ScopeEntry> getWorkerSymbols(LSContext context) {
List<Scope.ScopeEntry> visibleSymbols = new ArrayList<>(context.get(CommonKeys.VISIBLE_SYMBOLS_KEY));
return visibleSymbols.stream().filter(scopeEntry -> {
BType bType = scopeEntry.symbol.type;
return bType instanceof BFutureType && ((BFutureType) bType).workerDerivative;
}).collect(Collectors.toList());
}
Expand Down Expand Up @@ -1059,10 +1045,8 @@ public static List<BLangImportPackage> getCurrentModuleImports(LSContext ctx) {
*
* @return {@link Predicate} Predicate for the check
*/
public static Predicate<SymbolInfo> invalidSymbolsPredicate() {
return symbolInfo -> !symbolInfo.isCustomOperation()
&& symbolInfo.getScopeEntry() != null
&& isInvalidSymbol(symbolInfo.getScopeEntry().symbol);
public static Predicate<Scope.ScopeEntry> invalidSymbolsPredicate() {
return scopeEntry -> scopeEntry != null && isInvalidSymbol(scopeEntry.symbol);
}

/**
Expand Down
Loading

0 comments on commit ba5cefb

Please sign in to comment.