Skip to content

Commit

Permalink
Merge pull request #15874 from rasika/fix-15818
Browse files Browse the repository at this point in the history
Revamp Signature Help Feature in LS
  • Loading branch information
nadeeshaan authored Jun 25, 2019
2 parents 2237ec2 + a652148 commit 713da2e
Show file tree
Hide file tree
Showing 37 changed files with 532 additions and 340 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,7 @@ private String getRangeTextAppliedContent(Range range, String newText, String ol

@Override
public String toString() {
return "{" + "path:" + this.path + ", content:" + this.content + "}";
String cont = (this.usePrunedSource) ? prunedContent : this.content;
return "{" + "path:" + this.path + ", content:" + cont + "}";
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,12 @@
package org.ballerinalang.langserver;

import com.google.gson.JsonObject;
import org.apache.commons.lang3.tuple.Pair;
import org.ballerinalang.langserver.codelenses.CodeLensUtil;
import org.ballerinalang.langserver.codelenses.LSCodeLensesProviderFactory;
import org.ballerinalang.langserver.command.CommandUtil;
import org.ballerinalang.langserver.command.ExecuteCommandKeys;
import org.ballerinalang.langserver.common.CommonKeys;
import org.ballerinalang.langserver.common.utils.CommonUtil;
import org.ballerinalang.langserver.compiler.DocumentServiceKeys;
import org.ballerinalang.langserver.compiler.LSCompiler;
Expand All @@ -33,6 +35,7 @@
import org.ballerinalang.langserver.compiler.workspace.WorkspaceDocumentException;
import org.ballerinalang.langserver.compiler.workspace.WorkspaceDocumentManager;
import org.ballerinalang.langserver.completions.CompletionKeys;
import org.ballerinalang.langserver.completions.SymbolInfo;
import org.ballerinalang.langserver.completions.util.CompletionUtil;
import org.ballerinalang.langserver.definition.LSReferencesException;
import org.ballerinalang.langserver.diagnostic.DiagnosticsHelper;
Expand All @@ -45,6 +48,7 @@
import org.ballerinalang.langserver.signature.SignatureHelpUtil;
import org.ballerinalang.langserver.signature.SignatureKeys;
import org.ballerinalang.langserver.signature.SignatureTreeVisitor;
import org.ballerinalang.langserver.sourceprune.SourcePruner;
import org.ballerinalang.langserver.symbols.SymbolFindingVisitor;
import org.ballerinalang.langserver.util.Debouncer;
import org.ballerinalang.langserver.util.references.ReferencesUtil;
Expand Down Expand Up @@ -73,6 +77,7 @@
import org.eclipse.lsp4j.ReferenceParams;
import org.eclipse.lsp4j.RenameParams;
import org.eclipse.lsp4j.SignatureHelp;
import org.eclipse.lsp4j.SignatureInformation;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.TextDocumentClientCapabilities;
import org.eclipse.lsp4j.TextDocumentContentChangeEvent;
Expand All @@ -85,6 +90,7 @@
import org.eclipse.lsp4j.services.TextDocumentService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.ballerinalang.compiler.semantics.model.symbols.BInvokableSymbol;
import org.wso2.ballerinalang.compiler.tree.BLangCompilationUnit;
import org.wso2.ballerinalang.compiler.tree.BLangPackage;
import org.wso2.ballerinalang.compiler.util.ProjectDirConstants;
Expand Down Expand Up @@ -158,7 +164,7 @@ public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completio
context.put(LSGlobalContextKeys.LS_INDEX_KEY, this.lsIndex);

try {
CompletionUtil.getPrunedSource(context);
SourcePruner.pruneSource(context);
BLangPackage bLangPackage = lsCompiler.getBLangPackage(context, documentManager, false, null, false);
context.put(DocumentServiceKeys.CURRENT_PACKAGE_ID_KEY, bLangPackage.packageID);
context.put(DocumentServiceKeys.CURRENT_BLANG_PACKAGE_CONTEXT_KEY, bLangPackage);
Expand Down Expand Up @@ -219,21 +225,44 @@ public CompletableFuture<SignatureHelp> signatureHelp(TextDocumentPositionParams
Path sigFilePath = new LSDocument(uri).getPath();
Path compilationPath = getUntitledFilePath(sigFilePath.toString()).orElse(sigFilePath);
Optional<Lock> lock = documentManager.lockFile(compilationPath);

LSServiceOperationContext signatureContext = new LSServiceOperationContext();
signatureContext.put(DocumentServiceKeys.POSITION_KEY, position);
signatureContext.put(DocumentServiceKeys.FILE_URI_KEY, uri);
signatureContext.put(SignatureKeys.SIGNATURE_HELP_CAPABILITIES_KEY, clientCapabilities.getSignatureHelp());
signatureContext.put(CompletionKeys.DOC_MANAGER_KEY, documentManager);

try {
String fileContent = this.documentManager.getFileContent(compilationPath);
LSServiceOperationContext signatureContext = new LSServiceOperationContext();
SignatureHelpUtil.captureCallableItemInfo(position.getPosition(), fileContent, signatureContext);
signatureContext.put(DocumentServiceKeys.POSITION_KEY, position);
signatureContext.put(DocumentServiceKeys.FILE_URI_KEY, uri);
signatureContext.put(SignatureKeys.SIGNATURE_HELP_CAPABILITIES_KEY,
this.clientCapabilities.getSignatureHelp());
SignatureHelp signatureHelp;
SourcePruner.pruneSource(signatureContext);
BLangPackage bLangPackage = lsCompiler.getBLangPackage(signatureContext, documentManager, false,
LSCustomErrorStrategy.class, false);
LSCustomErrorStrategy.class,
false);
signatureContext.put(DocumentServiceKeys.CURRENT_PACKAGE_ID_KEY, bLangPackage.packageID);
signatureContext.put(DocumentServiceKeys.CURRENT_BLANG_PACKAGE_CONTEXT_KEY, bLangPackage);
SignatureTreeVisitor signatureTreeVisitor = new SignatureTreeVisitor(signatureContext);
bLangPackage.accept(signatureTreeVisitor);
signatureHelp = SignatureHelpUtil.getFunctionSignatureHelp(signatureContext);
Pair<Optional<String>, Integer> funcPathAndParamCntPair = SignatureHelpUtil.captureCallableItemInfo(
signatureContext);

List<SignatureInformation> signatures = new ArrayList<>();
funcPathAndParamCntPair.getLeft().ifPresent(funcPath -> {
// Capture visible symbols
SignatureTreeVisitor signatureTreeVisitor = new SignatureTreeVisitor(signatureContext);
bLangPackage.accept(signatureTreeVisitor);
List<SymbolInfo> visibleSymbols = signatureContext.get(CommonKeys.VISIBLE_SYMBOLS_KEY);

// Search function invocation symbol
Optional<SymbolInfo> searchSymbol = SignatureHelpUtil.getFuncSymbolInfo(funcPath, visibleSymbols);
searchSymbol.ifPresent(s -> {
if (s.getScopeEntry().symbol instanceof BInvokableSymbol) {
BInvokableSymbol symbol = (BInvokableSymbol) s.getScopeEntry().symbol;
signatures.add(SignatureHelpUtil.getSignatureInformation(symbol, signatureContext));
}
});
});

SignatureHelp signatureHelp = new SignatureHelp();
signatureHelp.setSignatures(signatures);
signatureHelp.setActiveParameter(signatureContext.get(SignatureKeys.PARAMETER_INDEX));
signatureHelp.setActiveSignature(0);
return signatureHelp;
} catch (Exception | ZipError | AssertionError e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
Expand Down Expand Up @@ -334,9 +363,12 @@ public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActio
List<CodeAction> actions = new ArrayList<>();
TextDocumentIdentifier identifier = params.getTextDocument();
String fileUri = identifier.getUri();
LSDocument document = new LSDocument(fileUri);
Path codeActionFilePath = new LSDocument(fileUri).getPath();
Path compilationPath = getUntitledFilePath(codeActionFilePath.toString()).orElse(codeActionFilePath);
Optional<Lock> lock = documentManager.lockFile(compilationPath);
try {
int line = params.getRange().getStart().getLine();
LSDocument document = new LSDocument(fileUri);
List<Diagnostic> diagnostics = params.getContext().getDiagnostics();

String topLevelNodeType = CommonUtil.topLevelNodeInLine(identifier, line, documentManager);
Expand Down Expand Up @@ -379,6 +411,8 @@ public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActio
String msg = e.getMessage();
LOGGER.error("Error while retrieving code actions" + ((msg != null) ? ": " + msg : ""), e);
}
} finally {
lock.ifPresent(Lock::unlock);
}
return actions.stream().map(
(Function<CodeAction, Either<Command, CodeAction>>) Either::forRight).collect(Collectors.toList());
Expand Down Expand Up @@ -572,7 +606,13 @@ public void didChange(DidChangeTextDocumentParams params) {
// Schedule diagnostics
LanguageClient client = this.ballerinaLanguageServer.getClient();
this.diagPushDebouncer.call(compilationPath, () -> {
diagnosticsHelper.compileAndSendDiagnostics(client, lsCompiler, changedPath, compilationPath);
// Need to lock since debouncer triggers later
Optional<Lock> nLock = documentManager.lockFile(compilationPath);
try {
diagnosticsHelper.compileAndSendDiagnostics(client, lsCompiler, changedPath, compilationPath);
} finally {
nLock.ifPresent(Lock::unlock);
}
});
} catch (WorkspaceDocumentException e) {
LOGGER.error("Error while updating change in file:" + changedPath.toString(), e);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -731,7 +731,18 @@ public static String getBTypeName(BType bType, LSContext ctx) {
* @return Extracted last Item
*/
public static <T> T getLastItem(List<T> list) {
return list.get(list.size() - 1);
return (list.size() == 0) ? null : list.get(list.size() - 1);
}

/**
* Get the last item of the Array.
*
* @param list Array to get the Last Item
* @param <T> Array content Type
* @return Extracted last Item
*/
public static <T> T getLastItem(T[] list) {
return (list.length == 0) ? null : list[list.length - 1];
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.ballerinalang.langserver.completions.util.ItemResolverConstants;
import org.ballerinalang.model.elements.MarkdownDocAttachment;
import org.ballerinalang.model.symbols.SymbolKind;
import org.ballerinalang.model.types.TypeConstants;
import org.eclipse.lsp4j.Command;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionItemKind;
import org.eclipse.lsp4j.InsertTextFormat;
Expand Down Expand Up @@ -93,6 +93,7 @@ private static void setMeta(CompletionItem item, BInvokableSymbol bSymbol) {
item.setInsertTextFormat(InsertTextFormat.Snippet);
item.setDetail(ItemResolverConstants.FUNCTION_TYPE);
item.setKind(CompletionItemKind.Function);
item.setCommand(new Command("editor.action.triggerParameterHints", "editor.action.triggerParameterHints"));
if (bSymbol != null && bSymbol.markdownDocumentation != null) {
item.setDocumentation(getDocumentation(bSymbol));
}
Expand Down Expand Up @@ -170,25 +171,22 @@ private static Pair<String, String> getFunctionSignature(BInvokableSymbol bInvok
for (int itr = 0; itr < funcArgumentsCount; itr++) {
String argument = funcArguments.get(itr);
signature.append(argument);
insertText.append("${").append(itr + 1).append(":");
insertText.append(argument.split(" ")[1]).append("}");

if (!(itr == funcArgumentsCount - 1)) {
signature.append(", ");
insertText.append(", ");
}
}
insertText.append("${1}");
}
} else {
for (int itr = 0; itr < parameterDefs.size(); itr++) {
signature.append(getParameterSignature(parameterDefs.get(itr), false));
insertText.append(getParameterInsertText(parameterDefs.get(itr), false, itr + 1));

if (itr != parameterDefs.size() - 1) {
signature.append(", ");
insertText.append(", ");
}
}
insertText.append("${1}");
}
signature.append(")");
insertText.append(")");
Expand Down Expand Up @@ -222,24 +220,6 @@ private static String getParameterSignature(BVarSymbol bVarSymbol, boolean isDef
}
}

private static String getParameterInsertText(BVarSymbol bVarSymbol, boolean isDefault, int iteration) {
if (!isDefault) {
return "${" + iteration + ":" + bVarSymbol.getName() + "}";
} else {
String defaultStringVal;
if (bVarSymbol.defaultValue == null || bVarSymbol.defaultValue.getValue() == null) {
defaultStringVal = "()";
} else {
defaultStringVal = bVarSymbol.defaultValue.getValue().toString();
if (bVarSymbol.getType() != null
&& bVarSymbol.getType().toString().equals(TypeConstants.STRING_TNAME)) {
defaultStringVal = "\"" + defaultStringVal + "\"";
}
}
return bVarSymbol.getName() + " = " + "${" + iteration + ":" + defaultStringVal + "}";
}
}

private static String getTypeName(BVarSymbol bVarSymbol) {
BType paramType = bVarSymbol.getType();
String typeName;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,40 +16,28 @@
package org.ballerinalang.langserver.completions.util;

import org.antlr.v4.runtime.CommonToken;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.TokenStream;
import org.ballerinalang.langserver.common.utils.CommonUtil;
import org.ballerinalang.langserver.compiler.DocumentServiceKeys;
import org.ballerinalang.langserver.compiler.LSContext;
import org.ballerinalang.langserver.compiler.LSServiceOperationContext;
import org.ballerinalang.langserver.compiler.workspace.WorkspaceDocumentException;
import org.ballerinalang.langserver.compiler.workspace.WorkspaceDocumentManager;
import org.ballerinalang.langserver.completions.CompletionKeys;
import org.ballerinalang.langserver.completions.LSCompletionProviderFactory;
import org.ballerinalang.langserver.completions.TreeVisitor;
import org.ballerinalang.langserver.completions.spi.LSCompletionProvider;
import org.ballerinalang.langserver.sourceprune.SourcePruner;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.InsertTextFormat;
import org.eclipse.lsp4j.Position;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser;
import org.wso2.ballerinalang.compiler.tree.BLangNode;
import org.wso2.ballerinalang.compiler.tree.BLangPackage;

import java.net.URI;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.ballerinalang.langserver.sourceprune.SourcePruner.searchTokenAtCursor;

/**
* Common utility methods for the completion operation.
*/
Expand Down Expand Up @@ -103,31 +91,6 @@ public static List<CompletionItem> getCompletionItems(LSContext ctx) {
}
return items;
}

public static void getPrunedSource(LSContext context) throws WorkspaceDocumentException, SourcePruneException {
WorkspaceDocumentManager documentManager = context.get(CompletionKeys.DOC_MANAGER_KEY);
String uri = context.get(DocumentServiceKeys.FILE_URI_KEY);
Position position = context.get(DocumentServiceKeys.POSITION_KEY).getPosition();
Path path = Paths.get(URI.create(uri));
String documentContent = documentManager.getFileContent(path);
BallerinaParser parser = CommonUtil.prepareParser(documentContent, true);
parser.removeErrorListeners();
parser.compilationUnit();
if (parser.getNumberOfSyntaxErrors() == 0) {
return;
}
TokenStream tokenStream = parser.getTokenStream();
List<Token> tokenList = new ArrayList<>(((CommonTokenStream) tokenStream).getTokens());

Optional<Token> tokenAtCursor = searchTokenAtCursor(tokenList, position.getLine(), position.getCharacter());

if (!tokenAtCursor.isPresent()) {
throw new SourcePruneException("Could not find token at cursor");
}

SourcePruner.pruneSource(tokenStream, tokenAtCursor.get().getTokenIndex(), context);
documentManager.setPrunedContent(path, tokenStream.getText());
}

/**
* Check whether the token stream corresponds to a action invocation or a function invocation.
Expand Down
Loading

0 comments on commit 713da2e

Please sign in to comment.