Skip to content

Commit

Permalink
Resolve Task ballerina-platform#45 - Introduce Operation context
Browse files Browse the repository at this point in the history
  • Loading branch information
nadeeshaan committed Dec 12, 2017
1 parent 9a877e6 commit 427f1e4
Show file tree
Hide file tree
Showing 50 changed files with 611 additions and 424 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ public CompletableFuture<InitializeResult> initialize(InitializeParams params) {
res.getCapabilities().setCompletionProvider(new CompletionOptions());
res.getCapabilities().setTextDocumentSync(TextDocumentSyncKind.Full);
res.getCapabilities().setSignatureHelpProvider(signatureHelpOptions);
res.getCapabilities().setDefinitionProvider(true);

return CompletableFuture.supplyAsync(() -> res);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package org.ballerinalang.langserver;

import org.ballerinalang.langserver.completions.SuggestionsFilterDataModel;
import org.ballerinalang.langserver.completions.CompletionKeys;
import org.ballerinalang.langserver.completions.TreeVisitor;
import org.ballerinalang.langserver.completions.consts.CompletionItemResolver;
import org.ballerinalang.langserver.completions.resolvers.TopLevelResolver;
Expand Down Expand Up @@ -99,19 +99,20 @@ public BallerinaTextDocumentService(BallerinaLanguageServer ballerinaLanguageSer
completion(TextDocumentPositionParams position) {
return CompletableFuture.supplyAsync(() -> {
List<CompletionItem> completions;
SuggestionsFilterDataModel fDataModel = new SuggestionsFilterDataModel();
BLangPackage bLangPackage = TextDocumentServiceUtil.getBLangPackage(position, documentManager, fDataModel);
TextDocumentServiceContext completionContext = new TextDocumentServiceContext();
completionContext.put(DocumentServiceKeys.POSITION_KEY, position);
BLangPackage bLangPackage = TextDocumentServiceUtil.getBLangPackage(completionContext, documentManager);
// Visit the package to resolve the symbols
TreeVisitor treeVisitor = new TreeVisitor(position, fDataModel);
TreeVisitor treeVisitor = new TreeVisitor(completionContext);
bLangPackage.accept(treeVisitor);

BLangNode symbolEnvNode = fDataModel.getSymbolEnvNode();
BLangNode symbolEnvNode = completionContext.get(CompletionKeys.SYMBOL_ENV_NODE_KEY);
if (symbolEnvNode == null) {
completions = CompletionItemResolver.getResolverByClass(TopLevelResolver.class)
.resolveItems(fDataModel);
.resolveItems(completionContext);
} else {
completions = CompletionItemResolver.getResolverByClass(symbolEnvNode.getClass())
.resolveItems(fDataModel);
.resolveItems(completionContext);
}
return Either.forLeft(completions);
});
Expand All @@ -133,10 +134,11 @@ public CompletableFuture<SignatureHelp> signatureHelp(TextDocumentPositionParams
String uri = position.getTextDocument().getUri();
String fileContent = this.documentManager.getFileContent(Paths.get(URI.create(uri)));
String callableItemName = SignatureHelpUtil.getCallableItemName(position.getPosition(), fileContent);
SuggestionsFilterDataModel fDataModel = new SuggestionsFilterDataModel();
BLangPackage bLangPackage = TextDocumentServiceUtil.getBLangPackage(position, documentManager, fDataModel);
SignatureHelpUtil.SignatureHelpPackageContext pkgContext =
new SignatureHelpUtil.SignatureHelpPackageContext(builtinPkg, bLangPackage);
TextDocumentServiceContext signatureContext = new TextDocumentServiceContext();
signatureContext.put(DocumentServiceKeys.POSITION_KEY, position);
BLangPackage bLangPackage = TextDocumentServiceUtil.getBLangPackage(signatureContext, documentManager);
SignatureHelpUtil.BLangPackageWrapper pkgContext =
new SignatureHelpUtil.BLangPackageWrapper(builtinPkg, bLangPackage);
return SignatureHelpUtil.getFunctionSignatureHelp(callableItemName, pkgContext);
});
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* Copyright (c) 2017, 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;

import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.TokenStream;
import org.antlr.v4.runtime.Vocabulary;
import org.ballerinalang.langserver.completions.PossibleToken;
import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.wso2.ballerinalang.compiler.semantics.model.SymbolTable;
import org.wso2.ballerinalang.compiler.util.CompilerContext;

import java.util.List;

/**
* Text Document Service context keys for the completion operation context
* @since 0.95.5
*/
public class DocumentServiceKeys {
public static final LanguageServerContext.Key<TextDocumentPositionParams> POSITION_KEY
= new LanguageServerContext.Key<>();
public static final LanguageServerContext.Key<String> FILE_NAME_KEY
= new LanguageServerContext.Key<>();
public static final LanguageServerContext.Key<CompilerContext> COMPILER_CONTEXT_KEY
= new LanguageServerContext.Key<>();
public static final LanguageServerContext.Key<ParserRuleContext> PARSER_RULE_CONTEXT_KEY
= new LanguageServerContext.Key<>();
public static final LanguageServerContext.Key<List<PossibleToken>> POSSIBLE_TOKENS_KEY
= new LanguageServerContext.Key<>();
public static final LanguageServerContext.Key<TokenStream> TOKEN_STREAM_KEY
= new LanguageServerContext.Key<>();
public static final LanguageServerContext.Key<Vocabulary> VOCABULARY_KEY
= new LanguageServerContext.Key<>();
public static final LanguageServerContext.Key<Integer> TOKEN_INDEX_KEY
= new LanguageServerContext.Key<>();
public static final LanguageServerContext.Key<SymbolTable> SYMBOL_TABLE_KEY
= new LanguageServerContext.Key<>();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* Copyright (c) 2017, 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;

/**
* Ballerina Language server context.
* @since 0.95.5
*/
public interface LanguageServerContext {

/**
* Add new Context property.
* @param key Property Key
* @param value Property value
* @param <V> Key Type
*/
<V> void put(Key<V> key, V value);

/**
* Get property by Key.
* @param key Property Key
* @param <V> Key Type
* @return {@link Object} Property
*/
<V> V get(Key<V> key);

/**
* @param <K>
* @since 0.95.5
*/
class Key<K> {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2017, 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;

import java.util.HashMap;
import java.util.Map;

/**
* Language server context for text document server.
* @since 0.95.5
*/
public class TextDocumentServiceContext implements LanguageServerContext {

private Map<Key<?>, Object> props = new HashMap<>();

@Override
public <V> void put(Key<V> key, V value) {
props.put(key, value);
}

@Override
@SuppressWarnings("unchecked")
public <V> V get(Key<V> key) {
return (V) props.get(key);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@
import org.antlr.v4.runtime.DefaultErrorStrategy;
import org.ballerinalang.compiler.CompilerPhase;
import org.ballerinalang.langserver.completions.BallerinaCustomErrorStrategy;
import org.ballerinalang.langserver.completions.SuggestionsFilterDataModel;
import org.ballerinalang.langserver.workspace.WorkspaceDocumentManager;
import org.ballerinalang.langserver.workspace.repository.WorkspacePackageRepository;
import org.ballerinalang.repository.PackageRepository;
Expand Down Expand Up @@ -119,31 +118,28 @@ static CompilerContext prepareCompilerContext(PackageRepository packageRepositor

/**
* Get the BLangPackage for a given program.
* @param position Text Document Position Parameters
* @param context Text Document Service Context
* @param docManager Document manager
* @param filterDataModel Suggestions Filter Data Model
* @return {@link BLangPackage} BLang Package
*/
static BLangPackage getBLangPackage(TextDocumentPositionParams position, WorkspaceDocumentManager docManager,
SuggestionsFilterDataModel filterDataModel) {
static BLangPackage getBLangPackage(TextDocumentServiceContext context, WorkspaceDocumentManager docManager) {
TextDocumentPositionParams position = context.get(DocumentServiceKeys.POSITION_KEY);
String uri = position.getTextDocument().getUri();
String fileContent = docManager.getFileContent(Paths.get(URI.create(uri)));
Path filePath = getPath(uri);
String[] pathComponents = position.getTextDocument().getUri().split("\\" + File.separator);
String fileName = pathComponents[pathComponents.length - 1];

String pkgName = TextDocumentServiceUtil.getPackageFromContent(fileContent);
String sourceRoot = TextDocumentServiceUtil.getSourceRoot(filePath, pkgName);

PackageRepository packageRepository = new WorkspacePackageRepository(sourceRoot, docManager);
CompilerContext compilerContext = TextDocumentServiceUtil.prepareCompilerContext(packageRepository, sourceRoot);
filterDataModel.setFileName(fileName);
filterDataModel.setCompilerContext(compilerContext);

context.put(DocumentServiceKeys.FILE_NAME_KEY, fileName);
context.put(DocumentServiceKeys.COMPILER_CONTEXT_KEY, compilerContext);

List<org.ballerinalang.util.diagnostic.Diagnostic> balDiagnostics = new ArrayList<>();
CollectDiagnosticListener diagnosticListener = new CollectDiagnosticListener(balDiagnostics);
BallerinaCustomErrorStrategy customErrorStrategy = new BallerinaCustomErrorStrategy(compilerContext,
position, filterDataModel);
BallerinaCustomErrorStrategy customErrorStrategy = new BallerinaCustomErrorStrategy(context);
compilerContext.put(DiagnosticListener.class, diagnosticListener);
compilerContext.put(DefaultErrorStrategy.class, customErrorStrategy);

Expand Down
Original file line number Diff line number Diff line change
@@ -1,81 +1,85 @@
/*
* Copyright (c) 2017, 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.completions;

import org.antlr.v4.runtime.InputMismatchException;
import org.antlr.v4.runtime.NoViableAltException;
import org.antlr.v4.runtime.Parser;
import org.antlr.v4.runtime.ParserRuleContext;
import org.antlr.v4.runtime.Token;
import org.antlr.v4.runtime.misc.IntervalSet;
import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.ballerinalang.langserver.DocumentServiceKeys;
import org.ballerinalang.langserver.TextDocumentServiceContext;
import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParser;
import org.wso2.ballerinalang.compiler.parser.antlr4.BallerinaParserErrorStrategy;
import org.wso2.ballerinalang.compiler.util.CompilerContext;

import java.util.LinkedList;
import java.util.List;
import java.util.ArrayList;

/**
* Capture possible errors from source.
*/
public class BallerinaCustomErrorStrategy extends BallerinaParserErrorStrategy {

protected final TextDocumentPositionParams positionParams;

protected List<PossibleToken> possibleTokens;

private SuggestionsFilterDataModel suggestionsFilterDataModel;

public BallerinaCustomErrorStrategy(CompilerContext compilerContext, TextDocumentPositionParams positionParams,
SuggestionsFilterDataModel filterDataModel) {
super(compilerContext, null);
this.positionParams = positionParams;
possibleTokens = new LinkedList<>();
this.suggestionsFilterDataModel = filterDataModel;
private TextDocumentServiceContext context;
public BallerinaCustomErrorStrategy(TextDocumentServiceContext context) {
super(context.get(DocumentServiceKeys.COMPILER_CONTEXT_KEY), null);
this.context = context;
}
@Override
public void reportInputMismatch(Parser parser, InputMismatchException e) {
fetchPossibleTokens(parser, e.getOffendingToken(), e.getExpectedTokens());
fillContext(parser, e.getOffendingToken());
}

@Override
public void reportMissingToken(Parser parser) {
fetchPossibleTokens(parser, parser.getCurrentToken(), parser.getExpectedTokens());
fillContext(parser, parser.getCurrentToken());
}

@Override
public void reportNoViableAlternative(Parser parser, NoViableAltException e) {
fetchPossibleTokens(parser, e.getOffendingToken(), e.getExpectedTokens());
fillContext(parser, e.getOffendingToken());
}

@Override
public void reportUnwantedToken(Parser parser) {
fetchPossibleTokens(parser, parser.getCurrentToken(), parser.getExpectedTokens());
fillContext(parser, parser.getCurrentToken());
}

public List<PossibleToken> getPossibleTokens() {
return possibleTokens;
}

protected void fetchPossibleTokens(Parser parser, Token currentToken, IntervalSet expectedTokens) {
private void fillContext(Parser parser, Token currentToken) {
ParserRuleContext currentContext = parser.getContext();
// Currently disabling the check since the possible token based implementation has been skipped

if (isCursorBetweenGivenTokenAndLastNonHiddenToken(currentToken, parser)) {
this.suggestionsFilterDataModel.initParserContext(parser, currentContext, this.possibleTokens);
this.context.put(DocumentServiceKeys.PARSER_RULE_CONTEXT_KEY, currentContext);
this.context.put(DocumentServiceKeys.POSSIBLE_TOKENS_KEY, new ArrayList<>());
this.context.put(DocumentServiceKeys.TOKEN_STREAM_KEY, parser.getTokenStream());
this.context.put(DocumentServiceKeys.VOCABULARY_KEY, parser.getVocabulary());
this.context.put(DocumentServiceKeys.TOKEN_INDEX_KEY, parser.getCurrentToken().getTokenIndex());
}

}
/**
* Checks whether cursor is within the whitespace region between current token to last token.
* @param token Token to be evaluated
* @param parser Parser Instance
* @return true|false
*/
protected boolean isCursorBetweenGivenTokenAndLastNonHiddenToken(Token token, Parser parser) {
private boolean isCursorBetweenGivenTokenAndLastNonHiddenToken(Token token, Parser parser) {
this.setContextException(parser);
boolean isCursorBetween = false;
int line = positionParams.getPosition().getLine();
int character = positionParams.getPosition().getCharacter();
int line = this.context.get(DocumentServiceKeys.POSITION_KEY).getPosition().getLine();
int character = this.context.get(DocumentServiceKeys.POSITION_KEY).getPosition().getCharacter();

Token lastNonHiddenToken = null;
for (int tokenIdx = token.getTokenIndex() - 1; tokenIdx >= 0; tokenIdx--) {
Expand Down

0 comments on commit 427f1e4

Please sign in to comment.