diff --git a/src/main/kotlin/texlab/TextDocumentServiceImpl.kt b/src/main/kotlin/texlab/TextDocumentServiceImpl.kt index cd9878c24..48578e4ed 100644 --- a/src/main/kotlin/texlab/TextDocumentServiceImpl.kt +++ b/src/main/kotlin/texlab/TextDocumentServiceImpl.kt @@ -12,7 +12,7 @@ import texlab.build.BuildConfig import texlab.build.BuildEngine import texlab.build.BuildParams import texlab.build.BuildResult -import texlab.completion.OrderByQualityProvider +import texlab.completion.MatchQualityComparator import texlab.completion.bibtex.BibtexCitationActor import texlab.completion.bibtex.BibtexEntryTypeProvider import texlab.completion.bibtex.BibtexFieldNameProvider @@ -153,9 +153,6 @@ class TextDocumentServiceImpl(val workspaceActor: WorkspaceActor) : CustomTextDo BibtexEntryTypeProvider, BibtexFieldNameProvider, BibtexKernelCommandProvider) - .map { items -> items.distinctBy { it.label } } - .let { OrderByQualityProvider(it) } - .map { it.take(completionLimit) } private val symbolProvider: FeatureProvider> = FeatureProvider.concat( @@ -300,10 +297,19 @@ class TextDocumentServiceImpl(val workspaceActor: WorkspaceActor) : CustomTextDo override fun completion(params: CompletionParams) : CompletableFuture, CompletionList>> = future { - val items = runFeature(completionProvider, params.textDocument, params) + val items = workspaceActor.withWorkspace { workspace -> + val uri = URIHelper.parse(params.textDocument.uri) + val request = FeatureRequest(uri, workspace, params, logger) + val comparator = MatchQualityComparator(request.document, params.position) + + completionProvider.get(request) + .distinctBy { it.label } + .sortedWith(comparator) + .take(completionLimit) + } + val allIncludes = items.all { - it.kind == CompletionItemKind.Folder || - it.kind == CompletionItemKind.File + it.kind == CompletionItemKind.Folder || it.kind == CompletionItemKind.File } val isIncomplete = !allIncludes || items.size > completionLimit val list = CompletionList(isIncomplete, items) diff --git a/src/main/kotlin/texlab/completion/OrderByQualityProvider.kt b/src/main/kotlin/texlab/completion/MatchQualityComparator.kt similarity index 66% rename from src/main/kotlin/texlab/completion/OrderByQualityProvider.kt rename to src/main/kotlin/texlab/completion/MatchQualityComparator.kt index 8f97d1314..197deafe7 100644 --- a/src/main/kotlin/texlab/completion/OrderByQualityProvider.kt +++ b/src/main/kotlin/texlab/completion/MatchQualityComparator.kt @@ -1,39 +1,62 @@ package texlab.completion import org.eclipse.lsp4j.CompletionItem -import org.eclipse.lsp4j.CompletionParams +import org.eclipse.lsp4j.Position import texlab.BibtexDocument +import texlab.Document import texlab.LatexDocument import texlab.contains -import texlab.provider.FeatureProvider -import texlab.provider.FeatureRequest import texlab.syntax.bibtex.* import texlab.syntax.latex.LatexCommandSyntax import texlab.syntax.latex.LatexDocumentSyntax import texlab.syntax.latex.LatexGroupSyntax import texlab.syntax.latex.LatexTextSyntax -class OrderByQualityProvider(private val provider: FeatureProvider>) - : FeatureProvider> { +class MatchQualityComparator(private val document: Document, + private val position: Position) : Comparator { + override fun compare(left: CompletionItem, right: CompletionItem): Int { + val leftQuality = getQuality(left.label) + val rightQuality = getQuality(right.label) + return rightQuality.compareTo(leftQuality) + } + + private fun getQuality(label: String): Int { + val query = getName(document, position) ?: return -1 + if (label == query) { + return 7 + } + + if (label.equals(query, ignoreCase = true)) { + return 6 + } + + if (label.startsWith(query)) { + return 5 + } - override suspend fun get(request: FeatureRequest): List { - val name = getName(request) - return if (name == null) { - emptyList() - } else { - provider.get(request) - .sortedByDescending { getQuality(it.label, name) } + if (label.toLowerCase().startsWith(query.toLowerCase())) { + return 4 } + + if (label.contains(query)) { + return 3 + } + + if (label.toLowerCase().contains(query.toLowerCase())) { + return 2 + } + + return 1 } - private fun getName(request: FeatureRequest): String? { - return when (request.document) { + private fun getName(document: Document, position: Position): String? { + return when (document) { is LatexDocument -> { - val descendants = request.document.tree.root.descendants() + val descendants = document.tree.root.descendants() val node = descendants .filterIsInstance() - .lastOrNull { it.name.range.contains(request.params.position) } - ?: descendants.lastOrNull { it.range.contains(request.params.position) } + .lastOrNull { it.name.range.contains(position) } + ?: descendants.lastOrNull { it.range.contains(position) } when (node) { is LatexGroupSyntax -> "" @@ -44,14 +67,14 @@ class OrderByQualityProvider(private val provider: FeatureProvider { - val node = request.document.tree.root + val node = document.tree.root .descendants() - .lastOrNull { it.range.contains(request.params.position) } + .lastOrNull { it.range.contains(position) } when (node) { is BibtexDocumentSyntax -> "" is BibtexDeclarationSyntax -> { - if (node.type.range.contains(request.params.position)) { + if (node.type.range.contains(position)) { node.type.text.substring(1) } else { "" @@ -61,7 +84,7 @@ class OrderByQualityProvider(private val provider: FeatureProvider { - if (node.name.range.contains(request.params.position)) { + if (node.name.range.contains(position)) { node.name.text } else { "" @@ -81,32 +104,4 @@ class OrderByQualityProvider(private val provider: FeatureProvider { suspend fun get(request: FeatureRequest): R - fun map(transform: (R) -> C): FeatureProvider { - return create { request -> - transform(get(request)) - } - } - companion object { fun create(get: suspend (FeatureRequest) -> R): FeatureProvider { return object : FeatureProvider { diff --git a/src/test/kotlin/texlab/completion/OrderByQualityProviderTests.kt b/src/test/kotlin/texlab/completion/MatchQualityComparatorTests.kt similarity index 68% rename from src/test/kotlin/texlab/completion/OrderByQualityProviderTests.kt rename to src/test/kotlin/texlab/completion/MatchQualityComparatorTests.kt index fa452f2fc..c6fa264cb 100644 --- a/src/test/kotlin/texlab/completion/OrderByQualityProviderTests.kt +++ b/src/test/kotlin/texlab/completion/MatchQualityComparatorTests.kt @@ -6,14 +6,17 @@ import org.junit.jupiter.api.Test import texlab.WorkspaceBuilder import texlab.completion.latex.LatexKernelCommandProvider -class OrderByQualityProviderTests { +class MatchQualityComparatorTests { @Test fun `it should prioritize items that begin with the query`() = runBlocking { - val provider = OrderByQualityProvider(LatexKernelCommandProvider) val request = WorkspaceBuilder() .document("foo.tex", "\\usep") .completion("foo.tex", 0, 5) - val items = provider.get(request) + val comparator = MatchQualityComparator(request.document, request.params.position) + val items = LatexKernelCommandProvider + .get(request) + .sortedWith(comparator) + assertEquals("usepackage", items[0].label) } } diff --git a/src/test/kotlin/texlab/provider/FeatureProviderTests.kt b/src/test/kotlin/texlab/provider/FeatureProviderTests.kt index e6b5a52ac..5627d6e95 100644 --- a/src/test/kotlin/texlab/provider/FeatureProviderTests.kt +++ b/src/test/kotlin/texlab/provider/FeatureProviderTests.kt @@ -1,7 +1,8 @@ package texlab.provider import kotlinx.coroutines.runBlocking -import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertNull import org.junit.jupiter.api.Test import texlab.WorkspaceBuilder @@ -18,24 +19,6 @@ class FeatureProviderTests { } } - @Test - fun `it should create a new provider that maps the result`() = runBlocking { - val request = WorkspaceBuilder() - .document("foo.tex", "") - .request("foo.tex") {} - - val provider = NumberProvider(1) - val firstResult = provider.get(request) - - val transform = { x: Int? -> x?.plus(1) } - val result = provider - .map { transform(it) } - .get(request) - - assertNotNull(result) - assertEquals(transform(firstResult), result) - } - @Test fun `it should concatenate the results of the given providers`() = runBlocking { val request = WorkspaceBuilder()