diff --git a/app/build.gradle b/app/build.gradle index 5b98e2e27..113054a1f 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -145,6 +145,9 @@ dependencies { implementation project(':javapoet') implementation project(':lsp') + // LSP4J + implementation 'org.eclipse.lsp4j:org.eclipse.lsp4j:0.12.0' + implementation fileTree(dir: 'libs', include: ['*.jar']) coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:1.1.5' diff --git a/app/libs/android-retrostreams-and-retrofuture.jar b/app/libs/android-retrostreams-and-retrofuture.jar deleted file mode 100644 index 6eb00c60e..000000000 Binary files a/app/libs/android-retrostreams-and-retrofuture.jar and /dev/null differ diff --git a/app/libs/lsp4j-android-desugared.jar b/app/libs/lsp4j-android-desugared.jar deleted file mode 100644 index 9f2352ae5..000000000 Binary files a/app/libs/lsp4j-android-desugared.jar and /dev/null differ diff --git a/app/src/main/assets/data/jls.jar b/app/src/main/assets/data/jls.jar index 1e2bb1f22..3d4ab85bc 100644 Binary files a/app/src/main/assets/data/jls.jar and b/app/src/main/assets/data/jls.jar differ diff --git a/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java index 6b03fb83c..9bedc33c7 100644 --- a/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java +++ b/app/src/main/java/com/itsaky/androidide/language/java/JavaAutoComplete.java @@ -9,7 +9,7 @@ import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; import java.util.List; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.CompletionItem; import org.eclipse.lsp4j.CompletionList; import org.eclipse.lsp4j.CompletionParams; diff --git a/app/src/main/java/com/itsaky/androidide/lsp/AbstractLanguageClient.java b/app/src/main/java/com/itsaky/androidide/lsp/AbstractLanguageClient.java index 297f54665..291c6b15b 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/AbstractLanguageClient.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/AbstractLanguageClient.java @@ -35,7 +35,7 @@ import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.CodeAction; import org.eclipse.lsp4j.Command; import org.eclipse.lsp4j.Diagnostic; diff --git a/app/src/main/java/com/itsaky/androidide/lsp/LSPClientLauncher.java b/app/src/main/java/com/itsaky/androidide/lsp/LSPClientLauncher.java index 1beb24543..1aa133d5e 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/LSPClientLauncher.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/LSPClientLauncher.java @@ -1,21 +1,15 @@ package com.itsaky.androidide.lsp; -import com.blankj.utilcode.util.CloseUtils; import com.itsaky.androidide.utils.Logger; import com.itsaky.lsp.services.IDELanguageServer; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.net.InetSocketAddress; -import java.nio.channels.AsynchronousServerSocketChannel; -import java.nio.channels.AsynchronousSocketChannel; -import java.nio.channels.Channels; +import java.util.Objects; import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.BlockingQueue; -import java.util.concurrent.Future; import org.eclipse.lsp4j.jsonrpc.Launcher; -import java.util.Objects; /** * Launches a client for a Language server and handles connection. @@ -167,5 +161,5 @@ public abstract class LSPClientLauncher extends Thread { } } - private static final Logger LOG = Logger.instance("LSPClientLauncher"); + protected static final Logger LOG = Logger.instance("LSPClientLauncher"); } diff --git a/app/src/main/java/com/itsaky/androidide/lsp/LanguageServerWrapper.java b/app/src/main/java/com/itsaky/androidide/lsp/LanguageServerWrapper.java index 23f484861..ea93bef04 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/LanguageServerWrapper.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/LanguageServerWrapper.java @@ -7,7 +7,7 @@ import com.itsaky.lsp.services.IDETextDocumentService; import com.itsaky.lsp.services.IDEWorkspaceService; import java.util.Collections; import java.util.List; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.CallHierarchyIncomingCall; import org.eclipse.lsp4j.CallHierarchyIncomingCallsParams; import org.eclipse.lsp4j.CallHierarchyItem; diff --git a/app/src/main/java/com/itsaky/androidide/lsp/StandardStreamsLauncher.java b/app/src/main/java/com/itsaky/androidide/lsp/StandardStreamsLauncher.java index 5f6b5b4e6..dfaee41db 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/StandardStreamsLauncher.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/StandardStreamsLauncher.java @@ -2,6 +2,8 @@ package com.itsaky.androidide.lsp; import com.blankj.utilcode.util.CloseUtils; import com.itsaky.lsp.services.IDELanguageServer; +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.util.concurrent.Future; @@ -16,8 +18,8 @@ public class StandardStreamsLauncher extends LSPClientLauncher { public StandardStreamsLauncher(AbstractLanguageClient client, InputStream in, OutputStream out) { super(client); - this.in = in; - this.out = out; + this.in = new BufferedInputStream( in ); + this.out = new BufferedOutputStream( out ); } @Override @@ -32,6 +34,7 @@ public class StandardStreamsLauncher extends LSPClientLauncher { try { listening.get(); } catch (Throwable th) { + LOG.error("listening.get error", th); } shutdown(); diff --git a/app/src/main/java/com/itsaky/androidide/lsp/client/java/JavaLanguageClient.java b/app/src/main/java/com/itsaky/androidide/lsp/client/java/JavaLanguageClient.java index 12c59e864..3a432fb87 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/client/java/JavaLanguageClient.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/client/java/JavaLanguageClient.java @@ -2,7 +2,7 @@ package com.itsaky.androidide.lsp.client.java; import com.itsaky.androidide.lsp.AbstractLanguageClient; import java.util.List; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.ApplyWorkspaceEditParams; import org.eclipse.lsp4j.ApplyWorkspaceEditResponse; import org.eclipse.lsp4j.ConfigurationParams; diff --git a/app/src/main/java/com/itsaky/androidide/lsp/handlers/JLSHandler.java b/app/src/main/java/com/itsaky/androidide/lsp/handlers/JLSHandler.java index 815ba6814..8da5894c7 100644 --- a/app/src/main/java/com/itsaky/androidide/lsp/handlers/JLSHandler.java +++ b/app/src/main/java/com/itsaky/androidide/lsp/handlers/JLSHandler.java @@ -6,16 +6,14 @@ import com.itsaky.androidide.lsp.LSPClientLauncher; import com.itsaky.androidide.lsp.LSPProvider; import com.itsaky.androidide.lsp.StandardStreamsLauncher; import com.itsaky.androidide.lsp.client.java.JavaLanguageClient; -import com.itsaky.androidide.shell.ShellServer; import com.itsaky.androidide.utils.Environment; import com.itsaky.androidide.utils.Logger; import com.itsaky.lsp.services.IDELanguageServer; import java.io.File; import java.util.ArrayList; import java.util.List; -import java.util.Locale; import java.util.Optional; -import java9.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletableFuture; import org.eclipse.lsp4j.InitializeParams; import org.eclipse.lsp4j.InitializeResult; import org.eclipse.lsp4j.InitializedParams; @@ -23,11 +21,22 @@ import org.eclipse.lsp4j.WorkspaceFolder; public class JLSHandler implements LSPHandler { - private static ShellServer mShell; + /** + * Why not use {@link com.itsaky.androidide.shell.ShellServer ShellServer} instead? + * Because it will try to read from the process's input stream + * and at the same time, LSP4J will try to do the same. But, + * as {@code ShellServer} will be started first, LSP4J will not he able to read at all. + *
+ * That's why we use a ProcessBuilder without redirecting {@code System.err} of the process
+ */
+ private static ProcessBuilder mShellBuilder;
+ private static Process mShell;
+
private static JavaLanguageClient javaClient;
private static LSPClientLauncher mLauncher;
- private static final Logger LOG = Logger.instance("LSP");
+ private static final Logger LOG = Logger.instance("JLSHandler");
+ private static final boolean QUIET = !StudioApp.DEBUG;
@Override
public void start(Runnable onStarted) {
@@ -35,21 +44,36 @@ public class JLSHandler implements LSPHandler {
return;
}
- final boolean quiet = false;
- mShell = StudioApp.getInstance().newShell((t -> LOG.verbose(t)), false);
- mShell.append(String.format(Locale.US, "java -jar %s%s", Environment.JLS_JAR.getAbsolutePath(), quiet ? /* IMPORTANT: Do not forget the leading space */ " --quiet" : ""), false);
-
- javaClient = new JavaLanguageClient(null, server -> storeServerInfoAndNotify(server, onStarted));
- javaClient.setActivityProvider(LSP.PROVIDER);
- mLauncher = new StandardStreamsLauncher(javaClient, mShell.getProcessInputStream(), mShell.getProcessOutputStream());
- mLauncher.start();
+ try {
+ // Why not directly use 'java' command?
+ // I tried doing the same, but it ends up throwing unexpected errors.
+ // Something related to FileSystem...
+ mShellBuilder = new ProcessBuilder("/system/bin/sh");
+ mShellBuilder.directory(Environment.HOME);
+ mShellBuilder.redirectErrorStream(false);
+
+ if(StudioApp.DEBUG) {
+ mShellBuilder.redirectError(new File("/sdcard/ide_xlog/process_error.txt"));
+ }
+
+ mShellBuilder.environment().putAll(Environment.getEnvironment(false));
+ mShell = mShellBuilder.start();
+
+ mShell.getOutputStream().write(("java -jar " + Environment.JLS_JAR.getAbsolutePath() + (QUIET ? " --quiet" : "") + "\n").getBytes());
+ mShell.getOutputStream().flush();
+
+ javaClient = new JavaLanguageClient(null, server -> storeServerInfoAndNotify(server, onStarted));
+ javaClient.setActivityProvider(LSP.PROVIDER);
+ mLauncher = new StandardStreamsLauncher(javaClient, mShell.getInputStream(), mShell.getOutputStream());
+ mLauncher.start();
+ } catch (Throwable th) {}
}
@Override
public Optional This is a functional interface
- * whose functional method is {@link #accept(Object, Object)}.
- *
- * @param