Skip to content

Commit

Permalink
Add completion provider
Browse files Browse the repository at this point in the history
  • Loading branch information
malinthar committed Jul 17, 2023
1 parent 671f309 commit 1cb5ac9
Show file tree
Hide file tree
Showing 18 changed files with 465 additions and 24 deletions.
8 changes: 4 additions & 4 deletions ballerina/Ballerina.toml
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
[package]
org = "ballerina"
name = "http"
version = "2.9.1"
version = "2.10.0"
authors = ["Ballerina"]
keywords = ["http", "network", "service", "listener", "client"]
repository = "https://github.com/ballerina-platform/module-ballerina-http"
icon = "icon.png"
license = ["Apache-2.0"]
distribution = "2201.7.0"
distribution = "2201.8.0"
export = ["http", "http.httpscerr"]

[platform.java11]
Expand All @@ -16,8 +16,8 @@ graalvmCompatible = true
[[platform.java11.dependency]]
groupId = "io.ballerina.stdlib"
artifactId = "http-native"
version = "2.9.1"
path = "../native/build/libs/http-native-2.9.1-SNAPSHOT.jar"
version = "2.10.0"
path = "../native/build/libs/http-native-2.10.0-SNAPSHOT.jar"

[[platform.java11.dependency]]
groupId = "io.ballerina.stdlib"
Expand Down
2 changes: 1 addition & 1 deletion ballerina/CompilerPlugin.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ id = "http-compiler-plugin"
class = "io.ballerina.stdlib.http.compiler.HttpCompilerPlugin"

[[dependency]]
path = "../compiler-plugin/build/libs/http-compiler-plugin-2.9.1-SNAPSHOT.jar"
path = "../compiler-plugin/build/libs/http-compiler-plugin-2.10.0-SNAPSHOT.jar"
4 changes: 2 additions & 2 deletions ballerina/Dependencies.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

[ballerina]
dependencies-toml-version = "2"
distribution-version = "2201.7.0"
distribution-version = "2201.8.0-20230716-001200-4e224cd5"

[[package]]
org = "ballerina"
Expand Down Expand Up @@ -76,7 +76,7 @@ modules = [
[[package]]
org = "ballerina"
name = "http"
version = "2.9.1"
version = "2.10.0"
dependencies = [
{org = "ballerina", name = "auth"},
{org = "ballerina", name = "cache"},
Expand Down
2 changes: 1 addition & 1 deletion build-config/resources/Ballerina.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ keywords = ["http", "network", "service", "listener", "client"]
repository = "https://github.com/ballerina-platform/module-ballerina-http"
icon = "icon.png"
license = ["Apache-2.0"]
distribution = "2201.7.0"
distribution = "2201.8.0"
export = ["http", "http.httpscerr"]

[platform.java11]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2023, 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 io.ballerina.stdlib.http.compiler;

import io.ballerina.projects.ProjectEnvironmentBuilder;
import io.ballerina.projects.environment.Environment;
import io.ballerina.projects.environment.EnvironmentBuilder;

import java.nio.file.Path;
import java.nio.file.Paths;

/**
* Abstract compiler plugin test for LS.
*/
public class AbstractLSCompilerPluginTest {
protected static final Path RESOURCE_PATH = Paths.get("src", "test", "resources");
protected static final Path DISTRIBUTION_PATH = Paths.get("../", "target", "ballerina-runtime");

protected static ProjectEnvironmentBuilder getEnvironmentBuilder() {
Environment environment = EnvironmentBuilder.getBuilder().setBallerinaHome(DISTRIBUTION_PATH).build();
return ProjectEnvironmentBuilder.getBuilder(environment);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,42 +26,31 @@
import io.ballerina.projects.Package;
import io.ballerina.projects.PackageCompilation;
import io.ballerina.projects.Project;
import io.ballerina.projects.ProjectEnvironmentBuilder;
import io.ballerina.projects.directory.ProjectLoader;
import io.ballerina.projects.environment.Environment;
import io.ballerina.projects.environment.EnvironmentBuilder;
import io.ballerina.projects.plugins.codeaction.CodeActionArgument;
import io.ballerina.projects.plugins.codeaction.CodeActionContextImpl;
import io.ballerina.projects.plugins.codeaction.CodeActionExecutionContext;
import io.ballerina.projects.plugins.codeaction.CodeActionExecutionContextImpl;
import io.ballerina.projects.plugins.codeaction.CodeActionInfo;
import io.ballerina.projects.plugins.codeaction.DocumentEdit;
import io.ballerina.stdlib.http.compiler.AbstractLSCompilerPluginTest;
import io.ballerina.tools.text.LinePosition;
import org.testng.Assert;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
* Abstract implementation of codeaction tests.
*/
public abstract class AbstractCodeActionTest {

protected static final Path RESOURCE_PATH = Paths.get("src", "test", "resources");
protected static final Path DISTRIBUTION_PATH = Paths.get("../", "target", "ballerina-runtime");
public abstract class AbstractCodeActionTest extends AbstractLSCompilerPluginTest {

private static final Gson GSON = new Gson();

private static ProjectEnvironmentBuilder getEnvironmentBuilder() {
Environment environment = EnvironmentBuilder.getBuilder().setBallerinaHome(DISTRIBUTION_PATH).build();
return ProjectEnvironmentBuilder.getBuilder(environment);
}


/**
* Performs the actual test. This will verify both the code action title/args and the edits made once executed.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
* Copyright (c) 2023, 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 io.ballerina.stdlib.http.compiler.completion;

import com.google.gson.Gson;
import io.ballerina.compiler.syntax.tree.ModulePartNode;
import io.ballerina.compiler.syntax.tree.NonTerminalNode;
import io.ballerina.projects.CompletionManager;
import io.ballerina.projects.CompletionResult;
import io.ballerina.projects.Document;
import io.ballerina.projects.DocumentId;
import io.ballerina.projects.Module;
import io.ballerina.projects.Package;
import io.ballerina.projects.PackageCompilation;
import io.ballerina.projects.Project;
import io.ballerina.projects.directory.ProjectLoader;
import io.ballerina.projects.plugins.completion.CompletionContext;
import io.ballerina.projects.plugins.completion.CompletionContextImpl;
import io.ballerina.projects.plugins.completion.CompletionException;
import io.ballerina.projects.plugins.completion.CompletionItem;
import io.ballerina.stdlib.http.compiler.AbstractLSCompilerPluginTest;
import io.ballerina.tools.text.LinePosition;
import io.ballerina.tools.text.TextRange;
import org.testng.Assert;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;

/**
* Abstract implementation of completion tests.
*/
public abstract class AbstractCompletionTest extends AbstractLSCompilerPluginTest {

private static final Gson GSON = new Gson();


@Test(dataProvider = "completion-data-provider")
protected void test(String filePath, int line, int offset, String configFile)
throws IOException {

Path sourceFilePath = Path.of(filePath);
Path configfilePath = Path.of(configFile);
TestConfig expectedList =
GSON.fromJson(Files.newBufferedReader(configfilePath), TestConfig.class);
List<CompletionItem> expectedItems = expectedList.getItems();
LinePosition cursorPos = LinePosition.from(line, offset);

Project project = ProjectLoader.loadProject(sourceFilePath, getEnvironmentBuilder());
CompletionResult completionResult = getCompletions(sourceFilePath, cursorPos, project);
List<CompletionItem> actualItems = completionResult.getCompletionItems();
List<CompletionException> errors = completionResult.getErrors();
Assert.assertTrue(errors.isEmpty());
Assert.assertTrue(compareCompletionItems(actualItems, expectedItems));
}

private static boolean compareCompletionItems(List<CompletionItem> actualItems,
List<CompletionItem> expectedItems) {
List<String> actualList = actualItems.stream()
.map(AbstractCompletionTest::getCompletionItemPropertyString)
.collect(Collectors.toList());
List<String> expectedList = expectedItems.stream()
.map(AbstractCompletionTest::getCompletionItemPropertyString)
.collect(Collectors.toList());
return actualList.containsAll(expectedList) && actualItems.size() == expectedItems.size();
}

private static String getCompletionItemPropertyString(CompletionItem completionItem) {
// Here we replace the Windows specific \r\n to \n for evaluation only
String additionalTextEdits = "";
if (completionItem.getAdditionalTextEdits() != null && !completionItem.getAdditionalTextEdits().isEmpty()) {
additionalTextEdits = "," + GSON.toJson(completionItem.getAdditionalTextEdits());
}
return ("{" +
completionItem.getInsertText() + "," +
completionItem.getLabel() + "," +
completionItem.getPriority() +
additionalTextEdits +
"}").replace("\r\n", "\n").replace("\\r\\n", "\\n");
}

private CompletionResult getCompletions(Path filePath, LinePosition cursorPos, Project project) {

Package currentPackage = project.currentPackage();
PackageCompilation compilation = currentPackage.getCompilation();
CompletionManager completionManager = compilation.getCompletionManager();

DocumentId documentId = project.documentId(filePath);
Document document = currentPackage.getDefaultModule().document(documentId);
Module module = project.currentPackage().module(documentId.moduleId());

int cursorPositionInTree = document.textDocument().textPositionFrom(cursorPos);
TextRange range = TextRange.from(cursorPositionInTree, 0);
NonTerminalNode nodeAtCursor = ((ModulePartNode) document.syntaxTree().rootNode()).findNode(range);

CompletionContext completionContext = CompletionContextImpl.from(filePath.toUri().toString(),
filePath, cursorPos, cursorPositionInTree, nodeAtCursor, document,
module.getCompilation().getSemanticModel());

return completionManager.completions(completionContext);
}

@DataProvider(name = "completion-data-provider")
public abstract Object[][] dataProvider();

/**
* Represents the completion test config.
*/
public static class TestConfig {
private List<CompletionItem> items;

public void setItems(List<CompletionItem> items) {
this.items = items;
}

public List<CompletionItem> getItems() {
return items;
}
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
/*
* Copyright (c) 2023, 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 io.ballerina.stdlib.http.compiler.completion;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import java.io.IOException;
import java.nio.file.Path;

/**
* Tests the completions in ServiceDeclarationNode context.
*/
public class ServiceDeclarationNodeContextTest extends AbstractCompletionTest {


@Override
@Test(dataProvider = "completion-data-provider")
protected void test(String filePath, int line, int offset, String configFile)
throws IOException {
Path filePathFromSourceRoot = RESOURCE_PATH.resolve("ballerina_sources")
.resolve(filePath);
Path configPath = RESOURCE_PATH.resolve("completion")
.resolve(getConfigDir())
.resolve(configFile);
super.test(filePathFromSourceRoot.toString(), line, offset, configPath.toString());
}

@DataProvider(name = "completion-data-provider")
@Override
public Object[][] dataProvider() {
return new Object[][]{
{"sample_completion_package_1/main.bal", 22, 5, "expected_completions1.json"},
{"sample_completion_package_2/main.bal", 22, 5, "expected_completions1.json"},
{"sample_completion_package_2/main.bal", 35, 5, "expected_completions1.json"},

};
}

protected String getConfigDir() {
return "service_declaration";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
[package]
org = "http_test"
name = "sample_completion_package_1"
version = "0.1.0"

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Copyright (c) 2023, 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.

// This is added to test some auto generated code segments.
// Please ignore the indentation.

import ballerina/http;

service /greeting on new http:Listener(9090) {
r
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
[package]
org = "http_test"
name = "sample_completion_package_2"
version = "0.1.0"
Loading

0 comments on commit 1cb5ac9

Please sign in to comment.