Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add codeLens feature for Language Server #13297

Merged
merged 20 commits into from
Jan 24, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ const Documentation = ({ docDetails }) => {
}[kind];

return (
<div className='documentation-block'>
<div className='documentation-block' id={title}>
<div className='title'>
{ icon && (<i className={`fw fw-fw icon ${icon}`}></i>) }{title}
{ kind === 'Function' && '()' }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/
package org.ballerinalang.langserver.compiler;

import org.antlr.v4.runtime.DefaultErrorStrategy;
import org.ballerinalang.compiler.CompilerPhase;
import org.ballerinalang.langserver.compiler.common.LSDocument;
import org.ballerinalang.langserver.compiler.common.modal.BallerinaFile;
Expand Down Expand Up @@ -124,12 +123,7 @@ public BallerinaFile compileFile(Path filePath, CompilerPhase phase) {
CompilerContext context = prepareCompilerContext(packageID, packageRepository, sourceDocument,
true, documentManager, phase);

// In order to capture the syntactic errors, need to go through the default error strategy
context.put(DefaultErrorStrategy.class, null);
BLangPackage bLangPackage = null;
if (context.get(DiagnosticListener.class) instanceof CollectDiagnosticListener) {
((CollectDiagnosticListener) context.get(DiagnosticListener.class)).clearAll();
}
boolean isProjectDir = (LSCompilerUtil.isBallerinaProject(sourceRoot, filePath.toUri().toString()));
try {
BLangDiagnosticLog.getInstance(context).errorCount = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import org.ballerinalang.repository.PackageRepository;
import org.ballerinalang.toml.model.Manifest;
import org.ballerinalang.toml.parser.ManifestProcessor;
import org.ballerinalang.util.diagnostic.DiagnosticListener;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.wso2.ballerinalang.compiler.Compiler;
Expand Down Expand Up @@ -143,6 +144,10 @@ public static CompilerContext prepareCompilerContext(PackageID packageID, Packag
// In order to capture the syntactic errors, need to go through the default error strategy
context.put(DefaultErrorStrategy.class, null);

if (context.get(DiagnosticListener.class) instanceof CollectDiagnosticListener) {
((CollectDiagnosticListener) context.get(DiagnosticListener.class)).clearAll();
}

Path sourceRootPath = document.getSourceRootPath();
if (isBallerinaProject(document.getSourceRoot(), document.getURIString())) {
LangServerFSProjectDirectory projectDirectory =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
import com.google.gson.Gson;
import org.ballerinalang.langserver.client.ExtendedLanguageClient;
import org.ballerinalang.langserver.client.ExtendedLanguageClientAware;
import org.ballerinalang.langserver.codelenses.LSCodeLensesProviderFactory;
import org.ballerinalang.langserver.command.LSCommandExecutorProvider;
import org.ballerinalang.langserver.common.utils.CommonUtil;
import org.ballerinalang.langserver.compiler.workspace.WorkspaceDocumentManager;
Expand All @@ -37,6 +38,7 @@
import org.ballerinalang.langserver.extensions.ballerina.traces.Listener;
import org.ballerinalang.langserver.extensions.ballerina.traces.ProviderOptions;
import org.ballerinalang.langserver.index.LSIndexImpl;
import org.eclipse.lsp4j.CodeLensOptions;
import org.eclipse.lsp4j.CompletionOptions;
import org.eclipse.lsp4j.ExecuteCommandOptions;
import org.eclipse.lsp4j.InitializeParams;
Expand Down Expand Up @@ -96,6 +98,7 @@ public BallerinaLanguageServer(WorkspaceDocumentManager documentManager) {
this.ballerinaFragmentService = new BallerinaFragmentServiceImpl(lsGlobalContext);

LSAnnotationCache.initiate();
LSCodeLensesProviderFactory.getInstance().initiate();
}

public ExtendedLanguageClient getClient() {
Expand Down Expand Up @@ -123,6 +126,7 @@ public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
res.getCapabilities().setRenameProvider(true);
res.getCapabilities().setWorkspaceSymbolProvider(true);
res.getCapabilities().setImplementationProvider(true);
res.getCapabilities().setCodeLensProvider(new CodeLensOptions());

TextDocumentClientCapabilities textDocCapabilities = params.getCapabilities().getTextDocument();
((BallerinaTextDocumentService) this.textService).setClientCapabilities(textDocCapabilities);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,15 @@
package org.ballerinalang.langserver;

import com.google.gson.JsonObject;
import org.ballerinalang.langserver.codelenses.CodeLensesProviderKeys;
import org.ballerinalang.langserver.codelenses.LSCodeLensesProvider;
import org.ballerinalang.langserver.codelenses.LSCodeLensesProviderException;
import org.ballerinalang.langserver.codelenses.LSCodeLensesProviderFactory;
import org.ballerinalang.langserver.command.CommandUtil;
import org.ballerinalang.langserver.common.constants.NodeContextKeys;
import org.ballerinalang.langserver.common.position.PositionTreeVisitor;
import org.ballerinalang.langserver.common.utils.CommonUtil;
import org.ballerinalang.langserver.compiler.CollectDiagnosticListener;
import org.ballerinalang.langserver.compiler.DocumentServiceKeys;
import org.ballerinalang.langserver.compiler.LSCompiler;
import org.ballerinalang.langserver.compiler.LSCompilerException;
Expand Down Expand Up @@ -52,6 +57,7 @@
import org.ballerinalang.langserver.symbols.SymbolFindingVisitor;
import org.ballerinalang.langserver.util.Debouncer;
import org.ballerinalang.model.elements.PackageID;
import org.ballerinalang.util.diagnostic.DiagnosticListener;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeActionParams;
import org.eclipse.lsp4j.CodeLens;
Expand Down Expand Up @@ -116,7 +122,7 @@
* Text document service implementation for ballerina.
*/
class BallerinaTextDocumentService implements TextDocumentService {
private static final Logger logger = LoggerFactory.getLogger(BallerinaTextDocumentService.class);
private static final Logger LOGGER = LoggerFactory.getLogger(BallerinaTextDocumentService.class);

// indicates the frequency to send diagnostics to server upon document did change
private static final int DIAG_PUSH_DEBOUNCE_DELAY = 500;
Expand Down Expand Up @@ -175,7 +181,7 @@ public CompletableFuture<Either<List<CompletionItem>, CompletionList>> completio
} catch (Exception | AssertionError e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while resolving symbols" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while resolving symbols" + ((msg != null) ? ": " + msg : ""), e);
}
} finally {
lock.ifPresent(Lock::unlock);
Expand Down Expand Up @@ -209,7 +215,7 @@ public CompletableFuture<Hover> hover(TextDocumentPositionParams position) {
} catch (Exception | AssertionError e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while retrieving hover content" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while retrieving hover content" + ((msg != null) ? ": " + msg : ""), e);
}
hover = new Hover();
List<Either<String, MarkedString>> contents = new ArrayList<>();
Expand Down Expand Up @@ -250,7 +256,7 @@ public CompletableFuture<SignatureHelp> signatureHelp(TextDocumentPositionParams
} catch (Exception | ZipError | AssertionError e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while retrieving signature help" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while retrieving signature help" + ((msg != null) ? ": " + msg : ""), e);
}
return new SignatureHelp();
} finally {
Expand Down Expand Up @@ -281,7 +287,7 @@ public CompletableFuture<List<? extends Location>> definition(TextDocumentPositi
} catch (Exception e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while retrieving definition" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while retrieving definition" + ((msg != null) ? ": " + msg : ""), e);
}
contents = new ArrayList<>();
} finally {
Expand Down Expand Up @@ -338,7 +344,7 @@ public CompletableFuture<List<? extends Location>> references(ReferenceParams pa
} catch (Exception e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while retrieving references" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while retrieving references" + ((msg != null) ? ": " + msg : ""), e);
}
return contents;
} finally {
Expand Down Expand Up @@ -383,7 +389,7 @@ public CompletableFuture<List<? extends DocumentHighlight>> documentHighlight(
} catch (Exception e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while retrieving document symbols" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while retrieving document symbols" + ((msg != null) ? ": " + msg : ""), e);
}
return symbols;
} finally {
Expand Down Expand Up @@ -439,7 +445,7 @@ public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActio
} catch (Exception e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while retrieving code actions" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while retrieving code actions" + ((msg != null) ? ": " + msg : ""), e);
}
return commands;
}
Expand All @@ -448,7 +454,65 @@ public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActio

@Override
public CompletableFuture<List<? extends CodeLens>> codeLens(CodeLensParams params) {
return null;
return CompletableFuture.supplyAsync(() -> {
List<CodeLens> lenses = new ArrayList<>();

if (!LSCodeLensesProviderFactory.getInstance().isEnabled()) {
// Disabled ballerina codeLens feature
clientCapabilities.setCodeLens(null);
// Skip code lenses if codeLens disabled
return lenses;
}

String fileUri = params.getTextDocument().getUri();
Path docSymbolFilePath = new LSDocument(fileUri).getPath();
Path compilationPath = getUntitledFilePath(docSymbolFilePath.toString()).orElse(docSymbolFilePath);
Optional<Lock> lock = documentManager.lockFile(compilationPath);
try {
LSServiceOperationContext codeLensContext = new LSServiceOperationContext();
codeLensContext.put(DocumentServiceKeys.FILE_URI_KEY, fileUri);
BLangPackage bLangPackage = lsCompiler.getBLangPackage(codeLensContext, documentManager, false,
LSCustomErrorStrategy.class, false);
Optional<BLangCompilationUnit> documentCUnit = bLangPackage.getCompilationUnits().stream()
.filter(cUnit -> (fileUri.endsWith(cUnit.getName())))
.findFirst();

CompilerContext compilerContext = codeLensContext.get(DocumentServiceKeys.COMPILER_CONTEXT_KEY);
final List<org.ballerinalang.util.diagnostic.Diagnostic> diagnostics = new ArrayList<>();
if (compilerContext.get(DiagnosticListener.class) instanceof CollectDiagnosticListener) {
CollectDiagnosticListener listener =
(CollectDiagnosticListener) compilerContext.get(DiagnosticListener.class);
diagnostics.addAll(listener.getDiagnostics());
listener.clearAll();
}

codeLensContext.put(CodeLensesProviderKeys.BLANG_PACKAGE_KEY, bLangPackage);
codeLensContext.put(CodeLensesProviderKeys.FILE_URI_KEY, fileUri);
codeLensContext.put(CodeLensesProviderKeys.DIAGNOSTIC_KEY, diagnostics);

documentCUnit.ifPresent(cUnit -> {
codeLensContext.put(CodeLensesProviderKeys.COMPILATION_UNIT_KEY, cUnit);

List<LSCodeLensesProvider> providers = LSCodeLensesProviderFactory.getInstance().getProviders();
for (LSCodeLensesProvider provider : providers) {
try {
lenses.addAll(provider.getLenses(codeLensContext));
} catch (LSCodeLensesProviderException e) {
LOGGER.error("Error while retrieving lenses from: " + provider.getName());
}
}
});
return lenses;
} catch (Exception e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
LOGGER.error("Error while retrieving code lenses " + ((msg != null) ? ": " + msg : ""), e);
}
return lenses;
} finally {
lock.ifPresent(Lock::unlock);
}
});
}

@Override
Expand Down Expand Up @@ -498,7 +562,7 @@ public CompletableFuture<List<? extends TextEdit>> formatting(DocumentFormatting
} catch (Exception e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while formatting" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while formatting" + ((msg != null) ? ": " + msg : ""), e);
}
return Collections.singletonList(textEdit);
} finally {
Expand Down Expand Up @@ -573,7 +637,7 @@ public CompletableFuture<WorkspaceEdit> rename(RenameParams params) {
} catch (Exception e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while renaming" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while renaming" + ((msg != null) ? ": " + msg : ""), e);
}
return workspaceEdit;
} finally {
Expand Down Expand Up @@ -604,7 +668,7 @@ public CompletableFuture<List<? extends Location>> implementation(TextDocumentPo
} catch (LSCompilerException e) {
if (CommonUtil.LS_DEBUG_ENABLED) {
String msg = e.getMessage();
logger.error("Error while go to implementation" + ((msg != null) ? ": " + msg : ""), e);
LOGGER.error("Error while go to implementation" + ((msg != null) ? ": " + msg : ""), e);
}
} finally {
lock.ifPresent(Lock::unlock);
Expand All @@ -626,7 +690,7 @@ public void didOpen(DidOpenTextDocumentParams params) {
LanguageClient client = this.ballerinaLanguageServer.getClient();
diagnosticsHelper.compileAndSendDiagnostics(client, lsCompiler, openedPath, compilationPath);
} catch (WorkspaceDocumentException e) {
logger.error("Error while opening file:" + openedPath.toString());
LOGGER.error("Error while opening file:" + openedPath.toString());
} finally {
lock.ifPresent(Lock::unlock);
}
Expand All @@ -647,7 +711,7 @@ public void didChange(DidChangeTextDocumentParams params) {
diagnosticsHelper.compileAndSendDiagnostics(client, lsCompiler, changedPath, compilationPath);
});
} catch (WorkspaceDocumentException e) {
logger.error("Error while updating change in file:" + changedPath.toString(), e);
LOGGER.error("Error while updating change in file:" + changedPath.toString(), e);
} finally {
lock.ifPresent(Lock::unlock);
}
Expand All @@ -666,7 +730,7 @@ public void didClose(DidCloseTextDocumentParams params) {
Path compilationPath = getUntitledFilePath(closedPath.toString()).orElse(closedPath);
this.documentManager.closeFile(compilationPath);
} catch (WorkspaceDocumentException e) {
logger.error("Error occurred while closing file:" + closedPath.toString(), e);
LOGGER.error("Error occurred while closing file:" + closedPath.toString(), e);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
*/
package org.ballerinalang.langserver;

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import org.ballerinalang.langserver.client.config.BallerinaClientConfig;
import org.ballerinalang.langserver.client.config.BallerinaClientConfigHolder;
import org.ballerinalang.langserver.command.ExecuteCommandKeys;
import org.ballerinalang.langserver.command.LSCommandExecutor;
import org.ballerinalang.langserver.command.LSCommandExecutorProvider;
Expand Down Expand Up @@ -58,6 +62,8 @@ public class BallerinaWorkspaceService implements WorkspaceService {
private DiagnosticsHelper diagnosticsHelper;
private LSCompiler lsCompiler;
private Map<String, Boolean> experimentalClientCapabilities;
private static final Gson GSON = new Gson();
private BallerinaClientConfigHolder configHolder = BallerinaClientConfigHolder.getInstance();

BallerinaWorkspaceService(LSGlobalContext globalContext) {
this.ballerinaLanguageServer = globalContext.get(LSGlobalContextKeys.LANGUAGE_SERVER_KEY);
Expand Down Expand Up @@ -109,7 +115,10 @@ private String generateHash(BLangCompilationUnit compUnit, String basePath) {

@Override
public void didChangeConfiguration(DidChangeConfigurationParams params) {
// Operation not supported
if (!(params.getSettings() instanceof JsonObject)) {
return;
}
configHolder.updateConfig(GSON.fromJson((JsonObject) params.getSettings(), BallerinaClientConfig.class));
}

@Override
Expand Down
Loading