mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
fix(projects): update entries from module source class indices on file events
This commit is contained in:
Binary file not shown.
@@ -220,6 +220,10 @@ open class ClassTrie(val root: Node = Node()) {
|
||||
return children.computeIfAbsent(name) { Node(it, qualifiedName, this) }
|
||||
}
|
||||
|
||||
open fun removeChild(child: Node) {
|
||||
this.children.remove(child.name)
|
||||
}
|
||||
|
||||
open fun allClassNames(): Set<String> {
|
||||
return this.allClassNodes().map { it.qualifiedName }.toSet()
|
||||
}
|
||||
|
||||
+53
-8
@@ -32,9 +32,11 @@ import com.itsaky.androidide.projects.util.ProjectTransformer
|
||||
import com.itsaky.androidide.tasks.executeAsync
|
||||
import com.itsaky.androidide.tooling.api.IProject
|
||||
import com.itsaky.androidide.tooling.api.messages.result.InitializeResult
|
||||
import com.itsaky.androidide.utils.DocumentUtils
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
import com.itsaky.androidide.utils.flashError
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import kotlin.io.path.extension
|
||||
import kotlin.io.path.isDirectory
|
||||
@@ -148,10 +150,6 @@ object ProjectManager : EventReceiver {
|
||||
return app
|
||||
}
|
||||
|
||||
fun getApplicationResDirectories(): Set<File> {
|
||||
return getApplicationModule()?.getResourceDirectories() ?: emptySet()
|
||||
}
|
||||
|
||||
fun notifyProjectUpdate() {
|
||||
|
||||
executeAsync {
|
||||
@@ -170,16 +168,18 @@ object ProjectManager : EventReceiver {
|
||||
}
|
||||
}
|
||||
|
||||
fun findModuleForFile(file: File): ModuleProject? {
|
||||
@JvmOverloads
|
||||
fun findModuleForFile(file: File, checkExistance: Boolean = false): ModuleProject? {
|
||||
if (!checkInit()) {
|
||||
return null
|
||||
}
|
||||
|
||||
return this.rootProject!!.findModuleForFile(file)
|
||||
return this.rootProject!!.findModuleForFile(file, checkExistance)
|
||||
}
|
||||
|
||||
fun findModuleForFile(file: Path): ModuleProject? {
|
||||
return findModuleForFile(file.toFile())
|
||||
@JvmOverloads
|
||||
fun findModuleForFile(file: Path, checkExistance: Boolean = false): ModuleProject? {
|
||||
return findModuleForFile(file.toFile(), checkExistance)
|
||||
}
|
||||
|
||||
fun containsSourceFile(file: Path): Boolean {
|
||||
@@ -187,6 +187,10 @@ object ProjectManager : EventReceiver {
|
||||
return false
|
||||
}
|
||||
|
||||
if (!Files.exists(file)) {
|
||||
return false
|
||||
}
|
||||
|
||||
for (module in this.rootProject!!.subModules) {
|
||||
if (module !is ModuleProject) {
|
||||
continue
|
||||
@@ -245,18 +249,55 @@ object ProjectManager : EventReceiver {
|
||||
@Subscribe(threadMode = BACKGROUND)
|
||||
fun onFileCreated(event: FileCreationEvent) {
|
||||
generateSourcesIfNecessary(event)
|
||||
|
||||
if (DocumentUtils.isJavaFile(event.file.toPath())) {
|
||||
findModuleForFile(event.file)?.let {
|
||||
val sourceRoot = it.findSourceRoot(event.file) ?: return@let
|
||||
|
||||
// add the source node entry
|
||||
it.compileJavaSourceClasses.append(event.file.toPath(), sourceRoot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@Subscribe(threadMode = BACKGROUND)
|
||||
fun onFileDeleted(event: FileDeletionEvent) {
|
||||
generateSourcesIfNecessary(event)
|
||||
|
||||
// Remove the source node entry
|
||||
// Do not check for Java file DocumentUtils.isJavaFile(...) as it checks for file existence as
|
||||
// well. As the file is already deleted, it will always return false
|
||||
if (event.file.extension == "java") {
|
||||
findModuleForFile(event.file)
|
||||
?.compileJavaSourceClasses
|
||||
?.findSource(event.file.toPath())
|
||||
?.let { it.parent?.removeChild(it) }
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused")
|
||||
@Subscribe(threadMode = BACKGROUND)
|
||||
fun onFileRenamed(event: FileRenameEvent) {
|
||||
generateSourcesIfNecessary(event)
|
||||
|
||||
// Do not check for Java file DocumentUtils.isJavaFile(...) as it checks for file existence as
|
||||
// well. As the file is already renamed to another filename, it will always return false
|
||||
if (event.file.extension == "java") {
|
||||
// remove the source node entry
|
||||
findModuleForFile(event.file)
|
||||
?.compileJavaSourceClasses
|
||||
?.findSource(event.file.toPath())
|
||||
?.let { it.parent?.removeChild(it) }
|
||||
}
|
||||
|
||||
if (DocumentUtils.isJavaFile(event.newFile.toPath())) {
|
||||
findModuleForFile(event.newFile)?.let {
|
||||
val sourceRoot = it.findSourceRoot(event.newFile) ?: return@let
|
||||
// add the new source node entry
|
||||
it.compileJavaSourceClasses.append(event.newFile.toPath(), sourceRoot)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateSourcesIfNecessary(event: FileEvent) {
|
||||
@@ -269,6 +310,10 @@ object ProjectManager : EventReceiver {
|
||||
generateSources(builder)
|
||||
}
|
||||
|
||||
private fun ModuleProject.findSourceRoot(file: File): Path? {
|
||||
return getCompileSourceDirectories().find { file.path.startsWith(it.path) }?.toPath()
|
||||
}
|
||||
|
||||
private fun isResource(file: File): Boolean {
|
||||
val module = findModuleForFile(file) ?: return false
|
||||
if (module is AndroidModule) {
|
||||
|
||||
@@ -33,7 +33,7 @@ import java.util.concurrent.*
|
||||
* @param name The display name of the project.
|
||||
* @param description The project description.
|
||||
* @param path The project path (same as Gradle project paths). For example, `:app`,
|
||||
* `:module:submodule`, etc. Root project is always represented by path `:`.
|
||||
* `:module:submodule`, etc. Root project is always represented by path `:`.
|
||||
* @param projectDir The project directory.
|
||||
* @param buildDir The build directory of the project.
|
||||
* @param buildScript The Gradle buildscript file of the project.
|
||||
@@ -124,7 +124,13 @@ open class Project(
|
||||
return findModuleForFile(file.toFile())
|
||||
}
|
||||
|
||||
fun findModuleForFile(file: File): ModuleProject? {
|
||||
@JvmOverloads
|
||||
fun findModuleForFile(file: File, checkExistance: Boolean = false): ModuleProject? {
|
||||
|
||||
if (!file.exists() && checkExistance) {
|
||||
return null
|
||||
}
|
||||
|
||||
val path = file.path
|
||||
var longestPath = ""
|
||||
var moduleWithLongestPath: ModuleProject? = null
|
||||
|
||||
+55
-9
@@ -18,18 +18,23 @@
|
||||
package com.itsaky.androidide.projects.api
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import com.itsaky.androidide.eventbus.events.file.FileCreationEvent
|
||||
import com.itsaky.androidide.eventbus.events.file.FileDeletionEvent
|
||||
import com.itsaky.androidide.eventbus.events.file.FileRenameEvent
|
||||
import com.itsaky.androidide.lookup.Lookup
|
||||
import com.itsaky.androidide.projects.ProjectManager
|
||||
import com.itsaky.androidide.projects.builder.BuildService
|
||||
import com.itsaky.androidide.tooling.api.messages.InitializeProjectMessage
|
||||
import com.itsaky.androidide.tooling.testing.ToolingApiTestLauncher
|
||||
import com.itsaky.androidide.utils.SourceClassTrie.SourceNode
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
import java.io.File
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
import kotlin.io.path.writeText
|
||||
|
||||
/** @author Akash Yadav */
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@@ -40,9 +45,8 @@ class ModuleProjectTest {
|
||||
fun test() {
|
||||
val (server, project) = ToolingApiTestLauncher().launchServer()
|
||||
server.initialize(InitializeProjectMessage(File("../../tests/test-project").absolutePath)).get()
|
||||
|
||||
|
||||
Lookup.DEFAULT.register(BuildService.KEY_PROJECT_PROXY, project)
|
||||
ProjectManager.setupProject()
|
||||
|
||||
verifyProjectManagerAPIs()
|
||||
|
||||
@@ -177,18 +181,35 @@ class ModuleProjectTest {
|
||||
}
|
||||
|
||||
private fun verifyProjectManagerAPIs() {
|
||||
|
||||
val testCls =
|
||||
Paths.get("../../tests/test-project/app/src/main/java/com/itsaky/test/app/Test.java")
|
||||
.toAbsolutePath()
|
||||
.normalize()
|
||||
val testCls_renamed = testCls.parent!!.resolve("TestRenamed.java")
|
||||
|
||||
if (Files.exists(testCls)) {
|
||||
Files.delete(testCls)
|
||||
}
|
||||
|
||||
if (Files.exists(testCls_renamed)) {
|
||||
Files.delete(testCls_renamed)
|
||||
}
|
||||
|
||||
ProjectManager.setupProject()
|
||||
|
||||
val root = ProjectManager.rootProject
|
||||
assertThat(root).isNotNull()
|
||||
assertThat(root!!.path).isEqualTo(":")
|
||||
|
||||
val source =
|
||||
root.projectDir.toPath().resolve("app/src/main/java/com/itsaky/test/app/MainActivity.java")
|
||||
val moduleForFile = root.findModuleForFile(source)
|
||||
assertThat(moduleForFile).isNotNull()
|
||||
assertThat(moduleForFile!!.path).isEqualTo(":app")
|
||||
assertThat(moduleForFile.projectDir.path).isEqualTo(File(root.projectDir, "app").path)
|
||||
val module = root.findModuleForFile(source)
|
||||
assertThat(module).isNotNull()
|
||||
assertThat(module!!.path).isEqualTo(":app")
|
||||
assertThat(module.projectDir.path).isEqualTo(File(root.projectDir, "app").path)
|
||||
|
||||
val sourceNode = moduleForFile.compileJavaSourceClasses.findSource(source)
|
||||
val sourceNode = module.compileJavaSourceClasses.findSource(source)
|
||||
assertThat(sourceNode).isNotNull()
|
||||
assertThat(sourceNode!!.isClass).isTrue()
|
||||
assertThat(sourceNode.name).isEqualTo("MainActivity")
|
||||
@@ -196,5 +217,30 @@ class ModuleProjectTest {
|
||||
assertThat(sourceNode.qualifiedName).isEqualTo("com.itsaky.test.app.MainActivity")
|
||||
assertThat(sourceNode.children).isEmpty()
|
||||
assertThat(Files.isSameFile(source, sourceNode.file)).isTrue()
|
||||
|
||||
// make sure the files are not indexed
|
||||
assertThat(ProjectManager.containsSourceFile(testCls)).isFalse()
|
||||
assertThat(ProjectManager.containsSourceFile(testCls_renamed)).isFalse()
|
||||
|
||||
testCls.writeText("public class Test { }")
|
||||
ProjectManager.onFileCreated(FileCreationEvent(testCls.toFile()))
|
||||
assertThat(ProjectManager.containsSourceFile(testCls)).isTrue()
|
||||
assertThat(ProjectManager.containsSourceFile(testCls_renamed)).isFalse()
|
||||
assertThat(ProjectManager.findModuleForFile(testCls, true)).isEqualTo(module)
|
||||
assertThat(ProjectManager.findModuleForFile(testCls_renamed, true)).isNull()
|
||||
|
||||
Files.move(testCls, testCls_renamed)
|
||||
ProjectManager.onFileRenamed(FileRenameEvent(testCls.toFile(), testCls_renamed.toFile()))
|
||||
assertThat(ProjectManager.containsSourceFile(testCls)).isFalse()
|
||||
assertThat(ProjectManager.containsSourceFile(testCls_renamed)).isTrue()
|
||||
assertThat(ProjectManager.findModuleForFile(testCls, true)).isNull()
|
||||
assertThat(ProjectManager.findModuleForFile(testCls_renamed, true)).isEqualTo(module)
|
||||
|
||||
Files.delete(testCls_renamed)
|
||||
ProjectManager.onFileDeleted(FileDeletionEvent(testCls_renamed.toFile()))
|
||||
assertThat(ProjectManager.containsSourceFile(testCls)).isFalse()
|
||||
assertThat(ProjectManager.containsSourceFile(testCls_renamed)).isFalse()
|
||||
assertThat(ProjectManager.findModuleForFile(testCls, true)).isNull()
|
||||
assertThat(ProjectManager.findModuleForFile(testCls_renamed, true)).isNull()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
public class Test { }
|
||||
Reference in New Issue
Block a user