diff --git a/build.gradle b/build.gradle index c5a50b6..7d112ef 100644 --- a/build.gradle +++ b/build.gradle @@ -41,12 +41,6 @@ allprojects { repositories { jcenter() - maven { - url "https://oss.sonatype.org/content/repositories/snapshots/" - } - maven { - url "https://oss.jfrog.org/artifactory/oss-snapshot-local" - } } if (System.env.CIRCLE_ARTIFACTS) { diff --git a/gradle.properties b/gradle.properties index 441ac76..83c80af 100644 --- a/gradle.properties +++ b/gradle.properties @@ -11,17 +11,18 @@ shadowJarVersion=1.2.3 # Project Dependencies commonsIoVersion=2.4 -groovyAllVersion=2.5.0-SNAPSHOT +groovyAllVersion=2.5.0-beta-1 guavaVersion=19.0 immutablesVersion=2.2.1 jacksonDatabindVersion=2.6.3 javaxRsVersion=2.0.1 jclOverSlf4jVersion=1.7.22 slf4jApiVersion=1.7.5 -typefoxLsApiVersion=0.4.0-SNAPSHOT +lsApiVersion=0.2.0 # Test Dependencies findbugsAnnotationsVersion=3.0.1 hamcrestVersion=1.3 junitVersion=4.12 mockitoVersion=1.10.19 +assertjVersion = 3.6.2 diff --git a/groovy-language-server/build.gradle b/groovy-language-server/build.gradle index afee338..9e512b9 100644 --- a/groovy-language-server/build.gradle +++ b/groovy-language-server/build.gradle @@ -14,14 +14,13 @@ dependencies { compile "commons-io:commons-io:${commonsIoVersion}" compile "org.slf4j:jcl-over-slf4j:${jclOverSlf4jVersion}" compile "org.slf4j:slf4j-api:${slf4jApiVersion}" - compile "io.typefox.lsapi:io.typefox.lsapi:${typefoxLsApiVersion}" - compile "io.typefox.lsapi:io.typefox.lsapi.annotations:${typefoxLsApiVersion}" - compile "io.typefox.lsapi:io.typefox.lsapi.services:${typefoxLsApiVersion}" + compile "org.eclipse.lsp4j:org.eclipse.lsp4j:${lsApiVersion}" + compile "org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc:${lsApiVersion}" compile "javax.ws.rs:javax.ws.rs-api:${javaxRsVersion}" compile "org.codehaus.groovy:groovy-all:${groovyAllVersion}" testCompile "junit:junit:${junitVersion}" testCompile "org.hamcrest:hamcrest-all:${hamcrestVersion}" testCompile "org.mockito:mockito-core:${mockitoVersion}" + testCompile "org.assertj:assertj-core:${assertjVersion}" } - diff --git a/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyLanguageServer.java b/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyLanguageServer.java index 0438bdb..adda75e 100644 --- a/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyLanguageServer.java +++ b/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyLanguageServer.java @@ -16,6 +16,7 @@ package com.palantir.ls.groovy; +import com.google.common.collect.ImmutableList; import com.google.common.io.Files; import com.palantir.ls.DefaultCompilerWrapper; import com.palantir.ls.DefaultLanguageServerState; @@ -23,49 +24,44 @@ import com.palantir.ls.api.LanguageServerState; import com.palantir.ls.api.TreeParser; import com.palantir.ls.services.DefaultTextDocumentService; -import com.palantir.ls.services.DefaultWindowService; import com.palantir.ls.services.DefaultWorkspaceService; import com.palantir.ls.util.Uris; import com.palantir.ls.util.WorkspaceUriSupplier; -import io.typefox.lsapi.InitializeParams; -import io.typefox.lsapi.InitializeResult; -import io.typefox.lsapi.ServerCapabilities; -import io.typefox.lsapi.TextDocumentSyncKind; -import io.typefox.lsapi.builders.CompletionOptionsBuilder; -import io.typefox.lsapi.builders.InitializeResultBuilder; -import io.typefox.lsapi.builders.ServerCapabilitiesBuilder; -import io.typefox.lsapi.services.LanguageServer; -import io.typefox.lsapi.services.TextDocumentService; -import io.typefox.lsapi.services.WindowService; -import io.typefox.lsapi.services.WorkspaceService; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; import org.apache.commons.io.FileUtils; +import org.eclipse.lsp4j.CompletionOptions; +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.InitializeResult; +import org.eclipse.lsp4j.ServerCapabilities; +import org.eclipse.lsp4j.TextDocumentSyncKind; +import org.eclipse.lsp4j.services.LanguageClient; +import org.eclipse.lsp4j.services.LanguageClientAware; +import org.eclipse.lsp4j.services.LanguageServer; +import org.eclipse.lsp4j.services.TextDocumentService; +import org.eclipse.lsp4j.services.WorkspaceService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -public class GroovyLanguageServer implements LanguageServer { +public class GroovyLanguageServer implements LanguageServer, LanguageClientAware { private static final Logger logger = LoggerFactory.getLogger(GroovyLanguageServer.class); private final LanguageServerState state; private final TextDocumentService textDocumentService; private final WorkspaceService workspaceService; - private final WindowService windowService; private Path workspaceRoot; private Path targetDirectory; private Path changedFilesDirectory; - public GroovyLanguageServer(LanguageServerState state, TextDocumentService textDocumentService, - WorkspaceService workspaceService, WindowService windowService) { + public GroovyLanguageServer( + LanguageServerState state, TextDocumentService textDocumentService, WorkspaceService workspaceService) { this.state = state; this.textDocumentService = textDocumentService; this.workspaceService = workspaceService; - this.windowService = windowService; } @Override @@ -74,20 +70,16 @@ public CompletableFuture initialize(InitializeParams params) { workspaceRoot = Uris.getAbsolutePath(params.getRootPath()); logger.debug("Resolve workspace root from '{}' to '{}'", params.getRootPath(), workspaceRoot); - ServerCapabilities capabilities = new ServerCapabilitiesBuilder() - .textDocumentSync(TextDocumentSyncKind.Incremental) - .documentSymbolProvider(true) - .workspaceSymbolProvider(true) - .referencesProvider(true) - .completionProvider(new CompletionOptionsBuilder() - .resolveProvider(false) - .triggerCharacter(".") - .build()) - .definitionProvider(true) - .build(); - InitializeResult result = new InitializeResultBuilder() - .capabilities(capabilities) - .build(); + CompletionOptions completionOptions = new CompletionOptions(false, ImmutableList.of(".")); + ServerCapabilities serverCapabilities = new ServerCapabilities(); + serverCapabilities.setCompletionProvider(completionOptions); + serverCapabilities.setTextDocumentSync(TextDocumentSyncKind.Incremental); + serverCapabilities.setDocumentSymbolProvider(true); + serverCapabilities.setWorkspaceSymbolProvider(true); + serverCapabilities.setDocumentSymbolProvider(true); + serverCapabilities.setReferencesProvider(true); + serverCapabilities.setDefinitionProvider(true); + InitializeResult initializeResult = new InitializeResult(serverCapabilities); targetDirectory = Files.createTempDir().toPath(); changedFilesDirectory = Files.createTempDir().toPath(); @@ -100,13 +92,14 @@ public CompletableFuture initialize(InitializeParams params) { DefaultCompilerWrapper groovycWrapper = new DefaultCompilerWrapper(compiler, parser); state.setCompilerWrapper(groovycWrapper); - return CompletableFuture.completedFuture(result); + return CompletableFuture.completedFuture(initializeResult); } @Override - public void shutdown() { + public CompletableFuture shutdown() { deleteDirectory(targetDirectory.toFile()); deleteDirectory(changedFilesDirectory.toFile()); + return CompletableFuture.completedFuture(new Object()); } private static void deleteDirectory(File directory) { @@ -130,16 +123,6 @@ public WorkspaceService getWorkspaceService() { return workspaceService; } - @Override - public WindowService getWindowService() { - return windowService; - } - - @Override - public void onTelemetryEvent(Consumer callback) { - state.setTelemetryEvent(callback); - } - public Path getWorkspaceRoot() { return workspaceRoot; } @@ -147,12 +130,20 @@ public Path getWorkspaceRoot() { public static void main(String[] args) { LanguageServerState state = new DefaultLanguageServerState(); LanguageServer server = - new GroovyLanguageServer(state, new DefaultTextDocumentService(state), - new DefaultWorkspaceService(state), new DefaultWindowService(state)); + new GroovyLanguageServer( + state, new DefaultTextDocumentService(state), new DefaultWorkspaceService(state)); + StreamLanguageServerLauncher launcher = new StreamLanguageServerLauncher(server, System.in, System.out); - launcher.setLogger(logger); launcher.launch(); } + @Override + public void connect(LanguageClient client) { + state.setPublishDiagnostics(client::publishDiagnostics); + state.setTelemetryEvent(client::telemetryEvent); + state.setShowMessage(client::showMessage); + state.setShowMessageRequest(client::showMessageRequest); + state.setLogMessage(client::logMessage); + } } diff --git a/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyTreeParser.java b/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyTreeParser.java index ea70715..09ae718 100644 --- a/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyTreeParser.java +++ b/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyTreeParser.java @@ -32,13 +32,6 @@ import com.palantir.ls.util.UriSupplier; import com.palantir.ls.util.Uris; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.typefox.lsapi.CompletionList; -import io.typefox.lsapi.Location; -import io.typefox.lsapi.Position; -import io.typefox.lsapi.ReferenceParams; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.SymbolKind; -import io.typefox.lsapi.builders.SymbolInformationBuilder; import java.net.URI; import java.nio.file.Path; import java.util.Collection; @@ -58,6 +51,12 @@ import org.codehaus.groovy.ast.expr.VariableExpression; import org.codehaus.groovy.ast.stmt.BlockStatement; import org.codehaus.groovy.control.CompilationUnit; +import org.eclipse.lsp4j.CompletionList; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; /** * Groovy implementation of the TreeParser. Depends on a supplier of a Groovy CompilationUnit. @@ -291,27 +290,27 @@ private static SymbolKind getKind(ClassNode node) { // sourceUri should already have been converted to a workspace URI private SymbolInformation getVariableSymbolInformation(String parentName, URI sourceUri, Variable variable) { - SymbolInformationBuilder builder = - new SymbolInformationBuilder().name(variable.getName()).containerName(parentName); + final SymbolKind kind; + final Location location; if (variable instanceof DynamicVariable) { - builder.kind(SymbolKind.Field); - builder.location(GroovyLocations.createLocation(sourceUri)); + kind = SymbolKind.Field; + location = GroovyLocations.createLocation(sourceUri); } else if (variable instanceof FieldNode) { - builder.kind(SymbolKind.Field); - builder.location(GroovyLocations.createLocation(sourceUri, (FieldNode) variable)); + kind = SymbolKind.Field; + location = GroovyLocations.createLocation(sourceUri, (FieldNode) variable); } else if (variable instanceof Parameter) { - builder.kind(SymbolKind.Variable); - builder.location(GroovyLocations.createLocation(sourceUri, (Parameter) variable)); + kind = SymbolKind.Variable; + location = GroovyLocations.createLocation(sourceUri, (Parameter) variable); } else if (variable instanceof PropertyNode) { - builder.kind(SymbolKind.Field); - builder.location(GroovyLocations.createLocation(sourceUri, (PropertyNode) variable)); + kind = SymbolKind.Field; + location = GroovyLocations.createLocation(sourceUri, (PropertyNode) variable); } else if (variable instanceof VariableExpression) { - builder.kind(SymbolKind.Variable); - builder.location(GroovyLocations.createLocation(sourceUri, (VariableExpression) variable)); + kind = SymbolKind.Variable; + location = GroovyLocations.createLocation(sourceUri, (VariableExpression) variable); } else { throw new IllegalArgumentException(String.format("Unknown type of variable: %s", variable)); } - return builder.build(); + return new SymbolInformation(variable.getName(), kind, location, parentName); } // sourceUri should already have been converted to a workspace URI @@ -351,12 +350,7 @@ private void parseMethod(Indexer newIndexer, URI sourceUri, ClassNode parent, Ma private static SymbolInformation createSymbolInformation(String name, SymbolKind kind, Location location, Optional parentName) { - return new SymbolInformationBuilder() - .containerName(parentName.orNull()) - .kind(kind) - .location(location) - .name(name) - .build(); + return new SymbolInformation(name, kind, location, parentName.orNull()); } private static class ReferenceLocation { diff --git a/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyWorkspaceCompiler.java b/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyWorkspaceCompiler.java index 773db7f..1e6d00a 100644 --- a/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyWorkspaceCompiler.java +++ b/groovy-language-server/src/main/java/com/palantir/ls/groovy/GroovyWorkspaceCompiler.java @@ -22,22 +22,15 @@ import com.google.common.base.Supplier; import com.google.common.base.Throwables; import com.google.common.collect.ImmutableSet; +import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.io.Files; import com.palantir.ls.api.WorkspaceCompiler; -import com.palantir.ls.groovy.util.DefaultDiagnosticBuilder; import com.palantir.ls.groovy.util.GroovyConstants; import com.palantir.ls.util.Ranges; import com.palantir.ls.util.SourceWriter; import com.palantir.ls.util.Uris; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.typefox.lsapi.Diagnostic; -import io.typefox.lsapi.DiagnosticSeverity; -import io.typefox.lsapi.FileEvent; -import io.typefox.lsapi.PublishDiagnosticsParams; -import io.typefox.lsapi.Range; -import io.typefox.lsapi.TextDocumentContentChangeEvent; -import io.typefox.lsapi.builders.PublishDiagnosticsParamsBuilder; import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -58,6 +51,12 @@ import org.codehaus.groovy.control.messages.SyntaxErrorMessage; import org.codehaus.groovy.control.messages.WarningMessage; import org.codehaus.groovy.syntax.SyntaxException; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.FileEvent; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -241,13 +240,16 @@ private void resetCompilationUnit() { } private Set parseErrors(ErrorCollector collector) { - Map diagnosticsByFile = Maps.newHashMap(); + Map> diagnosticsByFile = Maps.newHashMap(); for (int i = 0; i < collector.getWarningCount(); i++) { WarningMessage message = collector.getWarning(i); - diagnosticsByFile.computeIfAbsent(workspaceRoot.toUri(), - (value) -> new PublishDiagnosticsParamsBuilder().uri(workspaceRoot.toUri().toString())) - .diagnostic(new DefaultDiagnosticBuilder(message.getMessage(), DiagnosticSeverity.Warning).build()); + String message1 = message.getMessage() == null + ? "" + : message.getMessage(); + Diagnostic diag = new Diagnostic( + Ranges.UNDEFINED_RANGE, message1, DiagnosticSeverity.Warning, GroovyConstants.GROOVY_COMPILER); + diagnosticsByFile.computeIfAbsent(workspaceRoot.toUri(), (ignored) -> Lists.newArrayList()).add(diag); } for (int i = 0; i < collector.getErrorCount(); i++) { Message message = collector.getError(i); @@ -261,20 +263,22 @@ private Set parseErrors(ErrorCollector collector) { Ranges.createZeroBasedRange(cause.getStartLine(), cause.getStartColumn(), cause.getEndLine(), cause.getEndColumn()); uri = Paths.get(cause.getSourceLocator()).toUri(); - diagnostic = new DefaultDiagnosticBuilder(cause.getMessage(), DiagnosticSeverity.Error) - .range(range) - .build(); + diagnostic = new Diagnostic( + range, cause.getMessage(), DiagnosticSeverity.Error, GroovyConstants.GROOVY_COMPILER); } else { StringWriter data = new StringWriter(); PrintWriter writer = new PrintWriter(data); message.write(writer); uri = workspaceRoot.toUri(); - diagnostic = new DefaultDiagnosticBuilder(data.toString(), DiagnosticSeverity.Error).build(); + String message1 = data.toString(); + diagnostic = new Diagnostic( + Ranges.UNDEFINED_RANGE, message1, DiagnosticSeverity.Error, GroovyConstants.GROOVY_COMPILER); } - diagnosticsByFile.computeIfAbsent(uri, (value) -> new PublishDiagnosticsParamsBuilder().uri(uri.toString())) - .diagnostic(diagnostic); + diagnosticsByFile.computeIfAbsent(uri, (ignored) -> Lists.newArrayList()).add(diagnostic); } - return diagnosticsByFile.values().stream().map(PublishDiagnosticsParamsBuilder::build) + return diagnosticsByFile.entrySet() + .stream() + .map(entry -> new PublishDiagnosticsParams(entry.getKey().toString(), entry.getValue())) .collect(Collectors.toSet()); } diff --git a/groovy-language-server/src/main/java/com/palantir/ls/groovy/Indexer.java b/groovy-language-server/src/main/java/com/palantir/ls/groovy/Indexer.java index 0c55df7..9b4da2a 100644 --- a/groovy-language-server/src/main/java/com/palantir/ls/groovy/Indexer.java +++ b/groovy-language-server/src/main/java/com/palantir/ls/groovy/Indexer.java @@ -20,11 +20,11 @@ import com.google.common.collect.Maps; import com.google.common.collect.Sets; import com.palantir.ls.util.Ranges; -import io.typefox.lsapi.Location; -import io.typefox.lsapi.SymbolInformation; import java.net.URI; import java.util.Map; import java.util.Set; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.SymbolInformation; public class Indexer { diff --git a/groovy-language-server/src/main/java/com/palantir/ls/groovy/MethodVisitor.java b/groovy-language-server/src/main/java/com/palantir/ls/groovy/MethodVisitor.java index f02afdc..7cb8d18 100644 --- a/groovy-language-server/src/main/java/com/palantir/ls/groovy/MethodVisitor.java +++ b/groovy-language-server/src/main/java/com/palantir/ls/groovy/MethodVisitor.java @@ -21,10 +21,6 @@ import com.palantir.ls.groovy.util.GroovyLocations; import com.palantir.ls.util.Ranges; import com.palantir.ls.util.UriSupplier; -import io.typefox.lsapi.Location; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.SymbolKind; -import io.typefox.lsapi.builders.SymbolInformationBuilder; import java.net.URI; import java.util.List; import java.util.Map; @@ -46,6 +42,9 @@ import org.codehaus.groovy.ast.expr.StaticMethodCallExpression; import org.codehaus.groovy.ast.expr.VariableExpression; import org.codehaus.groovy.ast.stmt.CatchStatement; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; public class MethodVisitor extends CodeVisitorSupport { @@ -219,33 +218,34 @@ private Location createLocation(URI locationUri, ASTNode node) { } private SymbolInformation getVariableSymbolInformation(Variable variable) { - SymbolInformationBuilder builder = - new SymbolInformationBuilder().name(variable.getName()); + final String containerName; + final SymbolKind kind; + final Location location; if (methodNode.isPresent()) { - builder.containerName(methodNode.get().getName()); + containerName = methodNode.get().getName(); } else { - builder.containerName(clazz.getName()); + containerName = clazz.getName(); } if (variable instanceof DynamicVariable) { - builder.kind(SymbolKind.Field); - builder.location(GroovyLocations.createLocation(workspaceUriSupplier.get(uri))); + kind = SymbolKind.Field; + location = GroovyLocations.createLocation(workspaceUriSupplier.get(uri)); } else if (variable instanceof FieldNode) { - builder.kind(SymbolKind.Field); - builder.location(createLocation(uri, (FieldNode) variable)); + kind = SymbolKind.Field; + location = createLocation(uri, (FieldNode) variable); } else if (variable instanceof Parameter) { - builder.kind(SymbolKind.Variable); - builder.location(createLocation(uri, (Parameter) variable)); + kind = SymbolKind.Variable; + location = createLocation(uri, (Parameter) variable); } else if (variable instanceof PropertyNode) { - builder.kind(SymbolKind.Field); - builder.location(createLocation(uri, (PropertyNode) variable)); + kind = SymbolKind.Field; + location = createLocation(uri, (PropertyNode) variable); } else if (variable instanceof VariableExpression) { - builder.kind(SymbolKind.Variable); - builder.location(createLocation(uri, (VariableExpression) variable)); + kind = SymbolKind.Variable; + location = createLocation(uri, (VariableExpression) variable); } else { throw new IllegalArgumentException(String.format("Unknown type of variable: %s", variable)); } - return builder.build(); + return new SymbolInformation(variable.getName(), kind, location, containerName); } private static boolean areEquals(Parameter[] parameters, ArgumentListExpression arguments) { diff --git a/groovy-language-server/src/main/java/com/palantir/ls/groovy/util/DefaultDiagnosticBuilder.java b/groovy-language-server/src/main/java/com/palantir/ls/groovy/util/DefaultDiagnosticBuilder.java deleted file mode 100644 index 720715d..0000000 --- a/groovy-language-server/src/main/java/com/palantir/ls/groovy/util/DefaultDiagnosticBuilder.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2016 Palantir Technologies, Inc. All rights reserved. - * - * Licensed 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 com.palantir.ls.groovy.util; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.palantir.ls.util.Ranges; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.typefox.lsapi.DiagnosticSeverity; -import io.typefox.lsapi.builders.DiagnosticBuilder; - -@SuppressFBWarnings("PT_EXTENDS_CONCRETE_TYPE") -public class DefaultDiagnosticBuilder extends DiagnosticBuilder { - - public DefaultDiagnosticBuilder(String message, DiagnosticSeverity severity) { - checkNotNull(message, "message cannot be null"); - this.message(message); - this.severity(severity); - this.range(Ranges.UNDEFINED_RANGE); - this.source(GroovyConstants.GROOVY_COMPILER); - } - -} diff --git a/groovy-language-server/src/main/java/com/palantir/ls/groovy/util/GroovyLocations.java b/groovy-language-server/src/main/java/com/palantir/ls/groovy/util/GroovyLocations.java index bcd9cbd..5defeee 100644 --- a/groovy-language-server/src/main/java/com/palantir/ls/groovy/util/GroovyLocations.java +++ b/groovy-language-server/src/main/java/com/palantir/ls/groovy/util/GroovyLocations.java @@ -17,12 +17,11 @@ package com.palantir.ls.groovy.util; import com.palantir.ls.util.Ranges; -import io.typefox.lsapi.Location; -import io.typefox.lsapi.Range; -import io.typefox.lsapi.builders.LocationBuilder; import java.net.URI; import org.codehaus.groovy.ast.ASTNode; import org.codehaus.groovy.ast.ClassNode; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Range; public final class GroovyLocations { @@ -32,21 +31,20 @@ private GroovyLocations() {} * Creates a location from the given URI with an undefined range. */ public static Location createLocation(URI uri) { - return new LocationBuilder() - .uri(uri.toString()) - .range(Ranges.UNDEFINED_RANGE) - .build(); + return new Location(uri.toString(), Ranges.UNDEFINED_RANGE); } /** * Creates a location from the given URI and node's start and end positions. */ public static Location createLocation(URI uri, ASTNode node) { - return new LocationBuilder() - .uri(uri.toString()) - .range(Ranges.createZeroBasedRange(node.getLineNumber(), node.getColumnNumber(), - node.getLastLineNumber(), node.getLastColumnNumber())) - .build(); + return new Location( + uri.toString(), + Ranges.createZeroBasedRange( + node.getLineNumber(), + node.getColumnNumber(), + node.getLastLineNumber(), + node.getLastColumnNumber())); } /** @@ -63,10 +61,7 @@ public static Location createClassDefinitionLocation(URI uri, ClassNode node) { Math.min(node.getLineNumber() + 1, node.getLastLineNumber()), Math.min(1, node.getLastColumnNumber())); } - return new LocationBuilder() - .uri(uri.toString()) - .range(range) - .build(); + return new Location(uri.toString(), range); } } diff --git a/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyLanguageServerIntegrationTest.java b/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyLanguageServerIntegrationTest.java index c4de4ce..71f8048 100644 --- a/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyLanguageServerIntegrationTest.java +++ b/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyLanguageServerIntegrationTest.java @@ -16,41 +16,19 @@ package com.palantir.ls.groovy; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Sets; import com.palantir.ls.DefaultLanguageServerState; -import com.palantir.ls.StreamLanguageServerLauncher; import com.palantir.ls.api.LanguageServerState; -import com.palantir.ls.groovy.util.DefaultDiagnosticBuilder; +import com.palantir.ls.groovy.util.GroovyConstants; import com.palantir.ls.services.DefaultTextDocumentService; -import com.palantir.ls.services.DefaultWindowService; import com.palantir.ls.services.DefaultWorkspaceService; import com.palantir.ls.util.Ranges; -import io.typefox.lsapi.Diagnostic; -import io.typefox.lsapi.DiagnosticSeverity; -import io.typefox.lsapi.InitializeResult; -import io.typefox.lsapi.Message; -import io.typefox.lsapi.ServerCapabilities; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.SymbolKind; -import io.typefox.lsapi.TextDocumentSyncKind; -import io.typefox.lsapi.builders.CompletionOptionsBuilder; -import io.typefox.lsapi.builders.DidOpenTextDocumentParamsBuilder; -import io.typefox.lsapi.builders.DocumentSymbolParamsBuilder; -import io.typefox.lsapi.builders.InitializeParamsBuilder; -import io.typefox.lsapi.builders.ServerCapabilitiesBuilder; -import io.typefox.lsapi.builders.SymbolInformationBuilder; -import io.typefox.lsapi.builders.TextDocumentItemBuilder; -import io.typefox.lsapi.services.LanguageServer; -import io.typefox.lsapi.services.json.MessageJsonHandler; -import io.typefox.lsapi.services.json.StreamMessageReader; -import io.typefox.lsapi.services.json.StreamMessageWriter; -import io.typefox.lsapi.services.transport.client.LanguageClientEndpoint; -import io.typefox.lsapi.services.transport.io.ConcurrentMessageReader; -import io.typefox.lsapi.services.transport.io.MessageReader; -import io.typefox.lsapi.services.transport.io.MessageWriter; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.File; import java.io.IOException; import java.io.InputStream; @@ -65,13 +43,32 @@ import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; -import java.util.function.Consumer; import java.util.stream.Collectors; -import org.eclipse.xtext.xbase.lib.Procedures.Procedure2; +import org.eclipse.lsp4j.CompletionOptions; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.DidOpenTextDocumentParams; +import org.eclipse.lsp4j.DocumentSymbolParams; +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.InitializeResult; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.MessageActionItem; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.ServerCapabilities; +import org.eclipse.lsp4j.ShowMessageRequestParams; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.eclipse.lsp4j.TextDocumentItem; +import org.eclipse.lsp4j.TextDocumentSyncKind; +import org.eclipse.lsp4j.jsonrpc.Launcher; +import org.eclipse.lsp4j.launch.LSPLauncher; +import org.eclipse.lsp4j.services.LanguageClient; +import org.eclipse.lsp4j.services.LanguageClientAware; +import org.eclipse.lsp4j.services.LanguageServer; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -86,81 +83,97 @@ public class GroovyLanguageServerIntegrationTest { @Rule public TemporaryFolder workspaceRoot = new TemporaryFolder(); - private LanguageClientEndpoint client; private List publishedDiagnostics = Lists.newArrayList(); + private static LanguageServer actualServer; + private LanguageServer server; + @SuppressFBWarnings("DM_DEFAULT_ENCODING") @Before - public void before() throws IOException { - ExecutorService executorService = Executors.newCachedThreadPool(); - client = new LanguageClientEndpoint(executorService); - - MessageJsonHandler jsonHandler = new MessageJsonHandler(); - jsonHandler.setMethodResolver(client); - + public void before() throws IOException, InterruptedException { PipedOutputStream clientOutputStream = new PipedOutputStream(); PipedOutputStream serverOutputStream = new PipedOutputStream(); PipedInputStream clientInputStream = new PipedInputStream(serverOutputStream); PipedInputStream serverInputStream = new PipedInputStream(clientOutputStream); - MessageReader reader = - new ConcurrentMessageReader(new StreamMessageReader(clientInputStream, jsonHandler), executorService); - MessageWriter writer = new StreamMessageWriter(clientOutputStream, jsonHandler); + // Start Groovy language server + createAndLaunchLanguageServer(serverInputStream, serverOutputStream); + int counter = 0; + while (server != null && counter++ < 20) { + Thread.sleep(50); + } + LanguageClient client = getClient(); + Launcher clientLauncher = LSPLauncher.createClientLauncher( + client, + clientInputStream, + clientOutputStream, + false, + new PrintWriter(System.out)); + clientLauncher.startListening(); + server = clientLauncher.getRemoteProxy(); + ((LanguageClientAware) actualServer).connect(client); + } - reader.setOnError(new Consumer() { + private void createAndLaunchLanguageServer(final InputStream in, final OutputStream out) { + new Thread(() -> { + LanguageServerState state = new DefaultLanguageServerState(); + actualServer = new GroovyLanguageServer( + state, new DefaultTextDocumentService(state), new DefaultWorkspaceService(state)); + Launcher launcher = LSPLauncher.createServerLauncher( + actualServer, in, out, false, new PrintWriter(System.out)); + launcher.startListening(); + }).start(); + } + + private LanguageClient getClient() { + return new LanguageClient() { @Override - public void accept(Throwable error) { - System.err.println("ERROR:\n" + error); + public void telemetryEvent(Object object) { + logger.info("TELEMETRY"); } - }); - reader.setOnRead(new Procedure2() { + @Override - public void apply(Message message, String data) { - System.err.println("READ:\n" + message.getJsonrpc() + "\n" + data); + public void publishDiagnostics(PublishDiagnosticsParams diagnostics) { + publishedDiagnostics.add( + new MyPublishDiagnosticParams( + diagnostics.getUri(), + diagnostics.getDiagnostics().stream().collect(Collectors.toSet()))); } - }); - writer.setOnWrite(new Procedure2() { + @Override - public void apply(Message message, String data) { - System.err.println("WRITE:\n" + message.getJsonrpc() + "\n" + data); + public void showMessage(MessageParams messageParams) { + logger.info("MESSAGE"); } - }); - client.connect(reader, writer); - - // Start Groovy language server - createAndLaunchLanguageServer(serverInputStream, serverOutputStream); - - client.getTextDocumentService().onPublishDiagnostics((diagnosticsParams) -> { - publishedDiagnostics.add(new MyPublishDiagnosticParams(diagnosticsParams.getUri(), - diagnosticsParams.getDiagnostics().stream().collect(Collectors.toSet()))); - }); - } + @Override + public CompletableFuture showMessageRequest(ShowMessageRequestParams requestParams) { + logger.info("message"); + return CompletableFuture.completedFuture(new MessageActionItem()); + } - private static void createAndLaunchLanguageServer(final InputStream in, final OutputStream out) { - new Thread(new Runnable() { @Override - public void run() { - LanguageServerState state = new DefaultLanguageServerState(); - LanguageServer server = - new GroovyLanguageServer(state, new DefaultTextDocumentService(state), - new DefaultWorkspaceService(state), new DefaultWindowService(state)); - - StreamLanguageServerLauncher launcher = new StreamLanguageServerLauncher(server, in, out); - launcher.setLogger(logger); - launcher.launch(); + public void logMessage(MessageParams message) { + logger.info("LOG!"); } - }).start(); + }; } @Test public void testInitialize() throws InterruptedException, ExecutionException, TimeoutException { - CompletableFuture completableResult = - client.initialize(new InitializeParamsBuilder().clientName("natacha").processId(0) - .rootPath(workspaceRoot.getRoot().toPath().toUri().toString()).build()); + InitializeParams params = getInitializeParams(); + + CompletableFuture completableResult = server.initialize(params); InitializeResult result = completableResult.get(60, TimeUnit.SECONDS); assertCorrectInitializeResult(result); } + private InitializeParams getInitializeParams() { + InitializeParams params = new InitializeParams(); + params.setProcessId(0); + params.setClientName("natacha"); + params.setRootPath(workspaceRoot.getRoot().toPath().toUri().toString()); + return params; + } + @Test public void testSymbols() throws InterruptedException, ExecutionException, TimeoutException, IOException { File newFolder1 = workspaceRoot.newFolder(); @@ -178,9 +191,7 @@ public void testSymbols() throws InterruptedException, ExecutionException, Timeo + " }\n" + "}\n"); - CompletableFuture completableResult = - client.initialize(new InitializeParamsBuilder().clientName("natacha").processId(0) - .rootPath(workspaceRoot.getRoot().toPath().toUri().toString()).build()); + CompletableFuture completableResult = server.initialize(getInitializeParams()); InitializeResult result = completableResult.get(60, TimeUnit.SECONDS); assertCorrectInitializeResult(result); @@ -193,8 +204,8 @@ public void testSymbols() throws InterruptedException, ExecutionException, Timeo // Assert no diagnostics were published because compilation was successful assertEquals(Sets.newHashSet(), publishedDiagnostics.stream().collect(Collectors.toSet())); - CompletableFuture> documentSymbolResult = client.getTextDocumentService() - .documentSymbol(new DocumentSymbolParamsBuilder().textDocument(file.getAbsolutePath()).build()); + CompletableFuture> documentSymbolResult = server.getTextDocumentService() + .documentSymbol(new DocumentSymbolParams(new TextDocumentIdentifier(file.getAbsolutePath()))); Set actualSymbols = Sets.newHashSet(documentSymbolResult.get(60, TimeUnit.SECONDS)); // Remove generated symbols for a saner comparison actualSymbols = actualSymbols.stream() @@ -202,55 +213,44 @@ public void testSymbols() throws InterruptedException, ExecutionException, Timeo String fileUri = file.toPath().toUri().toString(); Set expectedResults = Sets.newHashSet( - new SymbolInformationBuilder() - .name("Coordinates") - .kind(SymbolKind.Class) - .location(fileUri, Ranges.createRange(0, 0, 1, 0)) - .build(), - new SymbolInformationBuilder() - .name("getAt") - .containerName("Coordinates") - .kind(SymbolKind.Method) - .location(fileUri, Ranges.createRange(4, 3, 10, 4)) - .build(), - new SymbolInformationBuilder() - .name("latitude") - .containerName("Coordinates") - .kind(SymbolKind.Field) - .location(fileUri, Ranges.createRange(1, 3, 1, 18)) - .build(), - new SymbolInformationBuilder() - .name("longitude") - .containerName("Coordinates") - .kind(SymbolKind.Field) - .location(fileUri, Ranges.createRange(2, 3, 2, 19)) - .build(), - new SymbolInformationBuilder() - .name("name") - .containerName("Coordinates") - .kind(SymbolKind.Field) - .location(fileUri, Ranges.createRange(3, 3, 3, 23)) - .build(), - new SymbolInformationBuilder() - .name("idx1") - .containerName("getAt") - .kind(SymbolKind.Variable) - .location(fileUri, Ranges.createRange(4, 16, 4, 24)) - .build(), - new SymbolInformationBuilder() - .name("idx2") - .containerName("getAt") - .kind(SymbolKind.Variable) - .location(fileUri, Ranges.createRange(4, 26, 4, 34)) - .build(), - new SymbolInformationBuilder() - .name("someString") - .containerName("getAt") - .kind(SymbolKind.Variable) - .location(fileUri, Ranges.createRange(5, 10, 5, 20)) - .build()); - - assertEquals(expectedResults, actualSymbols); + new SymbolInformation( + "Coordinates", SymbolKind.Class, new Location(fileUri, Ranges.createRange(0, 0, 1, 0))), + new SymbolInformation( + "getAt", + SymbolKind.Method, + new Location(fileUri, Ranges.createRange(4, 3, 10, 4)), + "Coordinates"), + new SymbolInformation( + "latitude", + SymbolKind.Field, + new Location(fileUri, Ranges.createRange(1, 3, 1, 18)), + "Coordinates"), + new SymbolInformation( + "longitude", + SymbolKind.Field, + new Location(fileUri, Ranges.createRange(2, 3, 2, 19)), + "Coordinates"), + new SymbolInformation( + "name", + SymbolKind.Field, + new Location(fileUri, Ranges.createRange(3, 3, 3, 23)), + "Coordinates"), + new SymbolInformation( + "idx1", + SymbolKind.Variable, + new Location(fileUri, Ranges.createRange(4, 16, 4, 24)), + "getAt"), + new SymbolInformation( + "idx2", + SymbolKind.Variable, + new Location(fileUri, Ranges.createRange(4, 26, 4, 34)), + "getAt"), + new SymbolInformation( + "someString", + SymbolKind.Variable, + new Location(fileUri, Ranges.createRange(5, 10, 5, 20)), + "getAt")); + assertThat(actualSymbols).containsOnlyElementsOf(expectedResults); } @Test @@ -290,9 +290,7 @@ public void testDiagnosticNotification() + "}\n"); addFileToFolder(workspaceRoot.getRoot(), "test4.groovy", "class ExceptionNew {}\n"); - CompletableFuture completableResult = - client.initialize(new InitializeParamsBuilder().clientName("natacha").processId(0) - .rootPath(workspaceRoot.getRoot().toPath().toUri().toString()).build()); + CompletableFuture completableResult = server.initialize(getInitializeParams()); InitializeResult result = completableResult.get(60, TimeUnit.SECONDS); assertCorrectInitializeResult(result); @@ -305,47 +303,38 @@ public void testDiagnosticNotification() Set expectedDiagnosticsResult = Sets.newHashSet( new MyPublishDiagnosticParams(test1.toPath().toUri().toString(), - Sets.newHashSet(new DefaultDiagnosticBuilder( + Sets.newHashSet(new Diagnostic( + Ranges.createRange(6, 17, 6, 72), "unable to resolve class ExceptionNew1 \n @ line 7, column 18.", - DiagnosticSeverity.Error) - .range(Ranges.createRange(6, 17, 6, 72)) - .build())), + DiagnosticSeverity.Error, + GroovyConstants.GROOVY_COMPILER))), new MyPublishDiagnosticParams(test2.toPath().toUri().toString(), - Sets.newHashSet(new DefaultDiagnosticBuilder( + Sets.newHashSet(new Diagnostic( + Ranges.createRange(6, 17, 6, 74), "unable to resolve class ExceptionNew222 \n @ line 7, column 18.", - DiagnosticSeverity.Error) - .range(Ranges.createRange(6, 17, 6, 74)) - .build()))); + DiagnosticSeverity.Error, + GroovyConstants.GROOVY_COMPILER)))); assertEquals(expectedDiagnosticsResult, publishedDiagnostics.stream().collect(Collectors.toSet())); assertEquals(2, publishedDiagnostics.size()); } private void sendDidOpen(File file) { - client.getTextDocumentService() - .didOpen(new DidOpenTextDocumentParamsBuilder() - .textDocument( - new TextDocumentItemBuilder() - .languageId("groovy") - .uri(file.getAbsolutePath()) - .version(0) - .text("foo") - .build()) - .build()); + server.getTextDocumentService() + .didOpen(new DidOpenTextDocumentParams( + new TextDocumentItem(file.getAbsolutePath(), "groovy", 0, "foo"))); } private void assertCorrectInitializeResult(InitializeResult result) { - ServerCapabilities expectedCapabilities = new ServerCapabilitiesBuilder() - .textDocumentSync(TextDocumentSyncKind.Incremental) - .documentSymbolProvider(true) - .workspaceSymbolProvider(true) - .referencesProvider(true) - .completionProvider(new CompletionOptionsBuilder() - .resolveProvider(false) - .triggerCharacter(".") - .build()) - .definitionProvider(true) - .build(); - assertEquals(expectedCapabilities, result.getCapabilities()); + CompletionOptions comp = new CompletionOptions(false, ImmutableList.of(".")); + ServerCapabilities capabilities = new ServerCapabilities(); + capabilities.setDocumentSymbolProvider(true); + capabilities.setWorkspaceSymbolProvider(true); + capabilities.setReferencesProvider(true); + capabilities.setCompletionProvider(comp); + capabilities.setDefinitionProvider(true); + capabilities.setTextDocumentSync(TextDocumentSyncKind.Incremental); + + assertThat(capabilities).isEqualToIgnoringGivenFields(result.getCapabilities(), "textDocumentSync"); } private static File addFileToFolder(File parent, String filename, String contents) throws IOException { diff --git a/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyLanguageServerTest.java b/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyLanguageServerTest.java index 62a5c63..b36103d 100644 --- a/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyLanguageServerTest.java +++ b/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyLanguageServerTest.java @@ -16,24 +16,21 @@ package com.palantir.ls.groovy; -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; +import static org.assertj.core.api.Assertions.assertThat; import com.palantir.ls.api.LanguageServerState; -import io.typefox.lsapi.InitializeParams; -import io.typefox.lsapi.InitializeResult; -import io.typefox.lsapi.TextDocumentSyncKind; -import io.typefox.lsapi.builders.InitializeParamsBuilder; -import io.typefox.lsapi.impl.ClientCapabilitiesImpl; -import io.typefox.lsapi.services.TextDocumentService; -import io.typefox.lsapi.services.WindowService; -import io.typefox.lsapi.services.WorkspaceService; import java.io.File; import java.io.IOException; import java.nio.file.Path; import java.nio.file.Paths; +import java.util.Optional; import java.util.concurrent.ExecutionException; +import org.eclipse.lsp4j.ClientCapabilities; +import org.eclipse.lsp4j.InitializeParams; +import org.eclipse.lsp4j.InitializeResult; +import org.eclipse.lsp4j.TextDocumentSyncKind; +import org.eclipse.lsp4j.services.TextDocumentService; +import org.eclipse.lsp4j.services.WorkspaceService; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -50,36 +47,40 @@ public class GroovyLanguageServerTest { @Before public void before() { server = new GroovyLanguageServer(Mockito.mock(LanguageServerState.class), - Mockito.mock(TextDocumentService.class), Mockito.mock(WorkspaceService.class), - Mockito.mock(WindowService.class)); + Mockito.mock(TextDocumentService.class), Mockito.mock(WorkspaceService.class)); } @Test public void testInitialize_absoluteWorkspacePath() throws InterruptedException, ExecutionException { - InitializeParams params = - new InitializeParamsBuilder().capabilities(new ClientCapabilitiesImpl()).processId(1) - .rootPath(folder.getRoot().toPath().toAbsolutePath().toString()).build(); - InitializeResult result = server.initialize(params).get(); + InitializeParams initializeParams = getInitializeParams(Optional.empty()); + + InitializeResult result = server.initialize(initializeParams).get(); assertInitializeResultIsCorrect(folder.getRoot().toPath().toAbsolutePath().normalize(), result); // Test normalization - params = new InitializeParamsBuilder().capabilities(new ClientCapabilitiesImpl()).processId(1) - .rootPath(folder.getRoot().toPath().toAbsolutePath().toString() + "/somethingelse/..").build(); - result = server.initialize(params).get(); + initializeParams = getInitializeParams(Optional.of( + folder.getRoot().toPath().toAbsolutePath().toString() + "/somethingelse/..")); + result = server.initialize(initializeParams).get(); assertInitializeResultIsCorrect(folder.getRoot().toPath().toAbsolutePath().normalize(), result); } + private InitializeParams getInitializeParams(Optional root) { + InitializeParams initializeParams = new InitializeParams(); + initializeParams.setProcessId(1); + initializeParams.setCapabilities(new ClientCapabilities()); + initializeParams.setRootPath(root.orElse(folder.getRoot().toPath().toAbsolutePath().toString())); + return initializeParams; + } + @Test public void testInitialize_uriWorkspacePath() throws InterruptedException, ExecutionException { - InitializeParams params = - new InitializeParamsBuilder().capabilities(new ClientCapabilitiesImpl()).processId(1) - .rootPath(folder.getRoot().toURI().toString()).build(); + InitializeParams params = getInitializeParams(Optional.empty()); InitializeResult result = server.initialize(params).get(); assertInitializeResultIsCorrect(folder.getRoot().toPath().toAbsolutePath().normalize(), result); // Test normalization - params = new InitializeParamsBuilder().capabilities(new ClientCapabilitiesImpl()).processId(1) - .rootPath(folder.getRoot().toURI().toString() + "/somethingelse/..").build(); + params = getInitializeParams(Optional.of( + folder.getRoot().toPath().toAbsolutePath().toString() + "/somethingelse/..")); result = server.initialize(params).get(); assertInitializeResultIsCorrect(folder.getRoot().toPath().toAbsolutePath().normalize(), result); } @@ -89,34 +90,31 @@ public void testInitialize_relativeWorkspacePath() throws InterruptedException, File workspaceRoot = Paths.get("").toAbsolutePath().resolve("test-directory-to-be-deleted").toFile(); // Create a directory in our working directory // If this fails, make sure ./groovy-language-server/test-directory-to-be-deleted doesn't exist. - assertTrue(workspaceRoot.mkdir()); + assertThat(workspaceRoot.mkdir()).isTrue(); - InitializeParams params = - new InitializeParamsBuilder().capabilities(new ClientCapabilitiesImpl()).processId(1) - .rootPath("test-directory-to-be-deleted").build(); + InitializeParams params = getInitializeParams(Optional.of("test-directory-to-be-deleted")); InitializeResult result = server.initialize(params).get(); assertInitializeResultIsCorrect(workspaceRoot.toPath(), result); // Test normalization - params = new InitializeParamsBuilder().capabilities(new ClientCapabilitiesImpl()).processId(1) - .rootPath("./test-directory-to-be-deleted").build(); + params = getInitializeParams(Optional.of("./test-directory-to-be-deleted")); result = server.initialize(params).get(); assertInitializeResultIsCorrect(workspaceRoot.toPath(), result); - params = new InitializeParamsBuilder().capabilities(new ClientCapabilitiesImpl()).processId(1) - .rootPath("somethingelse/../something/../test-directory-to-be-deleted").build(); + params = getInitializeParams(Optional.of("somethingelse/../something/../test-directory-to-be-deleted")); result = server.initialize(params).get(); assertInitializeResultIsCorrect(workspaceRoot.toPath(), result); // Delete the directory we created in our working directory - assertTrue(workspaceRoot.delete()); + assertThat(workspaceRoot.delete()).isTrue(); } private void assertInitializeResultIsCorrect(Path expectedWorkspaceRoot, InitializeResult result) { - assertThat(server.getWorkspaceRoot(), is(expectedWorkspaceRoot)); - assertThat(result.getCapabilities().getTextDocumentSync(), is(TextDocumentSyncKind.Incremental)); - assertTrue(result.getCapabilities().isDocumentSymbolProvider()); - assertTrue(result.getCapabilities().isWorkspaceSymbolProvider()); + assertThat(server.getWorkspaceRoot()).isEqualTo(expectedWorkspaceRoot); + assertThat(result.getCapabilities().getTextDocumentSync().getLeft()) + .isEqualTo(TextDocumentSyncKind.Incremental); + assertThat(result.getCapabilities().getDocumentSymbolProvider()).isTrue(); + assertThat(result.getCapabilities().getWorkspaceSymbolProvider()).isTrue(); } } diff --git a/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyTreeParserTest.java b/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyTreeParserTest.java index 961b928..1ab2026 100644 --- a/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyTreeParserTest.java +++ b/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyTreeParserTest.java @@ -16,8 +16,8 @@ package com.palantir.ls.groovy; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; import com.google.common.base.Optional; import com.google.common.collect.ImmutableSet; @@ -25,15 +25,6 @@ import com.palantir.ls.util.Ranges; import com.palantir.ls.util.UriSupplier; import com.palantir.ls.util.WorkspaceUriSupplier; -import io.typefox.lsapi.Location; -import io.typefox.lsapi.Range; -import io.typefox.lsapi.ReferenceParams; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.SymbolKind; -import io.typefox.lsapi.builders.LocationBuilder; -import io.typefox.lsapi.builders.ReferenceParamsBuilder; -import io.typefox.lsapi.builders.SymbolInformationBuilder; -import io.typefox.lsapi.impl.PositionImpl; import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -46,6 +37,14 @@ import java.util.Set; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.ReferenceContext; +import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.TextDocumentIdentifier; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -118,14 +117,14 @@ public void testComputeAllSymbols_class() throws InterruptedException, Execution // The symbols will contain a lot of inherited fields and methods, so we just check to make sure it contains our // custom fields and methods. - assertTrue(mapHasSymbol(symbols, Optional.absent(), "Coordinates", SymbolKind.Class)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "getAt", SymbolKind.Method)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "latitude", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "longitude", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "name", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("getAt"), "idx1", SymbolKind.Variable)); - assertTrue(mapHasSymbol(symbols, Optional.of("getAt"), "idx2", SymbolKind.Variable)); - assertTrue(mapHasSymbol(symbols, Optional.of("getAt"), "someString", SymbolKind.Variable)); + assertThat(mapHasSymbol(symbols, Optional.absent(), "Coordinates", SymbolKind.Class)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "getAt", SymbolKind.Method)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "latitude", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "longitude", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "name", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("getAt"), "idx1", SymbolKind.Variable)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("getAt"), "idx2", SymbolKind.Variable)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("getAt"), "someString", SymbolKind.Variable)).isTrue(); } @Test @@ -139,9 +138,9 @@ public void testComputeAllSymbols_interface() throws InterruptedException, Execu Map> symbols = parser.getFileSymbols(); // The symbols will contain a lot of inherited and default fields and methods, so we just check to make sure it // contains our custom fields and methods. - assertTrue(mapHasSymbol(symbols, Optional.absent(), "ICoordinates", SymbolKind.Interface)); - assertTrue(mapHasSymbol(symbols, Optional.of("ICoordinates"), "getAt", SymbolKind.Method)); - assertTrue(mapHasSymbol(symbols, Optional.of("getAt"), "idx", SymbolKind.Variable)); + assertThat(mapHasSymbol(symbols, Optional.absent(), "ICoordinates", SymbolKind.Interface)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("ICoordinates"), "getAt", SymbolKind.Method)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("getAt"), "idx", SymbolKind.Variable)).isTrue(); } @Test @@ -155,10 +154,10 @@ public void testComputeAllSymbols_enum() throws InterruptedException, ExecutionE Map> symbols = parser.getFileSymbols(); // The symbols will contain a lot of inherited and default fields and methods, so we just check to make sure it // contains our custom fields and methods. - assertTrue(mapHasSymbol(symbols, Optional.absent(), "Type", SymbolKind.Enum)); - assertTrue(mapHasSymbol(symbols, Optional.of("Type"), "ONE", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("Type"), "TWO", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("Type"), "THREE", SymbolKind.Field)); + assertThat(mapHasSymbol(symbols, Optional.absent(), "Type", SymbolKind.Enum)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Type"), "ONE", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Type"), "TWO", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Type"), "THREE", SymbolKind.Field)).isTrue(); } @Test @@ -186,19 +185,22 @@ public void testComputeAllSymbols_innerClassInterfaceEnum() Map> symbols = parser.getFileSymbols(); // The symbols will contain a lot of inherited fields and methods, so we just check to make sure it contains our // custom fields and methods. - assertTrue(mapHasSymbol(symbols, Optional.absent(), "Coordinates", SymbolKind.Class)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "getAt", SymbolKind.Method)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "latitude", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "longitude", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "name", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "Coordinates$MyInnerClass", SymbolKind.Class)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "Coordinates$MyInnerInterface", - SymbolKind.Interface)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates"), "Coordinates$MyInnerEnum", SymbolKind.Enum)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates$MyInnerEnum"), "ONE", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("Coordinates$MyInnerEnum"), "TWO", SymbolKind.Field)); - assertTrue(mapHasSymbol(symbols, Optional.of("getAt"), "idx", SymbolKind.Variable)); - assertTrue(mapHasSymbol(symbols, Optional.of("getAt"), "someString", SymbolKind.Variable)); + assertThat(mapHasSymbol(symbols, Optional.absent(), "Coordinates", SymbolKind.Class)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "getAt", SymbolKind.Method)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "latitude", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "longitude", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "name", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "Coordinates$MyInnerClass", SymbolKind.Class)) + .isTrue(); + assertThat( + mapHasSymbol(symbols, Optional.of("Coordinates"), "Coordinates$MyInnerInterface", SymbolKind.Interface)) + .isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates"), "Coordinates$MyInnerEnum", SymbolKind.Enum)) + .isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates$MyInnerEnum"), "ONE", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("Coordinates$MyInnerEnum"), "TWO", SymbolKind.Field)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("getAt"), "idx", SymbolKind.Variable)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("getAt"), "someString", SymbolKind.Variable)).isTrue(); } @Test @@ -215,9 +217,9 @@ public void testComputeAllSymbols_script() parser.parseAllSymbols(); Map> symbols = parser.getFileSymbols(); - assertTrue(mapHasSymbol(symbols, Optional.of("test"), "myMethod", SymbolKind.Method)); - assertTrue(mapHasSymbol(symbols, Optional.of("test"), "name", SymbolKind.Variable)); - assertTrue(mapHasSymbol(symbols, Optional.of("myMethod"), "someString", SymbolKind.Variable)); + assertThat(mapHasSymbol(symbols, Optional.of("test"), "myMethod", SymbolKind.Method)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("test"), "name", SymbolKind.Variable)).isTrue(); + assertThat(mapHasSymbol(symbols, Optional.of("myMethod"), "someString", SymbolKind.Variable)).isTrue(); } @Test @@ -242,58 +244,51 @@ public void testGetFilteredSymbols() throws InterruptedException, ExecutionExcep parser.parseAllSymbols(); Set filteredSymbols = parser.getFilteredSymbols("Coordinates"); - assertEquals(Sets.newHashSet(new SymbolInformationBuilder() - .name("Coordinates") - .kind(SymbolKind.Class) - .location(createLocation(coordinatesFiles.toPath(), Ranges.createRange(0, 0, 1, 0))) - .build()), filteredSymbols); + assertEquals(Sets.newHashSet(new SymbolInformation( + "Coordinates", + SymbolKind.Class, + createLocation(coordinatesFiles.toPath(), Ranges.createRange(0, 0, 1, 0)))), + filteredSymbols); filteredSymbols = parser.getFilteredSymbols("Coordinates*"); assertEquals(Sets.newHashSet( - new SymbolInformationBuilder() - .name("Coordinates") - .kind(SymbolKind.Class) - .location(createLocation(coordinatesFiles.toPath(), Ranges.createRange(0, 0, 1, 0))) - .build(), - new SymbolInformationBuilder() - .name("CoordinatesVar") - .kind(SymbolKind.Field) - .location(createLocation(coordinatesFiles.toPath(), Ranges.createRange(4, 3, 4, 32))) - .containerName("Coordinates") - .build()), + new SymbolInformation( + "Coordinates", + SymbolKind.Class, + createLocation(coordinatesFiles.toPath(), Ranges.createRange(0, 0, 1, 0))), + new SymbolInformation( + "CoordinatesVar", + SymbolKind.Field, + createLocation(coordinatesFiles.toPath(), Ranges.createRange(4, 3, 4, 32)), + "Coordinates")), filteredSymbols); filteredSymbols = parser.getFilteredSymbols("Coordinates?"); assertEquals(NO_SYMBOLS, filteredSymbols); filteredSymbols = parser.getFilteredSymbols("*Coordinates*"); - assertEquals(Sets.newHashSet( - new SymbolInformationBuilder() - .name("Coordinates") - .kind(SymbolKind.Class) - .location(createLocation(coordinatesFiles.toPath(), Ranges.createRange(0, 0, 1, 0))) - .build(), - new SymbolInformationBuilder() - .name("CoordinatesVar") - .kind(SymbolKind.Field) - .location(createLocation(coordinatesFiles.toPath(), Ranges.createRange(4, 3, 4, 32))) - .containerName("Coordinates") - .build(), - new SymbolInformationBuilder() - .name("ICoordinates") - .kind(SymbolKind.Interface) - .location(createLocation(icoordinatesFiles.toPath(), Ranges.createRange(0, 0, 1, 0))) - .build()), - filteredSymbols); + assertThat(filteredSymbols).containsExactlyInAnyOrder( + new SymbolInformation( + "Coordinates", + SymbolKind.Class, + createLocation(coordinatesFiles.toPath(), Ranges.createRange(0, 0, 1, 0))), + new SymbolInformation( + "ICoordinates", + SymbolKind.Interface, + createLocation(icoordinatesFiles.toPath(), Ranges.createRange(0, 0, 1, 0))), + new SymbolInformation( + "CoordinatesVar", + SymbolKind.Field, + createLocation(coordinatesFiles.toPath(), Ranges.createRange(4, 3, 4, 32)), + "Coordinates")); filteredSymbols = parser.getFilteredSymbols("Coordinates???"); assertEquals(Sets.newHashSet( - new SymbolInformationBuilder() - .name("CoordinatesVar") - .kind(SymbolKind.Field) - .location(createLocation(coordinatesFiles.toPath(), Ranges.createRange(4, 3, 4, 32))) - .containerName("Coordinates") - .build()), + new SymbolInformation( + "CoordinatesVar", + SymbolKind.Field, + createLocation(coordinatesFiles.toPath(), Ranges.createRange(4, 3, 4, 32)), + "Coordinates")), filteredSymbols); filteredSymbols = parser.getFilteredSymbols("Coordinates..."); assertEquals(NO_SYMBOLS, filteredSymbols); @@ -943,49 +938,37 @@ public void testGotoDefinition() throws IOException { parser.parseAllSymbols(); // InnerClass - Location expectedLocation = new LocationBuilder() - .uri(file.toPath().toUri().toString()) - .range(Ranges.createRange(2, 3, 3, 0)).build(); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(1, 15)).get()); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(10, 10)).get()); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(10, 31)).get()); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(12, 12)).get()); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(14, 11)).get()); + Location expectedLocation = new Location(file.toPath().toUri().toString(), Ranges.createRange(2, 3, 3, 0)); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(1, 15)).get()); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(10, 10)).get()); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(10, 31)).get()); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(12, 12)).get()); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(14, 11)).get()); // someStaticField - expectedLocation = new LocationBuilder() - .uri(file.toPath().toUri().toString()) - // TODO(#124): figure out how to make these more precise - .range(Ranges.createRange(1, 3, 1, 36)).build(); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(11, 15)).get()); + // TODO(#124): figure out how to make these more precise + expectedLocation = new Location(file.toPath().toUri().toString(), Ranges.createRange(1, 3, 1, 36)); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(11, 15)).get()); // localField - expectedLocation = new LocationBuilder() - .uri(file.toPath().toUri().toString()) - .range(Ranges.createRange(10, 17, 10, 27)).build(); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(13, 10)).get()); + expectedLocation = new Location(file.toPath().toUri().toString(), Ranges.createRange(10, 17, 10, 27)); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(13, 10)).get()); // myICNonStaticMethod - expectedLocation = new LocationBuilder() - .uri(file.toPath().toUri().toString()) - .range(Ranges.createRange(3, 6, 3, 35)).build(); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(11, 23)).get()); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(12, 23)).get()); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(13, 23)).get()); + expectedLocation = new Location(file.toPath().toUri().toString(), Ranges.createRange(3, 6, 3, 35)); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(11, 23)).get()); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(12, 23)).get()); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(13, 23)).get()); // myICStaticMethod - expectedLocation = new LocationBuilder() - .uri(file.toPath().toUri().toString()) - // TODO(#124): figure out how to make these more precise - .range(Ranges.createRange(4, 6, 4, 39)).build(); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(14, 20)).get()); + // TODO(#124): figure out how to make these more precise + expectedLocation = new Location(file.toPath().toUri().toString(), Ranges.createRange(4, 6, 4, 39)); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(14, 20)).get()); // test2 - expectedLocation = new LocationBuilder() - .uri(file.toPath().toUri().toString()) - // TODO(#124): figure out how to make these more precise - .range(Ranges.createRange(6, 3, 8, 4)).build(); - assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new PositionImpl(15, 20)).get()); + // TODO(#124): figure out how to make these more precise + expectedLocation = new Location(file.toPath().toUri().toString(), Ranges.createRange(6, 3, 8, 4)); + assertEquals(expectedLocation, parser.gotoDefinition(file.toURI(), new Position(15, 20)).get()); } @Test @@ -1004,26 +987,20 @@ public void testGotoDefinition_multipleFiles() throws IOException { parser.parseAllSymbols(); // Dog class - Location expectedLocation = new LocationBuilder() - .uri(dog.toPath().toUri().toString()) - .range(Ranges.createRange(0, 0, 0, 19)).build(); - assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new PositionImpl(1, 18))); - assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new PositionImpl(2, 18))); - assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new PositionImpl(3, 8))); - assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new PositionImpl(3, 25))); + Location expectedLocation = new Location(dog.toPath().toUri().toString(), Ranges.createRange(0, 0, 0, 19)); + assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(1, 18))); + assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(2, 18))); + assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(3, 8))); + assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(3, 25))); // newDog local variable - expectedLocation = new LocationBuilder() - .uri(cat.toPath().toUri().toString()) - .range(Ranges.createRange(3, 11, 3, 17)).build(); - assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new PositionImpl(5, 18))); + expectedLocation = new Location(cat.toPath().toUri().toString(), Ranges.createRange(3, 11, 3, 17)); + assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(5, 18))); // foo method - expectedLocation = new LocationBuilder() - .uri(cat.toPath().toUri().toString()) - // TODO(#124): make this more accurate - .range(Ranges.createRange(2, 3, 6, 4)).build(); - assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new PositionImpl(4, 10))); + // TODO(#124): make this more accurate + expectedLocation = new Location(cat.toPath().toUri().toString(), Ranges.createRange(2, 3, 6, 4)); + assertEquals(Optional.of(expectedLocation), parser.gotoDefinition(cat.toURI(), new Position(4, 10))); } private boolean mapHasSymbol(Map> map, Optional container, String fieldName, @@ -1049,14 +1026,14 @@ private static File addFileToFolder(File root, String parent, String filename, S } private static Location createLocation(Path path, Range range) { - return new LocationBuilder().uri(path.toUri().toString()).range(range).build(); + return new Location(path.toUri().toString(), range); } private static ReferenceParams createReferenceParams(URI uri, int line, int col, boolean includeDeclaration) { - return new ReferenceParamsBuilder() - .context(includeDeclaration) - .textDocument(uri.toString()) - .position(line, col).build(); + ReferenceParams referenceParams = new ReferenceParams(new ReferenceContext(includeDeclaration)); + referenceParams.setTextDocument(new TextDocumentIdentifier(uri.toString())); + referenceParams.setPosition(new Position(line, col)); + return referenceParams; } } diff --git a/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyWorkspaceCompilerTest.java b/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyWorkspaceCompilerTest.java index 3cd7712..718fe66 100644 --- a/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyWorkspaceCompilerTest.java +++ b/groovy-language-server/src/test/java/com/palantir/ls/groovy/GroovyWorkspaceCompilerTest.java @@ -16,23 +16,16 @@ package com.palantir.ls.groovy; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Iterators; import com.google.common.collect.Lists; import com.google.common.collect.Sets; -import com.palantir.ls.groovy.util.DefaultDiagnosticBuilder; +import com.palantir.ls.groovy.util.GroovyConstants; import com.palantir.ls.util.Ranges; -import io.typefox.lsapi.Diagnostic; -import io.typefox.lsapi.DiagnosticSeverity; -import io.typefox.lsapi.FileChangeType; -import io.typefox.lsapi.PublishDiagnosticsParams; -import io.typefox.lsapi.builders.FileEventBuilder; -import io.typefox.lsapi.builders.PublishDiagnosticsParamsBuilder; -import io.typefox.lsapi.builders.TextDocumentContentChangeEventBuilder; import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -46,6 +39,12 @@ import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; import org.codehaus.groovy.control.SourceUnit; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.FileChangeType; +import org.eclipse.lsp4j.FileEvent; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -53,7 +52,7 @@ public class GroovyWorkspaceCompilerTest { - private static final Set NO_ERRORS = Sets.newHashSet(); + private static final Set NO_ERRORS = Sets.newHashSet(); @Rule public ExpectedException expectedException = ExpectedException.none(); @@ -176,13 +175,12 @@ public void testCompile_WithJavaExtensionError() throws InterruptedException, Ex GroovyWorkspaceCompiler compiler = createGroovyWorkspaceCompiler(); Set diagnostics = compiler.compile(ImmutableSet.of()); - assertEquals(Sets.newHashSet(new PublishDiagnosticsParamsBuilder() - .uri(test.toPath().toUri().toString()) - .diagnostic(new DefaultDiagnosticBuilder( - "unable to resolve class Foo \n @ line 1, column 20.", DiagnosticSeverity.Error) - .range(Ranges.createRange(0, 19, 0, 26)) - .build()) - .build()), + assertEquals(Sets.newHashSet(new PublishDiagnosticsParams( + test.toPath().toUri().toString(), + ImmutableList.of(new Diagnostic(Ranges.createRange(0, 19, 0, 26), + "unable to resolve class Foo \n @ line 1, column 20.", + DiagnosticSeverity.Error, + GroovyConstants.GROOVY_COMPILER)))), diagnostics); } @@ -247,24 +245,21 @@ public void testCompile_error() throws InterruptedException, ExecutionException, Set diagnostics = compiler.compile(ImmutableSet.of()); Set expectedDiagnostics = Sets.newHashSet( - new PublishDiagnosticsParamsBuilder() - .uri(test1.toPath().toUri().toString()) - .diagnostic( - new DefaultDiagnosticBuilder( + new PublishDiagnosticsParams(test1.toPath().toUri().toString(), + ImmutableList.of( + new Diagnostic( + Ranges.createRange(6, 17, 6, 72), "unable to resolve class ExceptionNew1 \n @ line 7, column 18.", - DiagnosticSeverity.Error) - .range(Ranges.createRange(6, 17, 6, 72)) - .build()) - .build(), - new PublishDiagnosticsParamsBuilder() - .uri(test2.toPath().toUri().toString()) - .diagnostic( - new DefaultDiagnosticBuilder( + DiagnosticSeverity.Error, + GroovyConstants.GROOVY_COMPILER))), + new PublishDiagnosticsParams(test2.toPath().toUri().toString(), + ImmutableList.of( + new Diagnostic( + Ranges.createRange(6, 17, 6, 74), "unable to resolve class ExceptionNew222 \n @ line 7, column 18.", - DiagnosticSeverity.Error) - .range(Ranges.createRange(6, 17, 6, 74)) - .build()) - .build()); + DiagnosticSeverity.Error, + GroovyConstants.GROOVY_COMPILER)))); + assertEquals(expectedDiagnostics, diagnostics); } @@ -283,8 +278,8 @@ public void testHandleFileChanged() throws IOException { assertSingleSourceFileUri(catFile, compiler.get().iterator()); // First change - compiler.handleFileChanged(catFile.toURI(), Lists.newArrayList(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 6, 0, 9)).rangeLength(3).text("Dog").build())); + compiler.handleFileChanged(catFile.toURI(), + Lists.newArrayList(new TextDocumentContentChangeEvent(Ranges.createRange(0, 6, 0, 9), 3, "Dog"))); // Re-compile assertEquals(NO_ERRORS, compiler.compile(ImmutableSet.of())); @@ -297,8 +292,8 @@ public void testHandleFileChanged() throws IOException { assertSingleSourceFileUri(catChangedFile, compiler.get().iterator()); // Second change - compiler.handleFileChanged(catFile.toURI(), Lists.newArrayList(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 6, 0, 9)).rangeLength(6).text("Turtle").build())); + compiler.handleFileChanged(catFile.toURI(), + Lists.newArrayList(new TextDocumentContentChangeEvent(Ranges.createRange(0, 6, 0, 9), 6, "Turtle"))); // Re-compile assertEquals(NO_ERRORS, compiler.compile(ImmutableSet.of())); @@ -329,8 +324,8 @@ public void testHandleFileClosed() throws IOException { // First change - compiler.handleFileChanged(catFile.toURI(), Lists.newArrayList(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 6, 0, 9)).rangeLength(3).text("Dog").build())); + compiler.handleFileChanged(catFile.toURI(), + Lists.newArrayList(new TextDocumentContentChangeEvent(Ranges.createRange(0, 6, 0, 9), 3, "Dog"))); // Re-compile assertEquals(NO_ERRORS, compiler.compile(ImmutableSet.of())); @@ -346,8 +341,11 @@ public void testHandleFileClosed() throws IOException { // Assert file contents assertEquals("class Cat {\n}\n", FileUtils.readFileToString(catFile)); // The changed file should have been deleted - assertFalse(changedOutput.getRoot().toPath().resolve(root.getRoot().toPath().relativize(catFile.toPath())) - .toFile().exists()); + assertThat(changedOutput.getRoot() + .toPath() + .resolve(root.getRoot().toPath().relativize(catFile.toPath())) + .toFile().exists()) + .isFalse(); // Re-compile assertEquals(NO_ERRORS, compiler.compile(ImmutableSet.of())); @@ -372,8 +370,8 @@ public void testHandleFileSaved() throws IOException { assertSingleSourceFileUri(catFile, compiler.get().iterator()); // First change - compiler.handleFileChanged(catFile.toURI(), Lists.newArrayList(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 6, 0, 9)).rangeLength(3).text("Dog").build())); + compiler.handleFileChanged(catFile.toURI(), + Lists.newArrayList(new TextDocumentContentChangeEvent(Ranges.createRange(0, 6, 0, 9), 3, "Dog"))); // Assert file contents assertEquals("class Cat {\n}\n", FileUtils.readFileToString(catFile)); assertEquals("class Dog {\n}\n", FileUtils.readFileToString(catChangedFile)); @@ -414,8 +412,8 @@ public void testHandleChangeWatchedFiles_changed() throws IOException { assertSingleSourceFileUri(catFile, compiler.get().iterator()); // First change - compiler.handleFileChanged(catFile.toURI(), Lists.newArrayList(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 6, 0, 9)).rangeLength(3).text("Dog").build())); + compiler.handleFileChanged(catFile.toURI(), + Lists.newArrayList(new TextDocumentContentChangeEvent(Ranges.createRange(0, 6, 0, 9), 3, "Dog"))); // Assert file contents assertEquals("class Cat {\n}\n", FileUtils.readFileToString(catFile)); assertEquals("class Dog {\n}\n", FileUtils.readFileToString(catChangedFile)); @@ -428,13 +426,16 @@ public void testHandleChangeWatchedFiles_changed() throws IOException { // Call handleChangeWatchedFile with a change saying this file has been changed outside this language server compiler.handleChangeWatchedFiles(Lists.newArrayList( - new FileEventBuilder().uri(root.getRoot().toPath().relativize(catFile.toPath()).toString()) - .type(FileChangeType.Changed).build())); + new FileEvent( + root.getRoot().toPath().relativize(catFile.toPath()).toString(), + FileChangeType.Changed))); // Assert file contents assertEquals("class Cat {\n}\n", FileUtils.readFileToString(catFile)); // The changed file should have been deleted - assertFalse(changedOutput.getRoot().toPath().resolve(root.getRoot().toPath().relativize(catFile.toPath())) - .toFile().exists()); + assertThat(changedOutput.getRoot() + .toPath() + .resolve(root.getRoot().toPath().relativize(catFile.toPath())).toFile().exists()) + .isFalse(); // Re-compile assertEquals(NO_ERRORS, compiler.compile(ImmutableSet.of())); @@ -457,18 +458,19 @@ public void testHandleChangeWatchedFiles_deleted() throws IOException { assertSingleSourceFileUri(catFile, compiler.get().iterator()); // Delete the file - assertTrue(catFile.delete()); + assertThat(catFile.delete()).isTrue(); // Call handleChangeWatchedFile with a change saying this file has been deleted outside this language server compiler.handleChangeWatchedFiles(Lists.newArrayList( - new FileEventBuilder().uri(root.getRoot().toPath().relativize(catFile.toPath()).toString()) - .type(FileChangeType.Changed).build())); + new FileEvent( + root.getRoot().toPath().relativize(catFile.toPath()).toString(), + FileChangeType.Changed))); // Re-compile assertEquals(NO_ERRORS, compiler.compile(ImmutableSet.of())); // Assert the compiler has no source units - assertFalse(compiler.get().iterator().hasNext()); + assertThat(compiler.get().iterator().hasNext()).isFalse(); } @Test @@ -479,7 +481,7 @@ public void testHandleChangeWatchedFiles_created() throws IOException { assertEquals(NO_ERRORS, compiler.compile(ImmutableSet.of())); // Assert the compiler has no source units - assertFalse(compiler.get().iterator().hasNext()); + assertThat(compiler.get().iterator().hasNext()).isFalse(); File catFile = addFileToFolder(newFolder1, "Cat.groovy", "class Cat {\n" @@ -487,8 +489,9 @@ public void testHandleChangeWatchedFiles_created() throws IOException { // Call handleChangeWatchedFile with a change saying this file has been changed outside this language server compiler.handleChangeWatchedFiles(Lists.newArrayList( - new FileEventBuilder().uri(root.getRoot().toPath().relativize(catFile.toPath()).toString()) - .type(FileChangeType.Created).build())); + new FileEvent( + root.getRoot().toPath().relativize(catFile.toPath()).toString(), + FileChangeType.Created))); // Re-compile assertEquals(NO_ERRORS, compiler.compile(ImmutableSet.of())); diff --git a/groovy-language-server/src/test/java/com/palantir/ls/groovy/util/DefaultDiagnosticBuilderTest.java b/groovy-language-server/src/test/java/com/palantir/ls/groovy/util/DefaultDiagnosticBuilderTest.java deleted file mode 100644 index 1ab8757..0000000 --- a/groovy-language-server/src/test/java/com/palantir/ls/groovy/util/DefaultDiagnosticBuilderTest.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2016 Palantir Technologies, Inc. All rights reserved. - * - * Licensed 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 com.palantir.ls.groovy.util; - -import static org.hamcrest.Matchers.is; -import static org.junit.Assert.assertThat; - -import com.palantir.ls.util.Ranges; -import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.typefox.lsapi.Diagnostic; -import io.typefox.lsapi.DiagnosticSeverity; -import io.typefox.lsapi.Range; -import org.junit.Rule; -import org.junit.Test; -import org.junit.rules.ExpectedException; - -public class DefaultDiagnosticBuilderTest { - - @Rule - public ExpectedException expectedException = ExpectedException.none(); - - @SuppressFBWarnings("NP_NULL_PARAM_DEREF") - @Test - public void testExceptionOnNullMessage() { - expectedException.expect(NullPointerException.class); - expectedException.expectMessage("message cannot be null"); - new DefaultDiagnosticBuilder(null, DiagnosticSeverity.Error).build(); - } - - @Test - public void testDefaults() { - Diagnostic diagnostic = new DefaultDiagnosticBuilder("message", DiagnosticSeverity.Error).build(); - assertThat(diagnostic.getMessage(), is("message")); - assertThat(diagnostic.getSeverity(), is(DiagnosticSeverity.Error)); - assertThat(diagnostic.getRange(), is(Ranges.UNDEFINED_RANGE)); - assertThat(diagnostic.getSource(), is("groovyc")); - } - - @Test - public void testOverrideDefaults() { - Range expectedRange = Ranges.createRange(0, 0, 1, 1); - Diagnostic diagnostic = new DefaultDiagnosticBuilder("message", DiagnosticSeverity.Error) - .range(expectedRange) - .source("foo") - .build(); - assertThat(diagnostic.getMessage(), is("message")); - assertThat(diagnostic.getSeverity(), is(DiagnosticSeverity.Error)); - assertThat(diagnostic.getRange(), is(expectedRange)); - assertThat(diagnostic.getSource(), is("foo")); - } - -} diff --git a/language-server-commons/build.gradle b/language-server-commons/build.gradle index 0486e75..fc7df76 100644 --- a/language-server-commons/build.gradle +++ b/language-server-commons/build.gradle @@ -10,12 +10,11 @@ dependencies { compile "com.google.guava:guava:${guavaVersion}" compile "commons-io:commons-io:${commonsIoVersion}" compile "org.slf4j:slf4j-api:${slf4jApiVersion}" - compile "io.typefox.lsapi:io.typefox.lsapi:${typefoxLsApiVersion}" - compile "io.typefox.lsapi:io.typefox.lsapi.annotations:${typefoxLsApiVersion}" - compile "io.typefox.lsapi:io.typefox.lsapi.services:${typefoxLsApiVersion}" + compile "org.eclipse.lsp4j:org.eclipse.lsp4j:${lsApiVersion}" + compile "org.eclipse.lsp4j:org.eclipse.lsp4j.jsonrpc:${lsApiVersion}" testCompile "junit:junit:${junitVersion}" testCompile "org.hamcrest:hamcrest-all:${hamcrestVersion}" testCompile "org.mockito:mockito-core:${mockitoVersion}" + testCompile "org.assertj:assertj-core:${assertjVersion}" } - diff --git a/language-server-commons/src/main/java/com/palantir/ls/AbstractLanguageServerState.java b/language-server-commons/src/main/java/com/palantir/ls/AbstractLanguageServerState.java index eabd792..476911f 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/AbstractLanguageServerState.java +++ b/language-server-commons/src/main/java/com/palantir/ls/AbstractLanguageServerState.java @@ -18,11 +18,11 @@ import com.palantir.ls.api.CompilerWrapper; import com.palantir.ls.api.LanguageServerState; -import io.typefox.lsapi.MessageParams; -import io.typefox.lsapi.PublishDiagnosticsParams; -import io.typefox.lsapi.ShowMessageRequestParams; import java.util.Set; import java.util.function.Consumer; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.ShowMessageRequestParams; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/language-server-commons/src/main/java/com/palantir/ls/DefaultCompilerWrapper.java b/language-server-commons/src/main/java/com/palantir/ls/DefaultCompilerWrapper.java index 81d4c88..bd50c11 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/DefaultCompilerWrapper.java +++ b/language-server-commons/src/main/java/com/palantir/ls/DefaultCompilerWrapper.java @@ -20,18 +20,18 @@ import com.palantir.ls.api.CompilerWrapper; import com.palantir.ls.api.TreeParser; import com.palantir.ls.api.WorkspaceCompiler; -import io.typefox.lsapi.CompletionList; -import io.typefox.lsapi.FileEvent; -import io.typefox.lsapi.Location; -import io.typefox.lsapi.Position; -import io.typefox.lsapi.PublishDiagnosticsParams; -import io.typefox.lsapi.ReferenceParams; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.TextDocumentContentChangeEvent; import java.net.URI; import java.util.List; import java.util.Map; import java.util.Set; +import org.eclipse.lsp4j.CompletionList; +import org.eclipse.lsp4j.FileEvent; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; /** * Wraps a WorkspaceCompiler and TreeParser. Ensures the tree is updated when the compiler is compiled successfully. diff --git a/language-server-commons/src/main/java/com/palantir/ls/StreamLanguageServerLauncher.java b/language-server-commons/src/main/java/com/palantir/ls/StreamLanguageServerLauncher.java index 0919076..9417bbd 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/StreamLanguageServerLauncher.java +++ b/language-server-commons/src/main/java/com/palantir/ls/StreamLanguageServerLauncher.java @@ -16,49 +16,41 @@ package com.palantir.ls; -import com.palantir.ls.util.LoggerMessageTracer; -import io.typefox.lsapi.services.LanguageServer; -import io.typefox.lsapi.services.json.MessageJsonHandler; -import io.typefox.lsapi.services.json.StreamMessageReader; -import io.typefox.lsapi.services.json.StreamMessageWriter; -import io.typefox.lsapi.services.transport.io.ConcurrentMessageReader; -import io.typefox.lsapi.services.transport.io.MessageReader; -import io.typefox.lsapi.services.transport.io.MessageWriter; -import io.typefox.lsapi.services.transport.server.LanguageServerEndpoint; +import com.palantir.ls.util.DelegatingOutputStream; +import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; import java.io.InputStream; import java.io.OutputStream; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.io.PrintWriter; +import org.eclipse.lsp4j.jsonrpc.Launcher; +import org.eclipse.lsp4j.launch.LSPLauncher; +import org.eclipse.lsp4j.services.LanguageClient; +import org.eclipse.lsp4j.services.LanguageServer; import org.slf4j.Logger; +import org.slf4j.LoggerFactory; public class StreamLanguageServerLauncher { - private final LanguageServerEndpoint languageServerEndpoint; + private static final Logger log = LoggerFactory.getLogger(StreamLanguageServerLauncher.class); + private final InputStream inputStream; private final OutputStream outputStream; - private final ExecutorService executorService; - private final MessageJsonHandler jsonHandler; + private final LanguageServer languageServer; public StreamLanguageServerLauncher(LanguageServer languageServer, InputStream in, OutputStream out) { - this.languageServerEndpoint = new LanguageServerEndpoint(languageServer); + this.languageServer = languageServer; this.inputStream = in; this.outputStream = out; - this.executorService = Executors.newCachedThreadPool(); - this.jsonHandler = new MessageJsonHandler(); - } - - public void setLogger(Logger logger) { - languageServerEndpoint.setMessageTracer(new LoggerMessageTracer(logger)); } + @SuppressFBWarnings("DM_DEFAULT_ENCODING") public void launch() { - MessageReader reader = new StreamMessageReader(inputStream, jsonHandler); - ConcurrentMessageReader concurrentReader = new ConcurrentMessageReader(reader, executorService); - MessageWriter writer = new StreamMessageWriter(outputStream, jsonHandler); - - languageServerEndpoint.connect(concurrentReader, writer); - - concurrentReader.join(); + Launcher serverLauncher = LSPLauncher.createServerLauncher( + languageServer, + inputStream, + outputStream, + false, + new PrintWriter(new DelegatingOutputStream(log::info))); + serverLauncher.startListening(); } } diff --git a/language-server-commons/src/main/java/com/palantir/ls/api/LanguageServerState.java b/language-server-commons/src/main/java/com/palantir/ls/api/LanguageServerState.java index be62944..356de17 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/api/LanguageServerState.java +++ b/language-server-commons/src/main/java/com/palantir/ls/api/LanguageServerState.java @@ -16,11 +16,11 @@ package com.palantir.ls.api; -import io.typefox.lsapi.MessageParams; -import io.typefox.lsapi.PublishDiagnosticsParams; -import io.typefox.lsapi.ShowMessageRequestParams; import java.util.Set; import java.util.function.Consumer; +import org.eclipse.lsp4j.MessageParams; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.ShowMessageRequestParams; /** * Used to share compilation state and message callbacks between Language Server services. diff --git a/language-server-commons/src/main/java/com/palantir/ls/api/TreeParser.java b/language-server-commons/src/main/java/com/palantir/ls/api/TreeParser.java index 84c9321..942bf58 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/api/TreeParser.java +++ b/language-server-commons/src/main/java/com/palantir/ls/api/TreeParser.java @@ -17,16 +17,16 @@ package com.palantir.ls.api; import com.google.common.base.Optional; -import io.typefox.lsapi.CompletionList; -import io.typefox.lsapi.Location; -import io.typefox.lsapi.Position; -import io.typefox.lsapi.ReferenceParams; -import io.typefox.lsapi.SymbolInformation; import java.net.URI; import java.util.Map; import java.util.Set; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; +import org.eclipse.lsp4j.CompletionList; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.SymbolInformation; /** * Provides functionality to fulfill all symbol related Language Server requests. diff --git a/language-server-commons/src/main/java/com/palantir/ls/api/WorkspaceCompiler.java b/language-server-commons/src/main/java/com/palantir/ls/api/WorkspaceCompiler.java index 946db8f..6aff39d 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/api/WorkspaceCompiler.java +++ b/language-server-commons/src/main/java/com/palantir/ls/api/WorkspaceCompiler.java @@ -16,12 +16,12 @@ package com.palantir.ls.api; -import io.typefox.lsapi.FileEvent; -import io.typefox.lsapi.PublishDiagnosticsParams; -import io.typefox.lsapi.TextDocumentContentChangeEvent; import java.net.URI; import java.util.List; import java.util.Set; +import org.eclipse.lsp4j.FileEvent; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; /** * Provides wrapper methods for compiling a workspace, handles incremental changes, and returns Language Server Protocol diff --git a/language-server-commons/src/main/java/com/palantir/ls/services/AbstractTextDocumentService.java b/language-server-commons/src/main/java/com/palantir/ls/services/AbstractTextDocumentService.java index 0c1e5d6..3040deb 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/services/AbstractTextDocumentService.java +++ b/language-server-commons/src/main/java/com/palantir/ls/services/AbstractTextDocumentService.java @@ -24,40 +24,39 @@ import com.palantir.ls.api.LanguageServerState; import com.palantir.ls.util.Ranges; import com.palantir.ls.util.Uris; -import io.typefox.lsapi.CodeActionParams; -import io.typefox.lsapi.CodeLens; -import io.typefox.lsapi.CodeLensParams; -import io.typefox.lsapi.Command; -import io.typefox.lsapi.CompletionItem; -import io.typefox.lsapi.CompletionList; -import io.typefox.lsapi.DidChangeTextDocumentParams; -import io.typefox.lsapi.DidCloseTextDocumentParams; -import io.typefox.lsapi.DidOpenTextDocumentParams; -import io.typefox.lsapi.DidSaveTextDocumentParams; -import io.typefox.lsapi.DocumentFormattingParams; -import io.typefox.lsapi.DocumentHighlight; -import io.typefox.lsapi.DocumentOnTypeFormattingParams; -import io.typefox.lsapi.DocumentRangeFormattingParams; -import io.typefox.lsapi.DocumentSymbolParams; -import io.typefox.lsapi.Hover; -import io.typefox.lsapi.Location; -import io.typefox.lsapi.PublishDiagnosticsParams; -import io.typefox.lsapi.ReferenceParams; -import io.typefox.lsapi.RenameParams; -import io.typefox.lsapi.SignatureHelp; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.TextDocumentPositionParams; -import io.typefox.lsapi.TextEdit; -import io.typefox.lsapi.WorkspaceEdit; -import io.typefox.lsapi.services.TextDocumentService; import java.io.File; import java.net.URI; import java.nio.file.Path; import java.nio.file.Paths; import java.util.List; import java.util.concurrent.CompletableFuture; -import java.util.function.Consumer; import java.util.stream.Collectors; +import org.eclipse.lsp4j.CodeActionParams; +import org.eclipse.lsp4j.CodeLens; +import org.eclipse.lsp4j.CodeLensParams; +import org.eclipse.lsp4j.Command; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionList; +import org.eclipse.lsp4j.DidChangeTextDocumentParams; +import org.eclipse.lsp4j.DidCloseTextDocumentParams; +import org.eclipse.lsp4j.DidOpenTextDocumentParams; +import org.eclipse.lsp4j.DidSaveTextDocumentParams; +import org.eclipse.lsp4j.DocumentFormattingParams; +import org.eclipse.lsp4j.DocumentHighlight; +import org.eclipse.lsp4j.DocumentOnTypeFormattingParams; +import org.eclipse.lsp4j.DocumentRangeFormattingParams; +import org.eclipse.lsp4j.DocumentSymbolParams; +import org.eclipse.lsp4j.Hover; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.RenameParams; +import org.eclipse.lsp4j.SignatureHelp; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.TextDocumentPositionParams; +import org.eclipse.lsp4j.TextEdit; +import org.eclipse.lsp4j.WorkspaceEdit; +import org.eclipse.lsp4j.jsonrpc.messages.Either; +import org.eclipse.lsp4j.services.TextDocumentService; /** * Provides a default implemented not dissimilar to to antlr generated visitors. @@ -103,11 +102,6 @@ public final void didSave(DidSaveTextDocumentParams params) { getState().publishDiagnostics(getState().getCompilerWrapper().compile(ImmutableSet.of(uri))); } - @Override - public final void onPublishDiagnostics(Consumer callback) { - getState().setPublishDiagnostics(callback); - } - final Path getWorkspacePath() { return Paths.get(getState().getCompilerWrapper().getWorkspaceRoot()); } @@ -172,9 +166,13 @@ public CompletableFuture rename(RenameParams params) { } @Override - public CompletableFuture completion(TextDocumentPositionParams position) { - return CompletableFuture.completedFuture(getState().getCompilerWrapper().getCompletion( - Uris.resolveToRoot(getWorkspacePath(), position.getTextDocument().getUri()), position.getPosition())); + public CompletableFuture, CompletionList>> completion( + TextDocumentPositionParams position) { + return CompletableFuture.completedFuture(Either.forRight( + getState().getCompilerWrapper() + .getCompletion( + Uris.resolveToRoot(getWorkspacePath(), position.getTextDocument().getUri()), + position.getPosition()))); } @Override diff --git a/language-server-commons/src/main/java/com/palantir/ls/services/AbstractWindowService.java b/language-server-commons/src/main/java/com/palantir/ls/services/AbstractWindowService.java deleted file mode 100644 index 6696aa9..0000000 --- a/language-server-commons/src/main/java/com/palantir/ls/services/AbstractWindowService.java +++ /dev/null @@ -1,44 +0,0 @@ -/* - * Copyright 2016 Palantir Technologies, Inc. All rights reserved. - * - * Licensed 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 com.palantir.ls.services; - -import com.palantir.ls.api.LanguageServerState; -import io.typefox.lsapi.MessageParams; -import io.typefox.lsapi.ShowMessageRequestParams; -import io.typefox.lsapi.services.WindowService; -import java.util.function.Consumer; - -public abstract class AbstractWindowService implements WindowService { - - protected abstract LanguageServerState getState(); - - @Override - public final void onShowMessage(Consumer callback) { - getState().setShowMessage(callback); - } - - @Override - public final void onShowMessageRequest(Consumer callback) { - getState().setShowMessageRequest(callback); - } - - @Override - public final void onLogMessage(Consumer callback) { - getState().setLogMessage(callback); - } - -} diff --git a/language-server-commons/src/main/java/com/palantir/ls/services/AbstractWorkspaceService.java b/language-server-commons/src/main/java/com/palantir/ls/services/AbstractWorkspaceService.java index 573fe25..a0fde47 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/services/AbstractWorkspaceService.java +++ b/language-server-commons/src/main/java/com/palantir/ls/services/AbstractWorkspaceService.java @@ -18,16 +18,16 @@ import com.palantir.ls.api.LanguageServerState; import com.palantir.ls.util.Ranges; -import io.typefox.lsapi.DidChangeConfigurationParams; -import io.typefox.lsapi.DidChangeWatchedFilesParams; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.WorkspaceSymbolParams; -import io.typefox.lsapi.services.WorkspaceService; import java.net.URI; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; +import org.eclipse.lsp4j.DidChangeConfigurationParams; +import org.eclipse.lsp4j.DidChangeWatchedFilesParams; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.WorkspaceSymbolParams; +import org.eclipse.lsp4j.services.WorkspaceService; public abstract class AbstractWorkspaceService implements WorkspaceService { diff --git a/language-server-commons/src/main/java/com/palantir/ls/services/DefaultWindowService.java b/language-server-commons/src/main/java/com/palantir/ls/services/DefaultWindowService.java deleted file mode 100644 index d2e2a94..0000000 --- a/language-server-commons/src/main/java/com/palantir/ls/services/DefaultWindowService.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Copyright 2016 Palantir Technologies, Inc. All rights reserved. - * - * Licensed 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 com.palantir.ls.services; - -import com.palantir.ls.api.LanguageServerState; - -public class DefaultWindowService extends AbstractWindowService { - private final LanguageServerState state; - - public DefaultWindowService(LanguageServerState state) { - this.state = state; - } - - @Override - protected LanguageServerState getState() { - return state; - } -} diff --git a/language-server-commons/src/main/java/com/palantir/ls/util/CompletionUtils.java b/language-server-commons/src/main/java/com/palantir/ls/util/CompletionUtils.java index c0ea1b9..19b37ef 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/util/CompletionUtils.java +++ b/language-server-commons/src/main/java/com/palantir/ls/util/CompletionUtils.java @@ -16,29 +16,28 @@ package com.palantir.ls.util; -import com.google.common.collect.Lists; -import io.typefox.lsapi.CompletionItemKind; -import io.typefox.lsapi.CompletionList; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.SymbolKind; -import io.typefox.lsapi.builders.CompletionItemBuilder; -import io.typefox.lsapi.builders.CompletionListBuilder; -import io.typefox.lsapi.impl.CompletionListImpl; import java.util.Set; +import java.util.stream.Collectors; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionItemKind; +import org.eclipse.lsp4j.CompletionList; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; public final class CompletionUtils { public static CompletionList createCompletionListFromSymbols(Set symbols) { if (symbols == null) { - return new CompletionListImpl(false, Lists.newArrayList()); + return new CompletionList(); } - CompletionListBuilder builder = new CompletionListBuilder().isIncomplete(false); - symbols.forEach(symbol -> { - builder.item(new CompletionItemBuilder() - .label(symbol.getName()) - .kind(symbolKindToCompletionItemKind(symbol.getKind())) - .build()); - }); - return builder.build(); + return new CompletionList( + false, + symbols.stream() + .map(symbol -> { + CompletionItem item = new CompletionItem(symbol.getName()); + item.setKind(symbolKindToCompletionItemKind(symbol.getKind())); + return item; + }) + .collect(Collectors.toList())); } @SuppressWarnings("checkstyle:cyclomaticcomplexity") // this is not complex behaviour diff --git a/language-server-commons/src/main/java/com/palantir/ls/util/DelegatingOutputStream.java b/language-server-commons/src/main/java/com/palantir/ls/util/DelegatingOutputStream.java new file mode 100644 index 0000000..147f726 --- /dev/null +++ b/language-server-commons/src/main/java/com/palantir/ls/util/DelegatingOutputStream.java @@ -0,0 +1,67 @@ +/* + * Copyright 2017 Palantir Technologies, Inc. All rights reserved. + * + * Licensed 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 com.palantir.ls.util; + +import static com.google.common.base.Preconditions.checkState; + +import java.io.IOException; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.util.function.Consumer; + +public class DelegatingOutputStream extends OutputStream { + + private static final int DEFAULT_BUFFER_LENGTH = 4096; + + private final Consumer logger; + + private byte[] buffer = new byte[DEFAULT_BUFFER_LENGTH]; + private int count = 0; + private int currentBufferSize = DEFAULT_BUFFER_LENGTH; + private boolean closed = false; + + public DelegatingOutputStream(Consumer logger) { + this.logger = logger; + } + + @Override + public void write(final int byteToWrite) throws IOException { + checkState(!closed, "Attempted to write to a closed stream."); + if (count >= currentBufferSize) { + int newSize = currentBufferSize + DEFAULT_BUFFER_LENGTH; + byte[] newBuffer = new byte[newSize]; + System.arraycopy(buffer, 0, newBuffer, 0, currentBufferSize); + buffer = newBuffer; + currentBufferSize = newSize; + } + buffer[count] = (byte) byteToWrite; + count++; + } + + @Override + public void flush() { + String str = new String(buffer, StandardCharsets.UTF_8); + logger.accept(str); + count = 0; + } + + @Override + public void close() throws IOException { + flush(); + closed = true; + } +} diff --git a/language-server-commons/src/main/java/com/palantir/ls/util/LoggerMessageTracer.java b/language-server-commons/src/main/java/com/palantir/ls/util/LoggerMessageTracer.java deleted file mode 100644 index 6185ba5..0000000 --- a/language-server-commons/src/main/java/com/palantir/ls/util/LoggerMessageTracer.java +++ /dev/null @@ -1,72 +0,0 @@ -/* - * Copyright 2016 Palantir Technologies, Inc. All rights reserved. - * - * Licensed 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 com.palantir.ls.util; - -import io.typefox.lsapi.Message; -import io.typefox.lsapi.NotificationMessage; -import io.typefox.lsapi.RequestMessage; -import io.typefox.lsapi.ResponseMessage; -import io.typefox.lsapi.services.transport.trace.MessageTracer; -import java.io.PrintWriter; -import java.io.StringWriter; -import org.slf4j.Logger; - -public class LoggerMessageTracer implements MessageTracer { - - private final Logger logger; - - public LoggerMessageTracer(Logger logger) { - this.logger = logger; - } - - @Override - public void onError(String message, Throwable throwable) { - if (message != null) { - logger.error(message); - } - - if (throwable != null) { - StringWriter stringWriter = new StringWriter(); - PrintWriter printWriter = new PrintWriter(stringWriter); - throwable.printStackTrace(printWriter); - logger.error(stringWriter.toString()); - } - } - - @Override - public void onRead(Message message, String json) { - if (message instanceof RequestMessage) { - logger.info("Client Request:\n\t" + json); - } else if (message instanceof NotificationMessage) { - logger.info("Client Notification:\n\t" + json); - } else { - logger.info("Client Sent:\n\t" + json); - } - } - - @Override - public void onWrite(Message message, String json) { - if (message instanceof ResponseMessage) { - logger.info("Server Response:\n\t" + json); - } else if (message instanceof NotificationMessage) { - logger.info("Server Notification:\n\t" + json); - } else { - logger.info("Server Sent:\n\t" + json); - } - } - -} diff --git a/language-server-commons/src/main/java/com/palantir/ls/util/Ranges.java b/language-server-commons/src/main/java/com/palantir/ls/util/Ranges.java index 70261d4..c5a4b12 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/util/Ranges.java +++ b/language-server-commons/src/main/java/com/palantir/ls/util/Ranges.java @@ -18,12 +18,10 @@ import static com.google.common.base.Preconditions.checkArgument; -import io.typefox.lsapi.Position; -import io.typefox.lsapi.Range; -import io.typefox.lsapi.builders.RangeBuilder; -import io.typefox.lsapi.impl.PositionImpl; import java.util.Comparator; import java.util.List; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; public final class Ranges { @@ -45,10 +43,7 @@ private Ranges() {} * Returns a newly created range. */ public static Range createRange(int startLine, int startColumn, int endLine, int endColumn) { - return new RangeBuilder() - .start(new PositionImpl(startLine, startColumn)) - .end(new PositionImpl(endLine, endColumn)) - .build(); + return new Range(new Position(startLine, startColumn), new Position(endLine, endColumn)); } /** diff --git a/language-server-commons/src/main/java/com/palantir/ls/util/SourceWriter.java b/language-server-commons/src/main/java/com/palantir/ls/util/SourceWriter.java index 0147235..117008e 100644 --- a/language-server-commons/src/main/java/com/palantir/ls/util/SourceWriter.java +++ b/language-server-commons/src/main/java/com/palantir/ls/util/SourceWriter.java @@ -20,8 +20,6 @@ import com.google.common.base.Throwables; import edu.umd.cs.findbugs.annotations.SuppressFBWarnings; -import io.typefox.lsapi.Position; -import io.typefox.lsapi.TextDocumentContentChangeEvent; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; @@ -35,6 +33,8 @@ import java.util.List; import java.util.stream.Collectors; import org.apache.commons.io.FileUtils; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/language-server-commons/src/test/java/com/palantir/ls/DefaultCompilerWrapperTest.java b/language-server-commons/src/test/java/com/palantir/ls/DefaultCompilerWrapperTest.java index 76645e8..69e4dda 100644 --- a/language-server-commons/src/test/java/com/palantir/ls/DefaultCompilerWrapperTest.java +++ b/language-server-commons/src/test/java/com/palantir/ls/DefaultCompilerWrapperTest.java @@ -19,15 +19,16 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.when; +import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Sets; import com.palantir.ls.api.TreeParser; import com.palantir.ls.api.WorkspaceCompiler; import com.palantir.ls.util.Ranges; -import io.typefox.lsapi.DiagnosticSeverity; -import io.typefox.lsapi.builders.DiagnosticBuilder; -import io.typefox.lsapi.builders.PublishDiagnosticsParamsBuilder; import java.io.IOException; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.PublishDiagnosticsParams; import org.junit.Before; import org.junit.Test; import org.mockito.Mock; @@ -60,16 +61,8 @@ public void testCompile_noDiagnostics() throws IOException { @Test public void testCompile_withDiagnostics() throws IOException { when(compiler.compile(any())).thenReturn(Sets.newHashSet( - new PublishDiagnosticsParamsBuilder() - .uri("uri") - .diagnostic( - new DiagnosticBuilder() - .message("name") - .range(Ranges.UNDEFINED_RANGE) - .severity(DiagnosticSeverity.Error) - .source("groovyc") - .build()) - .build())); + new PublishDiagnosticsParams("uri", ImmutableList.of( + new Diagnostic(Ranges.UNDEFINED_RANGE, "name", DiagnosticSeverity.Error, "groovyc"))))); wrapper.compile(ImmutableSet.of()); // assert parser wasn't called Mockito.verify(parser, Mockito.never()).parseAllSymbols(); diff --git a/language-server-commons/src/test/java/com/palantir/ls/services/AbstractWindowServiceTest.java b/language-server-commons/src/test/java/com/palantir/ls/services/AbstractWindowServiceTest.java deleted file mode 100644 index 8db2ce9..0000000 --- a/language-server-commons/src/test/java/com/palantir/ls/services/AbstractWindowServiceTest.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2016 Palantir Technologies, Inc. All rights reserved. - * - * Licensed 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 com.palantir.ls.services; - -import com.palantir.ls.api.LanguageServerState; -import io.typefox.lsapi.MessageParams; -import io.typefox.lsapi.ShowMessageRequestParams; -import java.io.IOException; -import java.util.function.Consumer; -import org.junit.Before; -import org.junit.Test; -import org.mockito.Mock; -import org.mockito.Mockito; -import org.mockito.MockitoAnnotations; - -public class AbstractWindowServiceTest { - - public static class TestWindowService extends AbstractWindowService { - - private final LanguageServerState state; - - public TestWindowService(LanguageServerState state) { - this.state = state; - } - - @Override - protected LanguageServerState getState() { - return state; - } - } - - @Mock - private LanguageServerState state; - - private AbstractWindowService service; - - @Before - public void setup() throws IOException { - MockitoAnnotations.initMocks(this); - service = new TestWindowService(state); - } - - @Test - public void testOnShowMessage() { - Consumer callback = m -> { }; - service.onShowMessage(callback); - Mockito.verify(state, Mockito.times(1)).setShowMessage(callback); - } - - @Test - public void testOnShowMessageRequest() { - Consumer callback = m -> { }; - service.onShowMessageRequest(callback); - Mockito.verify(state, Mockito.times(1)).setShowMessageRequest(callback); - } - - @Test - public void testOnLogMessage() { - Consumer callback = m -> { }; - service.onLogMessage(callback); - Mockito.verify(state, Mockito.times(1)).setLogMessage(callback); - } - -} diff --git a/language-server-commons/src/test/java/com/palantir/ls/services/AbstractWorkspaceServiceTest.java b/language-server-commons/src/test/java/com/palantir/ls/services/AbstractWorkspaceServiceTest.java index a9ffe61..dc57a1e 100644 --- a/language-server-commons/src/test/java/com/palantir/ls/services/AbstractWorkspaceServiceTest.java +++ b/language-server-commons/src/test/java/com/palantir/ls/services/AbstractWorkspaceServiceTest.java @@ -21,28 +21,28 @@ import static org.mockito.Matchers.any; import static org.mockito.Mockito.when; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Sets; import com.palantir.ls.api.CompilerWrapper; import com.palantir.ls.api.LanguageServerState; import com.palantir.ls.util.Ranges; -import io.typefox.lsapi.DiagnosticSeverity; -import io.typefox.lsapi.DidChangeConfigurationParams; -import io.typefox.lsapi.FileChangeType; -import io.typefox.lsapi.PublishDiagnosticsParams; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.SymbolKind; -import io.typefox.lsapi.builders.DiagnosticBuilder; -import io.typefox.lsapi.builders.DidChangeWatchedFilesParamsBuilder; -import io.typefox.lsapi.builders.LocationBuilder; -import io.typefox.lsapi.builders.PublishDiagnosticsParamsBuilder; -import io.typefox.lsapi.builders.SymbolInformationBuilder; -import io.typefox.lsapi.builders.WorkspaceSymbolParamsBuilder; import java.io.IOException; import java.util.List; import java.util.Set; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ExecutionException; import java.util.stream.Collectors; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.DidChangeConfigurationParams; +import org.eclipse.lsp4j.DidChangeWatchedFilesParams; +import org.eclipse.lsp4j.FileChangeType; +import org.eclipse.lsp4j.FileEvent; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.WorkspaceSymbolParams; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -87,47 +87,26 @@ public void didChangeConfiguration(DidChangeConfigurationParams didChangeConfigu public void setup() throws IOException { MockitoAnnotations.initMocks(this); + Diagnostic d1 = new Diagnostic(); + d1.setMessage("Some message"); + d1.setSeverity(DiagnosticSeverity.Error); + Diagnostic d2 = new Diagnostic(); + d2.setMessage("Some other message"); + d2.setSeverity(DiagnosticSeverity.Warning); expectedDiagnostics = - Sets.newHashSet(new PublishDiagnosticsParamsBuilder().uri("foo") - .diagnostic(new DiagnosticBuilder() - .message("Some message") - .severity(DiagnosticSeverity.Error) - .build() - ).diagnostic(new DiagnosticBuilder() - .message("Some other message") - .severity(DiagnosticSeverity.Warning) - .build() - ).build()); - - expectedReferences.add(new SymbolInformationBuilder() - .containerName("Something") - .kind(SymbolKind.Class) - .name("MyClassName") - .location(new LocationBuilder() - .uri("uri") - .range(Ranges.createRange(1, 1, 9, 9)) - .build()) - .build()); - expectedReferences.add(new SymbolInformationBuilder() - .containerName("SomethingElse") - .kind(SymbolKind.Class) - .name("MyClassName2") - .location(new LocationBuilder() - .uri("uri") - .range(Ranges.createRange(1, 1, 9, 9)) - .build()) - .build()); + Sets.newHashSet(new PublishDiagnosticsParams("uri", ImmutableList.of(d1, d2))); + + expectedReferences.add(new SymbolInformation( + "MyClassName", SymbolKind.Class, new Location("uri", Ranges.createRange(1, 1, 9, 9)), "Something")); + expectedReferences.add(new SymbolInformation( + "MyClassName2", + SymbolKind.Class, + new Location("uri", Ranges.createRange(1, 1, 9, 9)), + "SomethingElse")); Set allReferencesReturned = Sets.newHashSet(expectedReferences); // The reference that will be filtered out - allReferencesReturned.add(new SymbolInformationBuilder() - .containerName("SomethingElse") - .kind(SymbolKind.Class) - .name("MyClassName3") - .location(new LocationBuilder() - .uri("uri") - .range(Ranges.UNDEFINED_RANGE) - .build()) - .build()); + allReferencesReturned.add(new SymbolInformation( + "MyClassName3", SymbolKind.Class, new Location("uri", Ranges.UNDEFINED_RANGE), "SomethingElse")); when(compilerWrapper.getWorkspaceRoot()).thenReturn(workspace.getRoot().toPath().toUri()); when(compilerWrapper.compile(any())).thenReturn(expectedDiagnostics); @@ -141,14 +120,16 @@ public void setup() throws IOException { @Test public void testSymbol() throws InterruptedException, ExecutionException { CompletableFuture> response = - service.symbol(new WorkspaceSymbolParamsBuilder().query("myQuery").build()); + service.symbol(new WorkspaceSymbolParams("myQuery")); assertThat(response.get().stream().collect(Collectors.toSet()), is(expectedReferences)); } @Test public void testDidChangeWatchedFiles() throws InterruptedException, ExecutionException { - service.didChangeWatchedFiles(new DidChangeWatchedFilesParamsBuilder().change("uri", FileChangeType.Deleted) - .change("uri", FileChangeType.Created).change("uri", FileChangeType.Changed).build()); + service.didChangeWatchedFiles(new DidChangeWatchedFilesParams(ImmutableList.of( + new FileEvent("uri", FileChangeType.Deleted), + new FileEvent("uri", FileChangeType.Created), + new FileEvent("uri", FileChangeType.Changed)))); // assert diagnostics were published Mockito.verify(state, Mockito.times(1)).publishDiagnostics(expectedDiagnostics); } diff --git a/language-server-commons/src/test/java/com/palantir/ls/services/DefaultTextDocumentServiceTest.java b/language-server-commons/src/test/java/com/palantir/ls/services/DefaultTextDocumentServiceTest.java index 3b40edf..df8cc2c 100644 --- a/language-server-commons/src/test/java/com/palantir/ls/services/DefaultTextDocumentServiceTest.java +++ b/language-server-commons/src/test/java/com/palantir/ls/services/DefaultTextDocumentServiceTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.when; import com.google.common.base.Optional; +import com.google.common.collect.ImmutableList; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; @@ -31,35 +32,6 @@ import com.palantir.ls.api.CompilerWrapper; import com.palantir.ls.api.LanguageServerState; import com.palantir.ls.util.Ranges; -import io.typefox.lsapi.CompletionItemKind; -import io.typefox.lsapi.CompletionList; -import io.typefox.lsapi.Diagnostic; -import io.typefox.lsapi.DiagnosticSeverity; -import io.typefox.lsapi.Location; -import io.typefox.lsapi.PublishDiagnosticsParams; -import io.typefox.lsapi.ReferenceParams; -import io.typefox.lsapi.SymbolInformation; -import io.typefox.lsapi.SymbolKind; -import io.typefox.lsapi.TextDocumentIdentifier; -import io.typefox.lsapi.TextDocumentItem; -import io.typefox.lsapi.TextDocumentPositionParams; -import io.typefox.lsapi.builders.CompletionItemBuilder; -import io.typefox.lsapi.builders.CompletionListBuilder; -import io.typefox.lsapi.builders.DiagnosticBuilder; -import io.typefox.lsapi.builders.DidChangeTextDocumentParamsBuilder; -import io.typefox.lsapi.builders.DidCloseTextDocumentParamsBuilder; -import io.typefox.lsapi.builders.DidOpenTextDocumentParamsBuilder; -import io.typefox.lsapi.builders.DidSaveTextDocumentParamsBuilder; -import io.typefox.lsapi.builders.DocumentSymbolParamsBuilder; -import io.typefox.lsapi.builders.LocationBuilder; -import io.typefox.lsapi.builders.PublishDiagnosticsParamsBuilder; -import io.typefox.lsapi.builders.ReferenceParamsBuilder; -import io.typefox.lsapi.builders.SymbolInformationBuilder; -import io.typefox.lsapi.builders.TextDocumentIdentifierBuilder; -import io.typefox.lsapi.builders.TextDocumentItemBuilder; -import io.typefox.lsapi.builders.TextDocumentPositionParamsBuilder; -import io.typefox.lsapi.builders.VersionedTextDocumentIdentifierBuilder; -import io.typefox.lsapi.impl.PositionImpl; import java.io.IOException; import java.net.URI; import java.nio.file.Path; @@ -70,6 +42,29 @@ import java.util.concurrent.ExecutionException; import java.util.function.Consumer; import java.util.stream.Collectors; +import org.eclipse.lsp4j.CompletionItem; +import org.eclipse.lsp4j.CompletionItemKind; +import org.eclipse.lsp4j.CompletionList; +import org.eclipse.lsp4j.Diagnostic; +import org.eclipse.lsp4j.DiagnosticSeverity; +import org.eclipse.lsp4j.DidChangeTextDocumentParams; +import org.eclipse.lsp4j.DidCloseTextDocumentParams; +import org.eclipse.lsp4j.DidOpenTextDocumentParams; +import org.eclipse.lsp4j.DidSaveTextDocumentParams; +import org.eclipse.lsp4j.DocumentSymbolParams; +import org.eclipse.lsp4j.Location; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.PublishDiagnosticsParams; +import org.eclipse.lsp4j.ReferenceContext; +import org.eclipse.lsp4j.ReferenceParams; +import org.eclipse.lsp4j.SymbolInformation; +import org.eclipse.lsp4j.SymbolKind; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; +import org.eclipse.lsp4j.TextDocumentIdentifier; +import org.eclipse.lsp4j.TextDocumentItem; +import org.eclipse.lsp4j.TextDocumentPositionParams; +import org.eclipse.lsp4j.VersionedTextDocumentIdentifier; +import org.eclipse.lsp4j.jsonrpc.messages.Either; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -104,65 +99,46 @@ public void setup() throws IOException { MockitoAnnotations.initMocks(this); filePath = workspace.newFile("something.groovy").toPath(); - expectedDiagnostics = - Sets.newHashSet(new PublishDiagnosticsParamsBuilder().uri("foo") - .diagnostic(createDiagnostic("Some message", DiagnosticSeverity.Error, filePath.toString())) - .diagnostic(createDiagnostic( - "Some other message", DiagnosticSeverity.Warning, filePath.toString())) - .build()); - - SymbolInformation symbol1 = new SymbolInformationBuilder().name("ThisIsASymbol").kind(SymbolKind.Field).build(); - SymbolInformation symbol2 = new SymbolInformationBuilder().name("methodA").kind(SymbolKind.Method).build(); + expectedDiagnostics = Sets.newHashSet(new PublishDiagnosticsParams("foo", ImmutableList.of( + createDiagnostic("Some message", DiagnosticSeverity.Error, filePath.toString()), + createDiagnostic("Some other message", DiagnosticSeverity.Warning, filePath.toString()) + ))); + + SymbolInformation symbol1 = new SymbolInformation("ThisIsASymbol", SymbolKind.Field, new Location()); + SymbolInformation symbol2 = new SymbolInformation("methodA", SymbolKind.Method, new Location()); symbolsMap.put(filePath.toUri(), Sets.newHashSet(symbol1, symbol2)); - emptyCompletionList = new CompletionListBuilder().isIncomplete(false).build(); - expectedCompletionList = new CompletionListBuilder() - .isIncomplete(false) - .item(new CompletionItemBuilder() - .label("ThisIsASymbol") - .kind(CompletionItemKind.Field) - .build()) - .item(new CompletionItemBuilder() - .label("methodA") - .kind(CompletionItemKind.Method).build()) - .build(); - - expectedReferences.add(new LocationBuilder() - .uri("uri") - .range(Ranges.createRange(1, 1, 9, 9)) - .build()); - expectedReferences.add(new LocationBuilder() - .uri("uri") - .range(Ranges.createRange(1, 1, 9, 9)) - .build()); + emptyCompletionList = new CompletionList(false, Lists.newArrayList()); + CompletionItem thisIsASymbol = new CompletionItem("ThisIsASymbol"); + thisIsASymbol.setKind(CompletionItemKind.Field); + CompletionItem methodA = new CompletionItem("methodA"); + methodA.setKind(CompletionItemKind.Method); + expectedCompletionList = new CompletionList(false, Lists.newArrayList(thisIsASymbol, methodA)); + + expectedReferences.add(new Location("uri", Ranges.createRange(1, 1, 9, 9))); + expectedReferences.add(new Location("uri", Ranges.createRange(1, 1, 9, 9))); Set allReferencesReturned = Sets.newHashSet(expectedReferences); // The reference that will be filtered out - allReferencesReturned.add(new LocationBuilder() - .uri("uri") - .range(Ranges.UNDEFINED_RANGE) - .build()); - expectedDefinitionLocation = - Optional.of(new LocationBuilder().uri("foo").range(Ranges.createRange(0, 1, 0, 1)).build()); + allReferencesReturned.add(new Location("uri", Ranges.UNDEFINED_RANGE)); + expectedDefinitionLocation = Optional.of(new Location("foo", Ranges.createRange(0, 1, 0, 1))); when(compilerWrapper.getWorkspaceRoot()).thenReturn(workspace.getRoot().toPath().toUri()); when(compilerWrapper.compile(any())).thenReturn(expectedDiagnostics); when(compilerWrapper.getFileSymbols()).thenReturn(symbolsMap); when(compilerWrapper.getCompletion(any(), any())).thenReturn(emptyCompletionList); - when(compilerWrapper.getCompletion(filePath.toUri(), new PositionImpl(5, 5))) + when(compilerWrapper.getCompletion(filePath.toUri(), new Position(5, 5))) .thenReturn(expectedCompletionList); when(compilerWrapper.findReferences(any())).thenReturn(allReferencesReturned); - when(compilerWrapper.gotoDefinition(any(), eq(new PositionImpl(5, 5)))).thenReturn(expectedDefinitionLocation); - when(compilerWrapper.gotoDefinition(any(), eq(new PositionImpl(4, 4)))).thenReturn(Optional.absent()); + when(compilerWrapper.gotoDefinition(any(), eq(new Position(5, 5)))).thenReturn(expectedDefinitionLocation); + when(compilerWrapper.gotoDefinition(any(), eq(new Position(4, 4)))).thenReturn(Optional.absent()); LanguageServerState state = new DefaultLanguageServerState(); state.setCompilerWrapper(compilerWrapper); service = new DefaultTextDocumentService(state); - Consumer callback = p -> { - publishDiagnostics(p); - }; + Consumer callback = this::publishDiagnostics; - service.onPublishDiagnostics(callback); + service.getState().setPublishDiagnostics(callback); } private void publishDiagnostics(PublishDiagnosticsParams params) { @@ -171,13 +147,9 @@ private void publishDiagnostics(PublishDiagnosticsParams params) { @Test public void testDidOpen() { - TextDocumentItem textDocument = new TextDocumentItemBuilder() - .uri(filePath.toAbsolutePath().toString()) - .languageId("groovy") - .version(1) - .text("something") - .build(); - service.didOpen(new DidOpenTextDocumentParamsBuilder().textDocument(textDocument).build()); + TextDocumentItem textDocument = new TextDocumentItem( + filePath.toAbsolutePath().toString(), "groovy", 1, "something"); + service.didOpen(new DidOpenTextDocumentParams(textDocument)); // assert diagnostics were published assertEquals(1, publishedDiagnostics.size()); assertEquals(expectedDiagnostics, Sets.newHashSet(publishedDiagnostics.get(0))); @@ -185,13 +157,10 @@ public void testDidOpen() { @Test public void testDidChange() { - service.didChange(new DidChangeTextDocumentParamsBuilder() - .contentChange(Ranges.createRange(0, 0, 1, 1), 3, "Hello") - .textDocument(new VersionedTextDocumentIdentifierBuilder() - .version(0) - .uri(filePath.toAbsolutePath().toString()) - .build()) - .build()); + VersionedTextDocumentIdentifier ident = new VersionedTextDocumentIdentifier(0); + ident.setUri(filePath.toAbsolutePath().toString()); + service.didChange(new DidChangeTextDocumentParams(ident, + ImmutableList.of(new TextDocumentContentChangeEvent(Ranges.createRange(0, 0, 1, 1), 3, "Hello")))); // assert diagnostics were published assertEquals(1, publishedDiagnostics.size()); assertEquals(expectedDiagnostics, Sets.newHashSet(publishedDiagnostics.get(0))); @@ -202,33 +171,26 @@ public void testDidChange_noChanges() { expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage( String.format("Calling didChange with no changes on uri '%s'", filePath.toUri())); - service.didChange(new DidChangeTextDocumentParamsBuilder() - .textDocument(new VersionedTextDocumentIdentifierBuilder() - .version(0) - .uri(filePath.toAbsolutePath().toString()) - .build()) - .build()); + VersionedTextDocumentIdentifier ident = new VersionedTextDocumentIdentifier(0); + ident.setUri(filePath.toAbsolutePath().toString()); + service.didChange(new DidChangeTextDocumentParams(ident, ImmutableList.of())); } @Test public void testDidChange_nonExistantUri() { expectedException.expect(IllegalArgumentException.class); expectedException - .expectMessage(String.format("Uri '%s' does not exist", filePath.toUri() + "boo")); - service.didChange(new DidChangeTextDocumentParamsBuilder() - .textDocument(new VersionedTextDocumentIdentifierBuilder() - .version(0) - .uri(filePath.toAbsolutePath().toString() + "boo") - .build()) - .build()); + .expectMessage(String.format("Uri '%s' does not exist", filePath.toUri() + "_fake")); + VersionedTextDocumentIdentifier ident = new VersionedTextDocumentIdentifier(0); + ident.setUri(filePath.toAbsolutePath().toString() + "_fake"); + service.didChange(new DidChangeTextDocumentParams(ident, + ImmutableList.of(new TextDocumentContentChangeEvent(Ranges.createRange(0, 0, 1, 1), 3, "Hello")))); } @Test public void testDidClose() { - TextDocumentIdentifier textDocument = new TextDocumentIdentifierBuilder() - .uri(filePath.toAbsolutePath().toString()) - .build(); - service.didClose(new DidCloseTextDocumentParamsBuilder().textDocument(textDocument).build()); + service.didClose(new DidCloseTextDocumentParams( + new TextDocumentIdentifier(filePath.toAbsolutePath().toString()))); // assert diagnostics were published assertEquals(1, publishedDiagnostics.size()); assertEquals(expectedDiagnostics, Sets.newHashSet(publishedDiagnostics.get(0))); @@ -236,21 +198,17 @@ public void testDidClose() { @Test public void testDidClose_nonExistantUri() { - TextDocumentIdentifier textDocument = new TextDocumentIdentifierBuilder() - .uri(filePath.toAbsolutePath().toString() + "boo") - .build(); expectedException.expect(IllegalArgumentException.class); expectedException - .expectMessage(String.format("Uri '%s' does not exist", filePath.toUri() + "boo")); - service.didClose(new DidCloseTextDocumentParamsBuilder().textDocument(textDocument).build()); + .expectMessage(String.format("Uri '%s' does not exist", filePath.toUri() + "_fake")); + service.didClose(new DidCloseTextDocumentParams( + new TextDocumentIdentifier(filePath.toAbsolutePath().toString() + "_fake"))); } @Test public void testDidSave() { - TextDocumentIdentifier textDocument = new TextDocumentIdentifierBuilder() - .uri(filePath.toAbsolutePath().toString()) - .build(); - service.didSave(new DidSaveTextDocumentParamsBuilder().textDocument(textDocument).build()); + service.didSave(new DidSaveTextDocumentParams( + new TextDocumentIdentifier(filePath.toAbsolutePath().toString()))); // assert diagnostics were published assertEquals(1, publishedDiagnostics.size()); assertEquals(expectedDiagnostics, Sets.newHashSet(publishedDiagnostics.get(0))); @@ -258,54 +216,45 @@ public void testDidSave() { @Test public void testDidSave_nonExistantUri() { - TextDocumentIdentifier textDocument = new TextDocumentIdentifierBuilder() - .uri(filePath.toAbsolutePath().toString() + "boo") - .build(); expectedException.expect(IllegalArgumentException.class); expectedException - .expectMessage(String.format("Uri '%s' does not exist", filePath.toUri() + "boo")); - service.didSave(new DidSaveTextDocumentParamsBuilder().textDocument(textDocument).build()); + .expectMessage(String.format("Uri '%s' does not exist", filePath.toUri() + "_fake")); + service.didSave(new DidSaveTextDocumentParams( + new TextDocumentIdentifier(filePath.toAbsolutePath().toString() + "_fake"))); } @Test public void testDocumentSymbols_absolutePath() throws InterruptedException, ExecutionException { - TextDocumentIdentifier textDocument = new TextDocumentIdentifierBuilder() - .uri(filePath.toAbsolutePath().toString()) - .build(); - CompletableFuture> response = - service.documentSymbol(new DocumentSymbolParamsBuilder().textDocument(textDocument).build()); + CompletableFuture> response = service.documentSymbol( + new DocumentSymbolParams( + new TextDocumentIdentifier(filePath.toAbsolutePath().toString()))); assertThat(response.get().stream().collect(Collectors.toSet()), is(symbolsMap.get(filePath.toUri()))); } @Test public void testDocumentSymbols_relativePath() throws InterruptedException, ExecutionException { - TextDocumentIdentifier textDocument = new TextDocumentIdentifierBuilder().uri("something.groovy").build(); CompletableFuture> response = - service.documentSymbol(new DocumentSymbolParamsBuilder().textDocument(textDocument).build()); + service.documentSymbol(new DocumentSymbolParams(new TextDocumentIdentifier("something.groovy"))); assertThat(response.get().stream().collect(Collectors.toSet()), is(symbolsMap.get(filePath.toUri()))); } @Test public void testDocumentSymbols_nonExistantUri() throws InterruptedException, ExecutionException { - TextDocumentIdentifier textDocument = new TextDocumentIdentifierBuilder() - .uri(filePath.toAbsolutePath().toString() + "boo") - .build(); expectedException.expect(IllegalArgumentException.class); expectedException - .expectMessage(String.format("Uri '%s' does not exist", filePath.toUri() + "boo")); - service.documentSymbol(new DocumentSymbolParamsBuilder().textDocument(textDocument).build()); + .expectMessage(String.format("Uri '%s' does not exist", filePath.toUri() + "_fake")); + service.documentSymbol(new DocumentSymbolParams( + new TextDocumentIdentifier(filePath.toAbsolutePath().toString() + "_fake"))); } @Test public void testReferences() throws InterruptedException, ExecutionException { - ReferenceParams params = new ReferenceParamsBuilder() - .context(false) - .position(5, 5) - .textDocument("uri") - .uri("uri") - .build(); + ReferenceParams params = new ReferenceParams(new ReferenceContext(false)); + params.setPosition(new Position(5, 5)); + params.setTextDocument(new TextDocumentIdentifier("uri")); + params.setUri("uri"); CompletableFuture> response = service.references(params); assertThat(response.get().stream().collect(Collectors.toSet()), is(expectedReferences)); } @@ -313,37 +262,29 @@ public void testReferences() throws InterruptedException, ExecutionException { @Test public void testCompletion() throws InterruptedException, ExecutionException { String uri = filePath.toAbsolutePath().toString(); - TextDocumentPositionParams params = new TextDocumentPositionParamsBuilder() - .position(5, 5) - .textDocument(uri) - .uri(uri) - .build(); - CompletableFuture response = service.completion(params); - assertThat(response.get().isIncomplete(), is(expectedCompletionList.isIncomplete())); - assertThat(Sets.newHashSet(response.get().getItems()), is(Sets.newHashSet(expectedCompletionList.getItems()))); + TextDocumentPositionParams params = + new TextDocumentPositionParams(new TextDocumentIdentifier(uri), uri, new Position(5, 5)); + CompletableFuture, CompletionList>> response = service.completion(params); + assertThat(response.get().getRight().isIncomplete(), is(expectedCompletionList.isIncomplete())); + assertThat(Sets.newHashSet(response.get().getRight().getItems()), + is(Sets.newHashSet(expectedCompletionList.getItems()))); } @Test public void testCompletion_noSymbols() throws InterruptedException, ExecutionException { String uri = workspace.getRoot().toPath().resolve("somethingthatdoesntexist.groovy").toString(); - TextDocumentPositionParams params = new TextDocumentPositionParamsBuilder() - .position(5, 5) - .textDocument(uri) - .uri(uri) - .build(); - CompletableFuture response = service.completion(params); - assertThat(response.get().isIncomplete(), is(false)); - assertThat(response.get().getItems(), is(Lists.newArrayList())); + TextDocumentPositionParams params = + new TextDocumentPositionParams(new TextDocumentIdentifier(uri), uri, new Position(5, 5)); + CompletableFuture, CompletionList>> response = service.completion(params); + assertThat(response.get().getRight().isIncomplete(), is(false)); + assertThat(response.get().getRight().getItems(), is(Lists.newArrayList())); } @Test public void testDefinition() throws InterruptedException, ExecutionException { String uri = filePath.toAbsolutePath().toString(); - TextDocumentPositionParams params = new TextDocumentPositionParamsBuilder() - .position(5, 5) - .textDocument(uri) - .uri(uri) - .build(); + TextDocumentPositionParams params = + new TextDocumentPositionParams(new TextDocumentIdentifier(uri), uri, new Position(5, 5)); CompletableFuture> response = service.definition(params); assertThat(response.get(), is(Lists.newArrayList(expectedDefinitionLocation.get()))); } @@ -351,22 +292,14 @@ public void testDefinition() throws InterruptedException, ExecutionException { @Test public void testDefinition_NoDefinition() throws InterruptedException, ExecutionException { String uri = filePath.toAbsolutePath().toString(); - TextDocumentPositionParams params = new TextDocumentPositionParamsBuilder() - .position(4, 4) - .textDocument(uri) - .uri(uri) - .build(); + TextDocumentPositionParams params = + new TextDocumentPositionParams(new TextDocumentIdentifier(uri), uri, new Position(4, 4)); CompletableFuture> response = service.definition(params); assertThat(response.get(), is(Lists.newArrayList())); } private Diagnostic createDiagnostic(String message, DiagnosticSeverity severity, String source) { - return new DiagnosticBuilder() - .message(message) - .severity(severity) - .source(source) - .range(Ranges.UNDEFINED_RANGE) - .build(); + return new Diagnostic(Ranges.UNDEFINED_RANGE, message, severity, source); } } diff --git a/language-server-commons/src/test/java/com/palantir/ls/util/RangesTest.java b/language-server-commons/src/test/java/com/palantir/ls/util/RangesTest.java index 8a8d605..f95ccf8 100644 --- a/language-server-commons/src/test/java/com/palantir/ls/util/RangesTest.java +++ b/language-server-commons/src/test/java/com/palantir/ls/util/RangesTest.java @@ -22,9 +22,8 @@ import static org.junit.Assert.assertTrue; import com.google.common.collect.Lists; -import io.typefox.lsapi.Position; -import io.typefox.lsapi.Range; -import io.typefox.lsapi.impl.PositionImpl; +import org.eclipse.lsp4j.Position; +import org.eclipse.lsp4j.Range; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -166,7 +165,7 @@ public void testSortedRangesIntersect() { } private static Position position(int line, int character) { - return new PositionImpl(line, character); + return new Position(line, character); } } diff --git a/language-server-commons/src/test/java/com/palantir/ls/util/SourceWriterTest.java b/language-server-commons/src/test/java/com/palantir/ls/util/SourceWriterTest.java index e91e548..8719d2b 100644 --- a/language-server-commons/src/test/java/com/palantir/ls/util/SourceWriterTest.java +++ b/language-server-commons/src/test/java/com/palantir/ls/util/SourceWriterTest.java @@ -19,9 +19,6 @@ import static org.junit.Assert.assertEquals; import com.google.common.collect.Lists; -import io.typefox.lsapi.Range; -import io.typefox.lsapi.TextDocumentContentChangeEvent; -import io.typefox.lsapi.builders.TextDocumentContentChangeEventBuilder; import java.io.File; import java.io.IOException; import java.io.PrintWriter; @@ -31,6 +28,8 @@ import java.nio.file.Paths; import java.util.List; import org.apache.commons.io.FileUtils; +import org.eclipse.lsp4j.Range; +import org.eclipse.lsp4j.TextDocumentContentChangeEvent; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; @@ -80,9 +79,7 @@ public void testDidChanges_nullRangeChange() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .text("foo") - .build()); + changes.add(new TextDocumentContentChangeEvent("foo")); writer.applyChanges(changes); assertEquals("foo", FileUtils.readFileToString(destination.toFile())); } @@ -94,14 +91,8 @@ public void testDidChanges_nullRangeWithMultipleChanges() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .text("foo") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(1, 0, 1, 0)) - .rangeLength(1) - .text("notfoo") - .build()); + changes.add(new TextDocumentContentChangeEvent("foo")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(1, 0, 1, 0), 1, "notfoo")); expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage(String.format("Cannot handle more than one change when a null range exists: %s", changes.get(0).toString())); @@ -114,11 +105,7 @@ public void testDidChanges_insertionBeginningOfLine() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(1, 0, 1, 0)) - .rangeLength(1) - .text("s") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(1, 0, 1, 0), 1, "s")); writer.applyChanges(changes); assertEquals("first line\nsecond line\n", FileUtils.readFileToString(destination.toFile())); } @@ -129,11 +116,7 @@ public void testDidChanges_insertionEndOfLine() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(1, 20, 1, 20)) - .rangeLength(13) - .text("small change\n") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(1, 20, 1, 20), 13, "small change\n")); writer.applyChanges(changes); // Two new lines expected, one from the original contents and one from the change assertEquals("first line\nsecond linesmall change\n\n", FileUtils.readFileToString(destination.toFile())); @@ -145,11 +128,7 @@ public void testDidChanges_oneLineRange() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 6, 0, 10)) - .rangeLength(12) - .text("small change") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 6, 0, 10), 12, "small change")); writer.applyChanges(changes); assertEquals("first small change\nsecond line\n", FileUtils.readFileToString(destination.toFile())); } @@ -160,11 +139,7 @@ public void testDidChanges_multiLineRange() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 6, 1, 6)) - .rangeLength(12) - .text("small change") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 6, 1, 6), 12, "small change")); writer.applyChanges(changes); assertEquals("first small change line\nthird line\n", FileUtils.readFileToString(destination.toFile())); } @@ -175,21 +150,9 @@ public void testDidChanges_multipleRangesWholeLines() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 0, 0, 20)) - .rangeLength(16) - .text("new line number 1") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(1, 0, 1, 20)) - .rangeLength(16) - .text("new line number 2") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(2, 0, 2, 20)) - .rangeLength(16) - .text("new line number 3") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 0, 0, 20), 16, "new line number 1")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(1, 0, 1, 20), 16, "new line number 2")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(2, 0, 2, 20), 16, "new line number 3")); writer.applyChanges(changes); assertEquals("new line number 1\nnew line number 2\nnew line number 3\n", FileUtils.readFileToString(destination.toFile())); @@ -202,21 +165,9 @@ public void testDidChanges_multipleRangesSpecific() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 1, 0, 9)) - .rangeLength(16) - .text("new line number 1") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(1, 1, 1, 10)) - .rangeLength(16) - .text("new line number 2") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(2, 1, 2, 9)) - .rangeLength(16) - .text("new line number 3") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 1, 0, 9), 16, "new line number 1")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(1, 1, 1, 10), 16, "new line number 2")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(2, 1, 2, 9), 16, "new line number 3")); writer.applyChanges(changes); assertEquals("fnew line number 1e\nsnew line number 2e\ntnew line number 3e\n", @@ -230,11 +181,7 @@ public void testDidChanges_beforeFile() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 0, 0, 0)) - .rangeLength(7) - .text("change\n") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 0, 0, 0), 7, "change\n")); writer.applyChanges(changes); assertEquals("change\nfirst line\nsecond line\nthird line\n", FileUtils.readFileToString(destination.toFile())); @@ -247,16 +194,8 @@ public void testDidChanges_afterFile() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(30, 1, 30, 1)) - .rangeLength(6) - .text("first ") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(31, 1, 31, 1)) - .rangeLength(6) - .text("second") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(30, 1, 30, 1), 6, "first ")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(31, 1, 31, 1), 6, "second")); writer.applyChanges(changes); assertEquals("first line\nsecond line\nthird line\nfirst second\n", FileUtils.readFileToString(destination.toFile())); @@ -269,16 +208,8 @@ public void testDidChanges_invalidRanges() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(-1, 0, 0, 0)) - .rangeLength(3) - .text("one") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 0, 0, 0)) - .rangeLength(3) - .text("two") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(-1, 0, 0, 0), 3, "one")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 0, 0, 0), 3, "two")); expectedException.expect(IllegalArgumentException.class); expectedException .expectMessage(String.format("range1 is not valid: %s", Ranges.createRange(-1, 0, 0, 0).toString())); @@ -293,16 +224,8 @@ public void testDidChanges_intersectingRanges() throws IOException { SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); Range range = Ranges.createRange(0, 0, 0, 1); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(range) - .rangeLength(3) - .text("one") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(range) - .rangeLength(3) - .text("two") - .build()); + changes.add(new TextDocumentContentChangeEvent(range, 3, "one")); + changes.add(new TextDocumentContentChangeEvent(range, 3, "two")); expectedException.expect(IllegalArgumentException.class); expectedException.expectMessage( String.format("Cannot apply changes with intersecting ranges in changes: %s", changes)); @@ -318,51 +241,15 @@ public void testDidChanges_rangesStartAndEndOnSameLine() throws IOException { Path destination = destinationFolder.getRoot().toPath().resolve("myfile.txt"); SourceWriter writer = SourceWriter.of(source, destination); List changes = Lists.newArrayList(); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 0, 0, 1)) - .rangeLength(1) - .text("a") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 2, 0, 3)) - .rangeLength(1) - .text("b") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 5, 0, 7)) - .rangeLength(1) - .text("c") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(0, 8, 1, 2)) - .rangeLength(1) - .text("d") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(1, 4, 2, 2)) - .rangeLength(1) - .text("e") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(2, 4, 2, 6)) - .rangeLength(1) - .text("f") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(2, 9, 2, 9)) - .rangeLength(1) - .text("g") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(4, 2, 4, 3)) - .rangeLength(1) - .text("h") - .build()); - changes.add(new TextDocumentContentChangeEventBuilder() - .range(Ranges.createRange(4, 3, 4, 4)) - .rangeLength(1) - .text("i") - .build()); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 0, 0, 1), 1, "a")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 2, 0, 3), 1, "b")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 5, 0, 7), 1, "c")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(0, 8, 1, 2), 1, "d")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(1, 4, 2, 2), 1, "e")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(2, 4, 2, 6), 1, "f")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(2, 9, 2, 9), 1, "g")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(4, 2, 4, 3), 1, "h")); + changes.add(new TextDocumentContentChangeEvent(Ranges.createRange(4, 3, 4, 4), 1, "i")); writer.applyChanges(changes); assertEquals("a1b34c7d23e23f678g9\n0123456789\n01hi456789\n", FileUtils.readFileToString(destination.toFile()));