diff --git a/Dart/src/com/jetbrains/lang/dart/analyzer/DartAnalysisServerService.java b/Dart/src/com/jetbrains/lang/dart/analyzer/DartAnalysisServerService.java index db41b0a2d83..710272deb2e 100644 --- a/Dart/src/com/jetbrains/lang/dart/analyzer/DartAnalysisServerService.java +++ b/Dart/src/com/jetbrains/lang/dart/analyzer/DartAnalysisServerService.java @@ -119,6 +119,9 @@ public final class DartAnalysisServerService implements Disposable { private static final long ANALYSIS_IN_TESTS_TIMEOUT = TimeUnit.SECONDS.toMillis(10); private static final long TESTS_TIMEOUT_COEFF = 10; + // LSP over Legacy Dart Analysis Protocol + public static final long LSP_MESSAGE_TEXT_DOCUMENT_CONTENT_TIMEOUT = TimeUnit.SECONDS.toMillis(100); + private static final Logger LOG = Logger.getInstance(DartAnalysisServerService.class); private static final int DEBUG_LOG_CAPACITY = 30; @@ -2041,6 +2044,40 @@ public void onError(final RequestError error) { return resultRef.get(); } + // + // LSP over Legacy Dart Analysis Server protocols + // + @Nullable + public String lspMessage_dart_textDocumentContent(@NotNull final String uri) { + final RemoteAnalysisServerImpl server = myServer; + if (server == null) { + return null; + } + + final Ref resultRef = new Ref<>(); + final CountDownLatch latch = new CountDownLatch(1); + server.lspMessage_dart_textDocumentContent(uri, new LSPDartTextDocumentContentConsumer() { + @Override + public void computedDocumentContents(String contents) { + resultRef.set(contents); + latch.countDown(); + } + + @Override + public void onError(final RequestError error) { + logError("lspMessage_dart_textDocumentContent()", uri, error); + latch.countDown(); + } + }); + + awaitForLatchCheckingCanceled(server, latch, LSP_MESSAGE_TEXT_DOCUMENT_CONTENT_TIMEOUT); + + if (latch.getCount() > 0) { + logTookTooLongMessage("lspMessage_dart_textDocumentContent", LSP_MESSAGE_TEXT_DOCUMENT_CONTENT_TIMEOUT, uri); + } + return resultRef.get(); + } + private void startServer(@NotNull final DartSdk sdk) { if (DartPubActionBase.isInProgress()) return; // DartPubActionBase will start the server itself when finished diff --git a/Dart/thirdPartySrc/analysisServer/com/google/dart/server/LSPDartTextDocumentContentConsumer.java b/Dart/thirdPartySrc/analysisServer/com/google/dart/server/LSPDartTextDocumentContentConsumer.java new file mode 100644 index 00000000000..3657b22fa95 --- /dev/null +++ b/Dart/thirdPartySrc/analysisServer/com/google/dart/server/LSPDartTextDocumentContentConsumer.java @@ -0,0 +1,16 @@ +// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +package com.google.dart.server; + +import org.dartlang.analysis.server.protocol.RequestError; + +public interface LSPDartTextDocumentContentConsumer extends Consumer { + + public void computedDocumentContents(String contents); + + /** + * If the file contents can't be sent back, some {@link RequestError} is passed back instead. + * + * @param requestError the reason why a result was not passed back + */ + public void onError(RequestError requestError); +} \ No newline at end of file diff --git a/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/RemoteAnalysisServerImpl.java b/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/RemoteAnalysisServerImpl.java index c6e7ec06d81..bb918e98af3 100644 --- a/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/RemoteAnalysisServerImpl.java +++ b/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/RemoteAnalysisServerImpl.java @@ -606,6 +606,14 @@ public void received() { stopServer(); } + // + // LSP over Legacy Dart Analysis Server protocol + // + public void lspMessage_dart_textDocumentContent(String uri, LSPDartTextDocumentContentConsumer consumer) { + String id = generateUniqueId(); + sendRequestToServer(id, RequestUtilities.generateLSPMessage_dart_textDocumentContent(id, uri), consumer); + } + /** * Starts the analysis server. * @@ -929,6 +937,12 @@ else if (consumer instanceof BasicConsumer) { else if (consumer instanceof JsonConsumer) { ((JsonConsumer)consumer).onResponse(resultObject, requestError); } + // + // LSP over Legacy DAS Dart Analysis Server protocol + // + else if (consumer instanceof LSPDartTextDocumentContentConsumer) { + new LSPDartTextDocumentContentProcessor((LSPDartTextDocumentContentConsumer)consumer).process(resultObject, requestError); + } synchronized (consumerMapLock) { consumerMap.remove(idString); diff --git a/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/processor/LSPDartTextDocumentContentProcessor.java b/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/processor/LSPDartTextDocumentContentProcessor.java new file mode 100644 index 00000000000..efbe315805a --- /dev/null +++ b/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/processor/LSPDartTextDocumentContentProcessor.java @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2024, the Dart project authors. + * + * Licensed under the Eclipse Public License v1.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.eclipse.org/legal/epl-v10.html + * + * 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.google.dart.server.internal.remote.processor; + +import com.google.dart.server.LSPDartTextDocumentContentConsumer; +import com.google.gson.JsonObject; + +import org.dartlang.analysis.server.protocol.RequestError; + +/** + * Instances of {@code LSPDartTextDocumentContentProcessor} translate JSON result objects for a given + * {@link LSPDartTextDocumentContentConsumer}. + * + * @coverage dart.server.remote + */ +public class LSPDartTextDocumentContentProcessor extends ResultProcessor { + + private final LSPDartTextDocumentContentConsumer consumer; + + public LSPDartTextDocumentContentProcessor(LSPDartTextDocumentContentConsumer consumer) { + this.consumer = consumer; + } + + public void process(JsonObject resultObject, RequestError requestError) { + if (resultObject != null) { + // Example: {"lspResponse":{"id":"1","jsonrpc":"2.0","result":{"content":"file contents"}}} + JsonObject lspResponse = resultObject.getAsJsonObject("lspResponse"); + JsonObject innerResultObject = lspResponse.getAsJsonObject("result"); + final String contents = innerResultObject.get("content").getAsString(); + consumer.computedDocumentContents(contents); + } + if (requestError != null) { + consumer.onError(requestError); + } + } +} \ No newline at end of file diff --git a/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/utilities/RequestUtilities.java b/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/utilities/RequestUtilities.java index e04ae76e36d..0f45954e0dc 100644 --- a/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/utilities/RequestUtilities.java +++ b/Dart/thirdPartySrc/analysisServer/com/google/dart/server/internal/remote/utilities/RequestUtilities.java @@ -1199,6 +1199,46 @@ private static String getRequestMethod(JsonObject request) { return null; } + // + // LSP over Legacy DAS (Dart Analysis Server) protocol below + // + public static final String LSP_DART_TEXT_DOCUMENT_CONTENT = "dart/textDocumentContent"; + + private static final String LSP_HANDLE = "lsp.handle"; + + public static final String LSP_JSONRPC = "jsonrpc"; + + public static final String LSP_JSONROC_VERSION = "2.0"; + + public static final String LSP_MESSAGE = "lspMessage"; + + /** + * Generate and return a LSP over Legacy DAS request. + * + * Example: + * {"id":"2","method":"lsp.handle","params": + * {"lspMessage": + * {"id":0,"jsonrpc":"2.0","method":"dart/textDocumentContent","params": + * {"position":{"character":7,"line":1}, + * "textDocument":{"uri":"some-uri"}}}}} + */ + private static JsonObject generateLSPMessage(String idValue, String lspMethod, JsonObject lspParams) { + JsonObject lspMessageParams = new JsonObject(); + lspMessageParams.addProperty(ID, idValue); + lspMessageParams.addProperty(LSP_JSONRPC, LSP_JSONROC_VERSION); + lspMessageParams.addProperty(METHOD, lspMethod); + lspMessageParams.add(PARAMS, lspParams); + JsonObject lspMessage = new JsonObject(); + lspMessage.add(LSP_MESSAGE, lspMessageParams); + return buildJsonObjectRequest(idValue, LSP_HANDLE, lspMessage); + } + + public static JsonObject generateLSPMessage_dart_textDocumentContent(String idValue, String uri) { + JsonObject lspParams = new JsonObject(); + lspParams.addProperty("uri", uri); + return generateLSPMessage(idValue, LSP_DART_TEXT_DOCUMENT_CONTENT, lspParams); + } + private RequestUtilities() { } }