mirror of
https://gitee.com/zhangsken/AndroidIDE.git
synced 2026-10-16 07:49:44 +08:00
Created ClassTrie to manage classes of a module
This commit is contained in:
@@ -20,34 +20,22 @@ package com.itsaky.androidide.handlers
|
||||
import android.content.Context
|
||||
import com.itsaky.androidide.EditorActivity
|
||||
import com.itsaky.androidide.eventbus.events.Event
|
||||
import com.itsaky.androidide.eventbus.events.EventReceiver
|
||||
import com.itsaky.androidide.utils.ILogger
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
/**
|
||||
* Base class for event handlers.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
abstract class BaseEventHandler {
|
||||
abstract class BaseEventHandler : EventReceiver {
|
||||
|
||||
protected val log = ILogger.newInstance(javaClass.simpleName)
|
||||
|
||||
/** Registeres this handler with [EventBus]. */
|
||||
fun register() {
|
||||
if (!EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
}
|
||||
|
||||
/** Unregisteres this handler from [EventBus]. */
|
||||
fun unregister() {
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
|
||||
protected open fun checkIsEditorActivity(event: Event): Boolean {
|
||||
return event.get(Context::class.java) is EditorActivity
|
||||
}
|
||||
|
||||
|
||||
protected open fun logCannotHandle(event: Event) {
|
||||
log.warn("Context is not EditorActivity. Cannot handle ${event.javaClass.simpleName} event.")
|
||||
}
|
||||
|
||||
@@ -48,12 +48,12 @@ import com.itsaky.androidide.utils.ProjectWriter
|
||||
import com.itsaky.toaster.Toaster.Type.ERROR
|
||||
import com.itsaky.toaster.Toaster.Type.SUCCESS
|
||||
import com.unnamed.b.atv.model.TreeNode
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.regex.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.greenrobot.eventbus.Subscribe
|
||||
import org.greenrobot.eventbus.ThreadMode.MAIN
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.regex.*
|
||||
|
||||
/**
|
||||
* Handles events related to files in filetree.
|
||||
|
||||
@@ -26,6 +26,8 @@ java {
|
||||
|
||||
dependencies {
|
||||
implementation common.jkotlin
|
||||
|
||||
api project (path: ':build-tools:eventbus')
|
||||
}
|
||||
|
||||
compileKotlin {
|
||||
|
||||
+17
-11
@@ -15,20 +15,26 @@
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.projects
|
||||
package com.itsaky.androidide.eventbus.events
|
||||
|
||||
import org.junit.Test
|
||||
|
||||
import org.junit.Assert.*
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
* Any class that receives an [Event].
|
||||
*
|
||||
* See [testing documentation](http://d.android.com/tools/testing).
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ExampleUnitTest {
|
||||
@Test
|
||||
fun addition_isCorrect() {
|
||||
assertEquals(4, 2 + 2)
|
||||
interface EventReceiver {
|
||||
|
||||
/** Registeres this handler with [EventBus]. */
|
||||
fun register() {
|
||||
if (!EventBus.getDefault().isRegistered(this)) {
|
||||
EventBus.getDefault().register(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Unregisteres this handler from [EventBus]. */
|
||||
fun unregister() {
|
||||
EventBus.getDefault().unregister(this)
|
||||
}
|
||||
}
|
||||
@@ -29,6 +29,9 @@ android {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
api project (path: ':build-tools:eventbus')
|
||||
api project (path: ':build-tools:eventbus-events')
|
||||
|
||||
implementation project (path: ':build-tools:tooling-api')
|
||||
implementation project (path: ':common')
|
||||
|
||||
|
||||
+17
-1
@@ -17,6 +17,8 @@
|
||||
|
||||
package com.itsaky.androidide.projects.api
|
||||
|
||||
import com.itsaky.androidide.eventbus.events.EventReceiver
|
||||
import com.itsaky.androidide.projects.util.ClassTrie
|
||||
import com.itsaky.androidide.tooling.api.model.GradleTask
|
||||
import java.io.File
|
||||
|
||||
@@ -35,7 +37,10 @@ abstract class ModuleProject(
|
||||
tasks: List<GradleTask>
|
||||
) :
|
||||
Project(name, description, path, projectDir, buildDir, buildScript, tasks),
|
||||
com.itsaky.androidide.tooling.api.model.ModuleProject {
|
||||
com.itsaky.androidide.tooling.api.model.ModuleProject,
|
||||
EventReceiver {
|
||||
|
||||
private val classes = ClassTrie()
|
||||
|
||||
/**
|
||||
* Get the source directories of this module (transitive).
|
||||
@@ -43,4 +48,15 @@ abstract class ModuleProject(
|
||||
* @return The source directories.
|
||||
*/
|
||||
abstract fun getSourceDirectories(): Set<File>
|
||||
|
||||
override fun register() {
|
||||
super.register()
|
||||
}
|
||||
|
||||
/** Finds the source files from source directories and indexes them. */
|
||||
fun indexSources() {
|
||||
val sourceDirs = getSourceDirectories()
|
||||
}
|
||||
|
||||
fun findClass(className: String) {}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.projects.util
|
||||
|
||||
import java.util.function.*
|
||||
|
||||
/**
|
||||
* Maps classes with their package name segments.
|
||||
*
|
||||
* @author Akash Yadav
|
||||
*/
|
||||
class ClassTrie {
|
||||
|
||||
val root = Node()
|
||||
|
||||
/**
|
||||
* Appends the class name entry to this trie.
|
||||
*
|
||||
* @param name The fully qualified class name.
|
||||
* @return The added node.
|
||||
*/
|
||||
fun append(name: String): Node {
|
||||
val segments = segments(name)
|
||||
var node = root
|
||||
for (segment in segments) {
|
||||
node = node.createChild(segment)
|
||||
}
|
||||
node.isClass = true
|
||||
return node
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the class name node with the given fully qualified name.
|
||||
*
|
||||
* @param name The fully qualified name of the package segment or class name to remove.
|
||||
*/
|
||||
fun remove(name: String) {
|
||||
remove(name, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the nodes (package segments and class names) with the given fully qualified name. A
|
||||
* [Predicate] can be provided to check which nodes should be deleted.
|
||||
*
|
||||
* @param name The fully qualified name of the package segment or the class.
|
||||
* @param predicate The predicate which can be used to test which entries should be deleted.
|
||||
*/
|
||||
fun remove(name: String, predicate: Predicate<Node>?) {
|
||||
val segments = segments(name)
|
||||
val condition = predicate ?: Predicate { it.isClass }
|
||||
var node: Node? = root
|
||||
for (segment in segments) {
|
||||
if (node == null || node.children.isEmpty()) {
|
||||
break
|
||||
}
|
||||
|
||||
val next = node.children[segment]
|
||||
if (next != null && condition.test(next)) {
|
||||
node.children.remove(next.name)
|
||||
}
|
||||
node = next
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all class names in the given package.
|
||||
*
|
||||
* @param packageName The package name to list classes from.
|
||||
*/
|
||||
fun findClassName(packageName: String): List<String> {
|
||||
val segments = segments(packageName)
|
||||
val classes = mutableListOf<String>()
|
||||
val curr = StringBuilder()
|
||||
var node: Node? = root
|
||||
for (segement in segments) {
|
||||
if (node == null || node.children.isEmpty() || !node.children.containsKey(segement)) {
|
||||
break
|
||||
}
|
||||
|
||||
if (node.isClass) {
|
||||
var name = "$curr.$segement"
|
||||
if (curr.isEmpty()) {
|
||||
name = segement
|
||||
}
|
||||
classes.add(name)
|
||||
} else {
|
||||
if (curr.isNotEmpty()) {
|
||||
curr.append(".")
|
||||
}
|
||||
curr.append(segement)
|
||||
}
|
||||
|
||||
node = node.children[segement]
|
||||
}
|
||||
|
||||
if (node == null || node.children.isEmpty()) {
|
||||
return classes
|
||||
}
|
||||
|
||||
node.children.values.forEach {
|
||||
addRecursively(it, curr.toString(), classes)
|
||||
}
|
||||
return classes
|
||||
}
|
||||
|
||||
private fun addRecursively(node: Node, curr: String, classes: MutableList<String>) {
|
||||
val segement = node.name
|
||||
var packageName = curr
|
||||
if (node.isClass) {
|
||||
var name = "$packageName.$segement"
|
||||
if (packageName.isEmpty()) {
|
||||
name = segement
|
||||
}
|
||||
classes.add(name)
|
||||
} else {
|
||||
packageName = if (curr.isEmpty()) {
|
||||
segement
|
||||
} else {
|
||||
"$packageName.$segement"
|
||||
}
|
||||
}
|
||||
|
||||
if (node.children.isEmpty()) {
|
||||
return
|
||||
}
|
||||
|
||||
node.children.values.forEach {
|
||||
addRecursively(it, packageName, classes)
|
||||
}
|
||||
}
|
||||
|
||||
private fun segments(name: String): List<String> {
|
||||
return if (name.contains('.')) {
|
||||
name.split(".")
|
||||
} else {
|
||||
listOf(name)
|
||||
}
|
||||
}
|
||||
|
||||
/** A Node can be a package segment or a class name in the package trie. */
|
||||
class Node(val name: String) {
|
||||
|
||||
internal constructor() : this("")
|
||||
|
||||
val children: MutableMap<String, Node> = mutableMapOf()
|
||||
var isClass = false
|
||||
|
||||
fun createChild(name: String): Node {
|
||||
return children.computeIfAbsent(name) { Node(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
+63
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* This file is part of AndroidIDE.
|
||||
*
|
||||
* AndroidIDE is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* AndroidIDE is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with AndroidIDE. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package com.itsaky.androidide.projects.util
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.annotation.Config
|
||||
|
||||
/** @author Akash Yadav */
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
@Config(manifest = Config.NONE)
|
||||
class ClassTrieTest {
|
||||
|
||||
@Test
|
||||
fun testAppend() {
|
||||
val trie = ClassTrie()
|
||||
trie.append("java.lang.String")
|
||||
trie.append("java.lang.Object")
|
||||
trie.append("java.util.List")
|
||||
trie.append("java.io.File")
|
||||
trie.append("java.nio.file.Path")
|
||||
|
||||
assertThat(trie.findClassName("java.lang"))
|
||||
.containsExactly("java.lang.String", "java.lang.Object")
|
||||
assertThat(trie.findClassName("java.util")).containsExactly("java.util.List")
|
||||
assertThat(trie.findClassName("java.nio")).containsExactly("java.nio.file.Path")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun testRemoval() {
|
||||
val trie = ClassTrie()
|
||||
trie.append("java.lang.String")
|
||||
trie.append("java.lang.Object")
|
||||
trie.append("java.util.List")
|
||||
trie.append("java.io.File")
|
||||
trie.append("java.nio.file.Path")
|
||||
|
||||
trie.remove("java.lang.String")
|
||||
trie.remove("java.nio.file.Path")
|
||||
|
||||
assertThat(trie.findClassName("java.lang"))
|
||||
.containsExactly("java.lang.Object")
|
||||
assertThat(trie.findClassName("java.util")).containsExactly("java.util.List")
|
||||
assertThat(trie.findClassName("java.nio")).isEmpty()
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
build/
|
||||
@@ -0,0 +1,16 @@
|
||||
plugins {
|
||||
id 'java-library'
|
||||
}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_11
|
||||
targetCompatibility = JavaVersion.VERSION_11
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'io.github.itsaky:nb-javac-android:17.0.0.0'
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral ()
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
package com.itsaky.androidide.tooling.test;
|
||||
|
||||
public class Main {
|
||||
public static void main(String[] args) {}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ java {
|
||||
|
||||
dependencies {
|
||||
implementation 'io.github.itsaky:nb-javac-android:17.0.0.0'
|
||||
implementation project(path: ':another-java-library')
|
||||
}
|
||||
|
||||
repositories {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
include ':app'
|
||||
include ':java-library'
|
||||
include ':android-library'
|
||||
include ':another-java-library'
|
||||
rootProject.name = "TestApp"
|
||||
Reference in New Issue
Block a user