On-demand additional edits computation for Class completion items

This commit is contained in:
Akash Yadav
2022-06-28 23:38:03 +05:30
parent ff462f9ba6
commit 8a53f71d46
7 changed files with 37 additions and 12 deletions
+1
View File
@@ -50,6 +50,7 @@ dependencies {
implementation androidx.appcompat
implementation androidx.ktx
implementation common.kotlin
implementation common.utilcode
implementation google.material
api project (':build-tools:tooling-api-model')
@@ -17,6 +17,8 @@
package com.itsaky.lsp.models
import android.os.Looper
import com.blankj.utilcode.util.ThreadUtils
import com.itsaky.androidide.fuzzysearch.FuzzySearch
import com.itsaky.androidide.tooling.api.model.IdeGradleProject
import com.itsaky.androidide.utils.ILogger
@@ -31,6 +33,9 @@ import com.itsaky.lsp.models.MatchLevel.PARTIAL_MATCH
import io.github.rosemoe.sora.text.Content
import io.github.rosemoe.sora.widget.CodeEditor
import java.nio.file.Path
import java.util.concurrent.*
import java.util.concurrent.TimeUnit.*
import java.util.function.*
data class CompletionParams(var position: Position, var file: Path) {
var content: CharSequence? = null
@@ -57,13 +62,12 @@ open class CompletionResult(items: List<CompletionItem>) {
val items: List<CompletionItem> = run {
var temp = items.toMutableList()
temp.sort()
if (TRIM_TO_MAX && temp.size > MAX_ITEMS) {
temp = temp.subList(0, MAX_ITEMS)
}
return@run temp
}
var isIncomplete = this.items.size < items.size
var isCached = false
@@ -88,7 +92,7 @@ open class CompletionResult(items: List<CompletionItem>) {
// Max limit has been reached
return
}
if (items is MutableList) {
this.items.add(item)
}
@@ -118,6 +122,8 @@ open class CompletionItem(
) :
io.github.rosemoe.sora.lang.completion.CompletionItem(label, detail), Comparable<CompletionItem> {
private val log = ILogger.newInstance(javaClass.simpleName)
var sortText: String? = sortText
get() {
if (field == null) {
@@ -138,6 +144,8 @@ open class CompletionItem(
var insertTextFormat: InsertTextFormat = insertTextFormat ?: PLAIN_TEXT
var postComputeAdditionalEdits: Supplier<List<TextEdit>>? = null
constructor() :
this(
"", // label
@@ -191,6 +199,11 @@ open class CompletionItem(
fun getLabel(): String = this.label as String
override fun performCompletion(editor: CodeEditor, text: Content, line: Int, column: Int) {
if (Looper.myLooper() != Looper.getMainLooper()) {
ThreadUtils.runOnUiThread { performCompletion(editor, text, line, column) }
return
}
val start = getIdentifierStart(text.getLine(line), column)
val shift = insertText.contains("$0")
@@ -204,7 +217,6 @@ open class CompletionItem(
if (i != 0) {
commit = "\n" + commit
}
editor.commitText(commit)
i++
}
@@ -223,6 +235,17 @@ open class CompletionItem(
}
}
if (postComputeAdditionalEdits != null) {
try {
log.debug("Computing text edits for selected completion item...")
this.additionalTextEdits =
CompletableFuture.supplyAsync(postComputeAdditionalEdits).get(200, MILLISECONDS)
} catch (e: Throwable) {
log.error("Unable to compute additional edits for completion item", e)
this.additionalTextEdits = null
}
}
if (additionalTextEdits != null && additionalTextEdits!!.isNotEmpty()) {
additionalTextEdits!!.forEach {
val s = it.range.start
@@ -250,17 +273,14 @@ open class CompletionItem(
}
private fun getIdentifierStart(text: CharSequence, end: Int): Int {
var start = end
while (start > 0) {
if (Character.isJavaIdentifierPart(text[start - 1])) {
start--
continue
}
break
}
return start
}
@@ -127,7 +127,7 @@ public class CompletionProvider extends AbstractServiceProvider implements IComp
result.markCached();
if (!result.isIncomplete() && result.getItems().size() > 10) {
if (!result.isIncomplete() && !result.getItems().isEmpty()) {
LOG.info("...using cached completion");
logCompletionDuration(started, result);
return result;
@@ -39,6 +39,7 @@ import com.itsaky.lsp.models.MatchLevel
import com.sun.source.tree.Tree
import com.sun.source.util.TreePath
import java.nio.file.Path
import java.util.function.*
import javax.lang.model.element.Element
import javax.lang.model.element.ElementKind.ANNOTATION_TYPE
import javax.lang.model.element.ElementKind.CLASS
@@ -75,7 +76,7 @@ abstract class IJavaCompletionProvider(
protected val log: ILogger = ILogger.newInstance(javaClass.name)
protected lateinit var filePackage: String
protected lateinit var fileImports: Set<String>
open fun complete(
task: CompileTask,
path: TreePath,
@@ -85,7 +86,7 @@ abstract class IJavaCompletionProvider(
val root = task.root(completingFile)
filePackage = root.`package`.packageName.toString()
fileImports = root.imports.map { it.qualifiedIdentifier.toString() }.toSet()
return doComplete(task, path, partial, endsWithParen)
return doComplete(task, path, partial, endsWithParen);
}
/**
@@ -201,7 +202,9 @@ abstract class IJavaCompletionProvider(
val data = CompletionData()
data.className = className
item.data = data
item.additionalTextEdits = EditHelper.addImportIfNeeded(compiler, file, imports, className)
item.postComputeAdditionalEdits = Supplier {
EditHelper.addImportIfNeeded(compiler, file, imports, className)
}
return item
}
@@ -179,7 +179,7 @@ class ScopeCompletionProvider(
if (item.additionalTextEdits == null) {
item.additionalTextEdits = mutableListOf()
}
imports.removeIf { "java.lang." == it || fileImports.contains(it) || filePackage == it }
if (imports.isNotEmpty()) {
for (className in imports) {
@@ -56,6 +56,7 @@ public class AddImport extends Rewrite {
file, new TextEdit[] {new TextEdit(new Range(point, point), text)});
}
@SuppressWarnings("Since15")
private Position insertPosition(@NonNull ParseTask task) {
List<? extends ImportTree> imports = task.root.getImports();
for (ImportTree i : imports) {