fwcd / fwcd/kotlin-language-server
java.util.concurrent.TimeoutException: Unable to connect language server
- Dominant language
- Kotlin
- Stars
- 2k
- Forks
- 252
- PR merge metrics
- No merged PRs in 30d
Description
I use this code to start the server in android:
```java
package com.example.sionora;
import android.app.Service;
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.os.IBinder;
import android.content.Intent;
import android.os.NetworkOnMainThreadException;
import android.widget.Toast;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import org.eclipse.lsp4j.jsonrpc.Launcher;
import org.javacs.kt.CompilerConfiguration;
import org.javacs.kt.Configuration;
import org.javacs.kt.JVMConfiguration;
import org.javacs.kt.KotlinLanguageServer;
import org.jetbrains.kotlin.idea.KotlinLanguage;
public class SinoraService extends Service {
@Override
public IBinder onBind(Intent arg0) {
return null;
}
@Override
public int onStartCommand(Intent arg0, int arg1, int arg2) {
new Thread(() -> {
try {
ServerSocket serverSocket = new ServerSocket(8080);
Socket socket = serverSocket.accept();
KotlinLanguageServer kls = new KotlinLanguageServer();
var outputStream = socket.getOutputStream();
var inputStream = socket.getInputStream();
var launcher = Launcher.createLauncher(kls, LanguageServerTestFixture.class, inputStream, outputStream);
var remoteProxy = launcher.getRemoteProxy();
kls.connect(remoteProxy);
launcher.startListening().get(Long.MAX_VALUE, TimeUnit.SECONDS);
} catch (NetworkOnMainThreadException | TimeoutException | InterruptedException | ExecutionException | IOException err) {
copyText(getApplicationContext(), err.toString());
Toast.makeText(getApplicationContext(), err.toString(), Toast.LENGTH_SHORT).show();
}
}).start();
return START_STICKY;
}
public static void copyText(Context context, String text) {
ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
ClipData cd = ClipData.newPlainText("noe", text);
cm.setPrimaryClip(cd);
}
}
```
and the client class:
```java
package com.example.sionora;
import java.nio.file.Files;
import org.eclipse.lsp4j.*;
import org.eclipse.lsp4j.services.LanguageClient;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import org.javacs.kt.Configuration;
import org.javacs.kt.KotlinLanguageServer;
public abstract class LanguageServerTestFixture implements LanguageClient {
protected final Path workspaceRoot;
protected final KotlinLanguageServer languageServer;
protected List diagnostics;
public LanguageServerTestFixture(String relativeWorkspaceRoot, Configuration config) {
this.workspaceRoot = absoluteWorkspaceRoot(relativeWorkspaceRoot);
this.languageServer = createLanguageServer(config);
}
public Path absoluteWorkspaceRoot(String relativeWorkspaceRoot) {
Path testResources = testResourcesRoot();
return testResources.resolve(relativeWorkspaceRoot);
}
private KotlinLanguageServer createLanguageServer(Configuration config) {
KotlinLanguageServer languageServer = new KotlinLanguageServer(config);
InitializeParams init = new InitializeParams();
init.setCapabilities(new ClientCapabilities());
init.getCapabilities().setTextDocument(new TextDocumentClientCapabilities());
init.getCapabilities().getTextDocument().setCompletion(new CompletionCapabilities());
init.getCapabilities().getTextDocument().getCompletion().setCompletionItem(new CompletionItemCapabilities());
init.getCapabilities().getTextDocument().getCompletion().getCompletionItem().setSnippetSupport(true);
init.setWorkspaceFolders(List.of(new WorkspaceFolder()));
init.getWorkspaceFolders().get(0).setName(workspaceRoot.getFileName().toString());
init.getWorkspaceFolders().get(0).setUri(workspaceRoot.toUri().toString());
languageServer.connect(this);
languageServer.initialize(init).join();
return languageServer;
}
public void closeLanguageServer() {
languageServer.close();
}
public void printMemoryUsage() {
Runtime rt = Runtime.getRuntime();
double total = rt.totalMemory() / 1000000.0;
double free = rt.freeMemory() / 1000000.0;
System.out.println("Memory after test: " + (total - free) + " MB used / " + total + " MB total");
}
public RenameParams renameParams(String relativePath, int line, int column, String newName) {
return new RenameParams(textDocumentPosition(relativePath, line, column).getTextDocument(),
textDocumentPosition(relativePath, line, column).getPosition(), newName);
}
public CompletionParams completionParams(String relativePath, int line, int column) {
String file = workspaceRoot.resolve(relativePath).toString();
TextDocumentIdentifier fileId = new TextDocumentIdentifier(file);
Position position = position(line, column);
return new CompletionParams(fileId, position);
}
public TextDocumentPositionParams textDocumentPosition(String relativePath, int line, int column) {
String file = workspaceRoot.resolve(relativePath).toString();
TextDocumentIdentifier fileId = new TextDocumentIdentifier(file);
Position position = position(line, column);
return new TextDocumentPositionParams(fileId, position);
}
public Position position(int line, int column) {
return new Position(line - 1, column - 1);
}
public Range range(int startLine, int startColumn, int endLine, int endColumn) {
return new Range(position(startLine, startColumn), position(endLine, endColumn));
}
public String uri(String relativePath) {
return workspaceRoot.resolve(relativePath).toUri().toString();
}
public ReferenceParams referenceParams(String relativePath, int line, int column) {
return new ReferenceParams(new TextDocumentIdentifier(uri(relativePath)), position(line, column), new ReferenceContext(true));
}
public void open(String relativePath) {
Path file = workspaceRoot.resolve(relativePath);
try{
String content =new String(Files.readAllBytes(file));
TextDocumentItem document = new TextDocumentItem(uri(relativePath), "Kotlin", 0, content);
languageServer.getTextDocumentService().didOpen(new DidOpenTextDocumentParams(document));
}catch(Exception e){
}
}
public void replace(String relativePath, int line, int character, String oldText, String newText) {
Range range = new Range(position(line, character), position(line, character + oldText.length()));
TextDocumentContentChangeEvent edit = new TextDocumentContentChangeEvent(range, newText);
VersionedTextDocumentIdentifier doc = new VersionedTextDocumentIdentifier(uri(relativePath), version++);
languageServer.getTextDocumentService().didChange(new DidChangeTextDocumentParams(doc, List.of(edit)));
}
// LanguageClient functions
@Override
public void publishDiagnostics(PublishDiagnosticsParams diagnostics) {
this.diagnostics = diagnostics.getDiagnostics();
}
@Override
public CompletableFuture showMessageRequest(ShowMessageRequestParams request) {
System.out.println(request.toString());
return null;
}
@Override
public void telemetryEvent(Object object) {
System.out.println(object.toString());
}
@Override
public void logMessage(MessageParams message) {
printMessage(message);
}
@Override
public void showMessage(MessageParams message) {
printMessage(message);
}
private void printMessage(MessageParams message) {
System.out.println("[" + message.getType() + "] " + message.getMessage());
}
public abstract Path testResourcesRoot();
private int version = 1;
}
```
but i get *java.util.concurrent.TimeoutException: Unable to connect language server*
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with SinoraService.onStartCommand, especially ServerSocket.accept and launcher.startListening().get(...), then trace LanguageServerTestFixture.createLanguageServer and its initialize call. Reproduce the Android connection failure and verify that the language server connects without TimeoutException.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, kotlin
- Domain
- devtools
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100