Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions app/src/main/java/com/itsaky/androidide/app/IDEApplication.kt
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.plus
import org.jetbrains.kotlin.cli.jvm.compiler.setupIdeaStandaloneExecution
import org.koin.android.ext.koin.androidContext
import org.koin.core.context.GlobalContext
import org.koin.core.context.startKoin
Expand Down Expand Up @@ -103,9 +102,6 @@ class IDEApplication :
private set

init {
System.setProperty("java.awt.headless", "true")
setupIdeaStandaloneExecution()

@Suppress("Deprecation")
Shell.setDefaultBuilder(
Shell.Builder
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,15 +30,15 @@ open class FilteredIndex<T : Indexable>(
/**
* Make a source's entries visible in query results.
*/
fun activateSource(sourceId: String) {
open fun activateSource(sourceId: String) {
activeSources.add(sourceId)
}

/**
* Hide a source's entries from query results.
* The data remains in the backing index.
*/
fun deactivateSource(sourceId: String) {
open fun deactivateSource(sourceId: String) {
activeSources.remove(sourceId)
}

Expand All @@ -49,21 +49,21 @@ open class FilteredIndex<T : Indexable>(
* This is the typical call on project sync: pass in all
* current classpath JAR paths.
*/
fun setActiveSources(sourceIds: Set<String>) {
open fun setActiveSources(sourceIds: Set<String>) {
activeSources.clear()
activeSources.addAll(sourceIds)
}

/**
* Returns the current set of active source IDs.
*/
fun activeSources(): Set<String> =
open fun activeSources(): Set<String> =
activeSources.toSet()

/**
* Returns true if the source is currently active (visible).
*/
fun isActive(sourceId: String): Boolean =
open fun isActive(sourceId: String): Boolean =
sourceId in activeSources

/**
Expand All @@ -72,24 +72,24 @@ open class FilteredIndex<T : Indexable>(
*
* Use this to check if a JAR needs indexing at all.
*/
suspend fun isCached(sourceId: String): Boolean =
open suspend fun isCached(sourceId: String): Boolean =
backing.containsSource(sourceId)

override fun query(query: IndexQuery): Sequence<T> {
if (query.sourceId != null && query.sourceId !in activeSources) {
if (query.sourceId != null && !isActive(query.sourceId)) {
return emptySequence()
}
val original = backing.query(query)
return original.filter { it.sourceId in activeSources }
return original.filter { isActive(it.sourceId) }
}

override suspend fun get(key: String): T? {
val entry = backing.get(key) ?: return null
return if (entry.sourceId in activeSources) entry else null
return if (isActive(entry.sourceId)) entry else null
}

override suspend fun containsSource(sourceId: String): Boolean {
return sourceId in activeSources && backing.containsSource(sourceId)
return isActive(sourceId) && backing.containsSource(sourceId)
}

override fun distinctValues(fieldName: String): Sequence<String> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,15 +126,32 @@ class InMemoryIndex<T : Indexable>(
}

for ((field, prefix) in query.prefixMatch) {
val buckets = prefixBuckets[field] ?: return@read emptySequence()
val lowerPrefix = prefix.lowercase()
val firstChar = lowerPrefix.firstOrNull() ?: continue
val bucket = buckets[firstChar] ?: return@read emptySequence()

val matching = bucket.asSequence()
.filter { it.lowerValue.startsWith(lowerPrefix) }
.map { it.key }
.toSet()
val buckets = prefixBuckets[field]
val matching: Set<String> = if (buckets != null) {
// Prefix-searchable: case-insensitive match via the lowercased buckets,
// mirroring SQLite's `lowerCol LIKE 'prefix%'`.
val lowerPrefix = prefix.lowercase()
val firstChar = lowerPrefix.firstOrNull()
if (firstChar == null) {
// Empty prefix == "field present", matching SQLite's `LIKE '%'`
// (which excludes rows where the column IS NULL).
buckets.values.flatMapTo(mutableSetOf()) { entries -> entries.map { it.key } }
} else {
val bucket = buckets[firstChar] ?: return@read emptySequence()
bucket.asSequence()
.filter { it.lowerValue.startsWith(lowerPrefix) }
.map { it.key }
.toSet()
}
} else {
// Not prefix-searchable: fall back to a case-sensitive prefix scan of the
// regular field map, mirroring SQLite's `col LIKE 'prefix%'` fallback.
val fieldMap = fieldMaps[field] ?: return@read emptySequence()
fieldMap.entries.asSequence()
.filter { (value, _) -> value.startsWith(prefix) }
.flatMap { (_, keys) -> keys.asSequence() }
.toSet()
}

candidates = intersect(candidates, matching)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ import java.io.Closeable
/**
* An index of symbols from JVM source and binary files.
*/
class JvmSymbolIndex(
open class JvmSymbolIndex(
private val backing: Index<JvmSymbol>,
private val indexer: BackgroundIndexer<JvmSymbol>,
) : FilteredIndex<JvmSymbol>(backing), WritableIndex<JvmSymbol> by backing, Closeable {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package org.appdevforall.codeonthego.indexing.jvm

import android.content.Context
import org.appdevforall.codeonthego.indexing.SQLiteIndex
import org.appdevforall.codeonthego.indexing.api.Index
import org.appdevforall.codeonthego.indexing.api.indexQuery
import org.appdevforall.codeonthego.indexing.jvm.KtFileMetadataDescriptor.KEY_IS_INDEXED
import org.appdevforall.codeonthego.indexing.jvm.KtFileMetadataDescriptor.KEY_PACKAGE
Expand All @@ -10,19 +11,19 @@ import java.io.Closeable
/**
* An index of [KtFileMetadata] entries, one per Kotlin source file.
*/
class KtFileMetadataIndex private constructor(
private val backing: SQLiteIndex<KtFileMetadata>,
class KtFileMetadataIndex(
private val backing: Index<KtFileMetadata>,
) : Closeable {

companion object {

/**
* Creates a [KtFileMetadataIndex] backed by an in-memory SQLite database.
* Creates a [KtFileMetadataIndex] backed by a SQLite database.
*
* The [context] is required by the AndroidX SQLite helpers even for in-memory
* databases; it is not used for any file I/O.
*/
fun create(
fun sqliteBacked(
context: Context,
dbName: String? = null
): KtFileMetadataIndex =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ class KotlinLanguageServer : ILanguageServer {

indexingRegistry.register(
key = KT_SOURCE_FILE_META_INDEX_KEY,
index = KtFileMetadataIndex.create(
index = KtFileMetadataIndex.sqliteBacked(
context = context,
dbName = KT_SOURCE_FILE_META_INDEX_KEY.name
)
Expand Down
Loading
Loading