AndroidIDEOfficial / AndroidIDE

AndroidIDE is an IDE for Android to develop full featured Android apps.
https://m.androidide.com
GNU General Public License v3.0
2.38k stars 312 forks source link

Inconsistent auto completion #50

Closed dhaigit closed 2 years ago

dhaigit commented 2 years ago

The auto completion is kind of iffy. Sometimes it shows sometimes it doesn't. Looking at the ide messages, I see that it isn't always able to process the classpath and ends up just being able to recognize only keywords and local variables.

A lot of the times, it even shows nothing. With each letter we enter, the idelogs view spits out:

JavaAutoComplete: Completion error java.io.IOException: Stream closed
    at java.lang.ProcessBuilder$NullOutputStream.write(ProcessBuilder.java:433)
    at java.io.OutputStream.write(OutputStream.java:116)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.write(BufferedOutputStream.java:126)
    at java.io.BufferedOutputStream.flushBuffer(BufferedOutputStream.java:82)
    at java.io.BufferedOutputStream.flush(BufferedOutputStream.java:140)
    at org.eclipse.lsp4j.jsonrpc.json.StreamMessageConsumer.consume(StreamMessageConsumer.java:69)
 Caused by: org.eclipse.lsp4j.jsonrpc.JsonRpcException: java.io.IOException: Stream closed
    at org.eclipse.lsp4j.jsonrpc.json.StreamMessageConsumer.consume(StreamMessageConsumer.java:72)
    at org.eclipse.lsp4j.jsonrpc.RemoteEndpoint.request(RemoteEndpoint.java:161)
    at org.eclipse.lsp4j.jsonrpc.services.EndpointProxy.invoke(EndpointProxy.java:91)
    at java.lang.reflect.Proxy.invoke(Proxy.java:913)
    at $Proxy5.completion(Unknown Source)
    at com.itsaky.androidide.language.java.JavaAutoComplete.getAutoCompleteItems(JavaAutoComplete.java:52)
 Caused by: java.util.concurrent.ExecutionException: org.eclipse.lsp4j.jsonrpc.JsonRpcException: java.io.IOException: Stream closed
    at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:359)
    at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1921)
    at com.itsaky.androidide.language.java.JavaAutoComplete.getAutoCompleteItems(JavaAutoComplete.java:60)
    at io.github.rosemoe.editor.widget.EditorAutoCompleteWindow$MatchThread.run(EditorAutoCompleteWindow.java:350)
itsaky commented 2 years ago

The java language server is started in the JVM and not ART. We use a process builder to start the language server process. This does not work so good.

I'm planning of using something else for completion, or fall back to using JDK 8's compiler.

itsaky commented 2 years ago

@dhaigit The language server is no longer dependent on the JVM. The java compiler is now included in the IDE and the language server too. I made some improvements in the java completion. Could you please check it?

dhaigit commented 2 years ago

Finally you have updated after many days, lol.

The new auto completion system seems to work better and more consistently. Still, there is a problem that I can't pinpoint at exactly when or why it happened but I think it did sometimes (not every time) while the IDE was doing a build and I was typing some letters to test out the auto completion.

These messages were from the IDE logs screen:

JavaCompletionProvider: Complete at MainActivity.java(29,10)... 
CompletionMatchThread: Error computing completion java.lang.RuntimeException: Compiler us already in use.
    at com.itsaky.lsp.java.compiler.ReusableCompiler.getTask(ReusableCompiler.java:110)
    at com.itsaky.lsp.java.compiler.CompileBatch.batchTask(CompileBatch.java:137)
    at com.itsaky.lsp.java.compiler.CompileBatch.<init>(CompileBatch.java:59)
    at com.itsaky.lsp.java.compiler.JavaCompilerService.doCompile(JavaCompilerService.java:113)
    at com.itsaky.lsp.java.compiler.JavaCompilerService.loadCompile(JavaCompilerService.java:101)
    at com.itsaky.lsp.java.compiler.JavaCompilerService.compileBatch(JavaCompilerService.java:135)
    at com.itsaky.lsp.java.compiler.JavaCompilerService.compile(JavaCompilerService.java:354)
    at com.itsaky.lsp.java.providers.CompletionProvider.compileAndComplete(CompletionProvider.java:149)
    at com.itsaky.lsp.java.providers.CompletionProvider.complete(CompletionProvider.java:129)
    at com.itsaky.lsp.java.providers.CompletionProvider.complete(CompletionProvider.java:111)
    at com.itsaky.androidide.language.java.JavaAutoComplete.lambda$getAutoCompleteItems$0(JavaAutoComplete.java:59)
    at com.itsaky.androidide.language.java.JavaAutoComplete$$ExternalSyntheticLambda1.get(Unknown Source:6)
    at java.util.concurrent.CompletableFuture$AsyncSupply.run(CompletableFuture.java:1625)
    at java.util.concurrent.CompletableFuture$AsyncSupply.exec(CompletableFuture.java:1617)
    at java.util.concurrent.ForkJoinTask.doExec(ForkJoinTask.java:285)
    at java.util.concurrent.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1152)
    at java.util.concurrent.ForkJoinPool.scan(ForkJoinPool.java:1990)
    at java.util.concurrent.ForkJoinPool.runWorker(ForkJoinPool.java:1938)
    at java.util.concurrent.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:157)
 Caused by: java.util.concurrent.ExecutionException: java.lang.RuntimeException: Compiler us already in use.
    at java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:359)
    at java.util.concurrent.CompletableFuture.get(CompletableFuture.java:1921)
    at com.itsaky.androidide.language.java.JavaAutoComplete.getAutoCompleteItems(JavaAutoComplete.java:62)
    at io.github.rosemoe.editor.widget.EditorAutoCompleteWindow$MatchThread.run(EditorAutoCompleteWindow.java:348)

At that moment, auto completion did not show anything while I was typing. (not even when the building process was done)

I managed to make it work again by selecting quick run or one of the two assemble options (after waiting for the ongoing one to finish first of course)

Also, maybe you could tweak to make completion suggestions appear a little more snappy.

Lastly, the Diagnostics view never showed anything.

dhaigit commented 2 years ago

Also, maybe you could tweak to make completion suggestions appear a little more snappy.

I just noticed something while playing around with the auto completion.

Open a simple project and make sure auto completion is working, then try this:

  1. Type "Toas"
  2. You should see "android.widget.Toast" appear in the list below the cursor.
  3. Now, tap backspace to delete "s"
  4. Type "s" again
  5. Keep deleting "s" and typing "s" quickly

You will notice that the big red icon "C" (for class) at the start of the list item jitters (but the rest of the line does not)

Auto completion should appear smoother if that is fixed.

Maybe we could find some more ways to improve it. I think quick and instant auto completion would make a very positive user experience.

itsaky commented 2 years ago

That is because the height of the icon widget is set dynamically to match the height of the completion item view. See this.

But I'll fix it.

dhaigit commented 2 years ago

Yes! It appears snappier now without the jittery completion results list.

Some more related thoughts:

When I open a project, I would like to be able to start typing and see the completion results as soon as possible. Currently, the IDE is always trying to run assembleDebug the moment we open a project, and it usually takes a while (also depends on the size of the project of course) before I could use auto completion.

Do we really need to assembleDebug every time we open a project? We do need to quickly analyze the project for possible compile errors so we could fix them, but probably not doing a build yet.

So maybe we could shorten the time from opening a project to the time the auto completion starting to work.

itsaky commented 2 years ago

The initializeIDEProject task is executed after the java compilation task. This initialize task allows us to get the list of dependencies (including other project details). Then the paths of those dependency jars are passed to the java language server. So, yes, that build is needed.

There is another way of getting the details we need. We could use the Gradle Tooling API. But we'll be able to use it only on the JVM. That's because the tooling API uses class loaders.

dhaigit commented 2 years ago

Yes! It appears snappier now without the jittery completion results list.

I just noticed the icon "F" still needs to be fixed.

itsaky commented 2 years ago

I didn't get any issues with the 'F' letter in completion window. Any specific way to reprodice it?

(Accidentally closed the issue).

dhaigit commented 2 years ago

Any specific way to reprodice it?

It's "F" for "Field" so any results list with fields in it would do. I think starting with "Me..." has plenty of those.

  1. Open a simple project and make sure autocompletion is working.
  2. Type "Med" (without quotes)
  3. Tap backspace to delete "d"
  4. Type "d"
  5. Keep deleting and typing "d"

Any list item that contains a field will jitter.

dhaigit commented 2 years ago

Even with the latest build, autocompletion still isn't 100% consistent. It will still sometimes fail with "...already in use" message. Here are my workarounds (that seem to work for me) that I have shared in another post, in order to continue using the IDE when it happens.

  1. Keep checking it out until it's working. (e.g., keep typing and deleting "t" repeatedly) Be patient because it could take a while. This works most of the time, but there will be times when no matter how many times we repeat doing, it still won't work. That's when we should try number 2.
  2. Run a build again. Use number 1 to test to see when it's starting to work. With the latest build, I've always managed to get it working again after this method.

I wish we could just open a project and start coding right away with perfect autocompletion, but according to Itsaky, we can't avoid that (long) initial build (that sometimes causes autocompletion failure) for now.

dhaigit commented 2 years ago

Any list item that contains a field will jitter.

With more testing, I have found that the jittering is caused not only specifically by having a field but anything that has the added "deprecated since..." info below it.

itsaky commented 2 years ago

Okay. I think that happens because we check the API details in the completion adapter itself (getView method). Takes a few milliseconds to compute. Maybe we could animate it?

Computing it in completion provider itself will make the completions a bit slower.

dhaigit commented 2 years ago

It flickers because of the switching back and forth between GONE and VISIBLE. I have two suggestions for choice:

  1. Don't set the API info view to GONE. Instead, let it say something like "API info not available" in grayed out text.

  2. Move API info somewhere else. For example:

   C   Toast                         Since
class android.widget.Toast API 1

(or maybe API info on the right and kind info on the left)