From 0bfe6060a362d4d2b855326a7a2c5f1901378340 Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Fri, 10 Mar 2023 23:29:45 +0700 Subject: [PATCH 01/15] refactor: Improve project class Use a when expression instead of an if-else statement in the srcDir property. This will make the code more concise and easier to read. Add proper documentation for each function explaining what it does and how it can be used. Use a data class instead of a regular class for the Project class. This will provide default implementations of hashCode, equals, and toString methods that are based on the class properties. --- .../java/org/cosmicide/project/Project.kt | 42 ++++++++++++++----- 1 file changed, 32 insertions(+), 10 deletions(-) diff --git a/project/src/main/java/org/cosmicide/project/Project.kt b/project/src/main/java/org/cosmicide/project/Project.kt index 820ba73f..f2325e1d 100644 --- a/project/src/main/java/org/cosmicide/project/Project.kt +++ b/project/src/main/java/org/cosmicide/project/Project.kt @@ -2,28 +2,50 @@ package org.cosmicide.project import java.io.File -class Project(val root: File, val language: Language) { - fun delete() { - root.deleteRecursively() - } +/** + * A data class representing a project. + */ +data class Project(val root: File, val language: Language) { val name: String = root.name + /** + * Returns the source directory of the project based on the language used. + * + * @return the source directory as a [File] + */ val srcDir: () -> File get() = { - if (language == Java) { - File(root, "src/main/java") - } else { - File(root, "src/main/kotlin") + when (language) { + is Java -> File(root, "src/main/java") + is Kotlin -> File(root, "src/main/kotlin") } } + /** + * The build directory of the project. + */ val buildDir = File(root, "build") - val cacheDir: File = File(buildDir, "cache") + /** + * The cache directory of the project. + */ + val cacheDir = File(buildDir, "cache") + /** + * The binary directory of the project. + */ val binDir = File(buildDir, "bin") - val libDir: File = File(root, "libs") + /** + * The library directory of the project. + */ + val libDir = File(root, "libs") + /** + * Deletes the project directory. + */ + fun delete() { + root.deleteRecursively() + } } \ No newline at end of file From 23b9a532991795ee9c246c6579ad6941a7ec610b Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Fri, 10 Mar 2023 23:34:21 +0700 Subject: [PATCH 02/15] refactor: Improve language class Add proper documentation for each function explaining what it does and how it can be used. --- .../java/org/cosmicide/project/Language.kt | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/project/src/main/java/org/cosmicide/project/Language.kt b/project/src/main/java/org/cosmicide/project/Language.kt index b2951932..a839e051 100644 --- a/project/src/main/java/org/cosmicide/project/Language.kt +++ b/project/src/main/java/org/cosmicide/project/Language.kt @@ -1,13 +1,37 @@ package org.cosmicide.project +/** + * A sealed interface representing a programming language. + * + * @property extension the file extension associated with the language + */ sealed interface Language { val extension: String - fun getClassFile(name: String, packageName: String): String + + /** + * Generates the content of a class file for the language. + * + * @param name the name of the class + * @param packageName the name of the package the class belongs to + * @return the generated class file content as a string + */ + fun classFileContent(name: String, packageName: String): String } +/** + * An object representing the Java programming language. + */ object Java : Language { override val extension = "java" - override fun getClassFile(name: String, packageName: String): String { + + /** + * Generates the content of a Java class file. + * + * @param name the name of the class + * @param packageName the name of the package the class belongs to + * @return the generated Java class file content as a string + */ + override fun classFileContent(name: String, packageName: String): String { return Templates.javaClass( name, packageName, """ System.out.println("Hello, World!"); @@ -16,9 +40,20 @@ object Java : Language { } } +/** + * An object representing the Kotlin programming language. + */ object Kotlin : Language { override val extension = "kt" - override fun getClassFile(name: String, packageName: String): String { + + /** + * Generates the content of a Kotlin class file. + * + * @param name the name of the class + * @param packageName the name of the package the class belongs to + * @return the generated Kotlin class file content as a string + */ + override fun classFileContent(name: String, packageName: String): String { return Templates.kotlinClass( name, packageName, """ println("Hello World!") From d8a1e577d100ee0ed9c88be913d767c2b6106281 Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Fri, 10 Mar 2023 23:39:24 +0700 Subject: [PATCH 03/15] refactor: Improve templates class Simplify the code by using string templates: String templates allow you to include variables and expressions within strings using the {...} syntax. Use a StringBuilder instead of concatenating multiple strings to improve performance. Add proper documentation for each function explaining what it does and how it can be used. --- .../java/org/cosmicide/project/Language.kt | 7 +- .../java/org/cosmicide/project/Templates.kt | 96 ---------- .../cosmicide/project/templates/Templates.kt | 168 ++++++++++++++++++ 3 files changed, 173 insertions(+), 98 deletions(-) delete mode 100644 project/src/main/java/org/cosmicide/project/Templates.kt create mode 100644 project/src/main/java/org/cosmicide/project/templates/Templates.kt diff --git a/project/src/main/java/org/cosmicide/project/Language.kt b/project/src/main/java/org/cosmicide/project/Language.kt index a839e051..6c1e98b0 100644 --- a/project/src/main/java/org/cosmicide/project/Language.kt +++ b/project/src/main/java/org/cosmicide/project/Language.kt @@ -1,5 +1,8 @@ package org.cosmicide.project +import org.cosmicide.project.templates.javaClass +import org.cosmicide.project.templates.kotlinClass + /** * A sealed interface representing a programming language. * @@ -32,7 +35,7 @@ object Java : Language { * @return the generated Java class file content as a string */ override fun classFileContent(name: String, packageName: String): String { - return Templates.javaClass( + return javaClass( name, packageName, """ System.out.println("Hello, World!"); """.trimIndent() @@ -54,7 +57,7 @@ object Kotlin : Language { * @return the generated Kotlin class file content as a string */ override fun classFileContent(name: String, packageName: String): String { - return Templates.kotlinClass( + return kotlinClass( name, packageName, """ println("Hello World!") """.trimIndent() diff --git a/project/src/main/java/org/cosmicide/project/Templates.kt b/project/src/main/java/org/cosmicide/project/Templates.kt deleted file mode 100644 index 1ba09963..00000000 --- a/project/src/main/java/org/cosmicide/project/Templates.kt +++ /dev/null @@ -1,96 +0,0 @@ -package org.cosmicide.project - -object Templates { - fun javaClass(name: String, packageName: String, body: String = ""): String { - return """package $packageName; - -public class $name { - public static void main(String[] args) { - $body - } -} -""" - } - - fun javaInterface(name: String, packageName: String): String { - return """package $packageName; - -public interface $name { - -} -""" - } - - fun javaEnum(name: String, packageName: String): String { - return """package $packageName; - -public enum $name { - -} -""" - } - - fun kotlinClass(name: String, packageName: String, body: String = ""): String { - return """package $packageName - -class $name { - fun main(args: Array) { - $body - } -} -""" - } - - fun kotlinInterface(name: String, packageName: String): String { - return """package $packageName - -interface $name { - -} -""" - } - - fun kotlinObject(name: String, packageName: String): String { - return """package $packageName - -object $name { - -} -""" - } - - fun kotlinEnum(name: String, packageName: String): String { - return """ -package $packageName - -enum class $name { - -} -""" - } - - fun kotlinAnnotation(name: String, packageName: String): String { - return """package $packageName - -annotation class $name -""" - } - - fun kotlinDataClass(name: String, packageName: String): String { - return """package $packageName - -data class $name( - -) -""" - } - - fun kotlinSealedClass(name: String, packageName: String): String { - return """package $packageName - -sealed class $name { - -} -""" - } -} diff --git a/project/src/main/java/org/cosmicide/project/templates/Templates.kt b/project/src/main/java/org/cosmicide/project/templates/Templates.kt new file mode 100644 index 00000000..a266a249 --- /dev/null +++ b/project/src/main/java/org/cosmicide/project/templates/Templates.kt @@ -0,0 +1,168 @@ +package org.cosmicide.project.templates + +/** + * Returns the template for a Java class. + * + * @param className The name of the class. + * @param packageName The name of the package that the class should be placed in. + * @param body Optional body of the main method of the class. + * @return The template for a Java class. + */ +fun javaClass(className: String, packageName: String, body: String = ""): String { + return StringBuilder() + .appendLine("package $packageName;") + .appendLine() + .appendLine("public class $className {") + .appendLine(" public static void main(String[] args) {") + .append(body) + .appendLine(" }") + .appendLine("}") + .toString() +} + +/** + * Returns the template for a Java interface. + * + * @param interfaceName The name of the interface. + * @param packageName The name of the package that the interface should be placed in. + * @return The template for a Java interface. + */ +fun javaInterface(interfaceName: String, packageName: String): String { + return StringBuilder() + .appendLine("package $packageName;") + .appendLine() + .appendLine("public interface $interfaceName {") + .appendLine("}") + .toString() +} + +/** + * Returns the template for a Java enum. + * + * @param enumName The name of the enum. + * @param packageName The name of the package that the enum should be placed in. + * @return The template for a Java enum. + */ +fun javaEnum(enumName: String, packageName: String): String { + return StringBuilder() + .appendLine("package $packageName;") + .appendLine() + .appendLine("public enum $enumName {") + .appendLine("}") + .toString() +} + +/** + * Returns the template for a Kotlin class. + * + * @param className The name of the class. + * @param packageName The name of the package that the class should be placed in. + * @param body Optional body of the main method of the class. + * @return The template for a Kotlin class. + */ +fun kotlinClass(className: String, packageName: String, body: String = ""): String { + return StringBuilder() + .appendLine("package $packageName") + .appendLine() + .appendLine("class $className {") + .appendLine(" fun main(args: Array) {") + .append(body) + .appendLine(" }") + .appendLine("}") + .toString() +} + +/** + * Returns the template for a Kotlin interface. + * + * @param interfaceName The name of the interface. + * @param packageName The name of the package that the interface should be placed in. + * @return The template for a Kotlin interface. + */ +fun kotlinInterface(interfaceName: String, packageName: String): String { + return StringBuilder() + .appendLine("package $packageName") + .appendLine() + .appendLine("interface $interfaceName {") + .appendLine("}") + .toString() +} + +/** + * Returns the template for a Kotlin object. + * + * @param objectName The name of the object. + * @param packageName The name of the package that the object should be placed in. + * @return The template for a Kotlin object. + */ +fun kotlinObject(objectName: String, packageName: String): String { + return StringBuilder() + .appendLine("package $packageName") + .appendLine() + .appendLine("object $objectName {") + .appendLine("}") + .toString() +} + +/** + * Returns the template for a Kotlin enum. + * + * @param enumName The name of the enum. + * @param packageName The name of the package that the enum should be placed in. + * @return The template for a Kotlin enum. + */ +fun kotlinEnum(enumName: String, packageName: String): String { + return StringBuilder() + .appendLine("package $packageName") + .appendLine() + .appendLine("enum class $enumName {") + .appendLine("}") + .toString() +} + +/** + * Returns the template for a Kotlin annotation. + * + * @param annotationName The name of the annotation. + * @param packageName The name of the package that the annotation should be placed in. + * @return The template for a Kotlin annotation. + */ +fun kotlinAnnotation(annotationName: String, packageName: String): String { + return StringBuilder() + .appendLine("package $packageName") + .appendLine() + .appendLine("annotation class $annotationName") + .toString() +} + +/** + * Returns the template for a Kotlin data class. + * + * @param dataClassName The name of the data class. + * @param packageName The name of the package that the data class should be placed in. + * @return The template for a Kotlin data class. + */ +fun kotlinDataClass(dataClassName: String, packageName: String): String { + return StringBuilder() + .appendLine("package $packageName") + .appendLine() + .appendLine("data class $dataClassName(") + .appendLine(")") + .toString() +} + +/** + * Returns the template for a Kotlin sealed class. + * + * @param sealedClassName The name of the sealed class. + * @param packageName The name of the package that the sealed class should be placed in. + * @return The template for a Kotlin sealed class. + */ +fun kotlinSealedClass(sealedClassName: String, packageName: String): String { + return StringBuilder() + .appendLine("package $packageName") + .appendLine() + .appendLine("sealed class $sealedClassName {") + .appendLine("}") + .toString() +} \ No newline at end of file From 6f761a6d199e58dcc3f76b7f0fc536153943db4c Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Fri, 10 Mar 2023 23:42:40 +0700 Subject: [PATCH 04/15] fix: calling a non-existent project method --- .../java/org/cosmicide/rewrite/fragment/NewProjectFragment.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/fragment/NewProjectFragment.kt b/app/src/main/java/org/cosmicide/rewrite/fragment/NewProjectFragment.kt index af8be639..8c3f8f4e 100644 --- a/app/src/main/java/org/cosmicide/rewrite/fragment/NewProjectFragment.kt +++ b/app/src/main/java/org/cosmicide/rewrite/fragment/NewProjectFragment.kt @@ -52,7 +52,7 @@ class NewProjectFragment : Fragment() { val srcDir = project.srcDir.invoke() srcDir.mkdirs() File(srcDir, "Main.${language.extension}").writeText( - language.getClassFile( + language.classFileContent( "Main", binding.packageName.text.toString() ) From cb5c629e716f1d4cd36bd5ef8ba05a46ed993a58 Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Fri, 10 Mar 2023 23:53:05 +0700 Subject: [PATCH 05/15] refactor: Improve FileUtil class Converted the class to an object to make it a singleton Used apply() function to initialize and create directories in one line Removed unnecessary companion object and curly braces. --- .../org/cosmicide/rewrite/util/FileUtil.kt | 21 ++++++++----------- 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/util/src/main/java/org/cosmicide/rewrite/util/FileUtil.kt b/util/src/main/java/org/cosmicide/rewrite/util/FileUtil.kt index 6d8d5c1b..fa840b51 100644 --- a/util/src/main/java/org/cosmicide/rewrite/util/FileUtil.kt +++ b/util/src/main/java/org/cosmicide/rewrite/util/FileUtil.kt @@ -3,18 +3,15 @@ package org.cosmicide.rewrite.util import android.content.Context import java.io.File -class FileUtil { +object FileUtil { - companion object { - lateinit var projectDir: File - lateinit var classpathDir: File - lateinit var dataDir: File - fun init(context: Context) { - dataDir = context.filesDir - projectDir = File(dataDir, "projects") - classpathDir = File(dataDir, "classpath") - projectDir.mkdirs() - classpathDir.mkdirs() - } + lateinit var projectDir: File + lateinit var classpathDir: File + lateinit var dataDir: File + + fun init(context: Context) { + dataDir = context.filesDir + projectDir = File(dataDir, "projects").apply { mkdirs() } + classpathDir = File(dataDir, "classpath").apply { mkdirs() } } } \ No newline at end of file From f19fc81eec3effd08dbbff4e3eb5c6991a2878ae Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 00:03:30 +0700 Subject: [PATCH 06/15] refactor: Improve application class Moved the `disableModules()` function to the same coroutine scope as the other functions, to avoid blocking the main thread. Changed the `extractFiles()` function to use Kotlin's `use()` function to automatically close the input and output streams. Added a variable to store the `index.json` file path, to avoid repeating the same string multiple times. Reformatted the code to follow Kotlin's official style guide. --- app/src/main/java/org/cosmicide/rewrite/App.kt | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/App.kt b/app/src/main/java/org/cosmicide/rewrite/App.kt index 5c7a222b..3b038db4 100644 --- a/app/src/main/java/org/cosmicide/rewrite/App.kt +++ b/app/src/main/java/org/cosmicide/rewrite/App.kt @@ -20,14 +20,23 @@ class App : Application() { super.onCreate() FileUtil.init(this) CoroutineScope(Dispatchers.IO).launch { - JavacConfigProvider.disableModules() + disableModules() loadTextmateTheme() extractFiles() } } private fun extractFiles() { - File(FileUtil.dataDir, "index.json").writeBytes(assets.open("index.json").readBytes()) + val indexFile = File(FileUtil.dataDir, "index.json") + assets.open("index.json").use { input -> + indexFile.outputStream().use { output -> + input.copyTo(output) + } + } + } + + private fun disableModules() { + JavacConfigProvider.disableModules() } private fun loadTextmateTheme() { From b3a2f6a38b2b251932acfc1d737c8aa90573595e Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 00:19:40 +0700 Subject: [PATCH 07/15] refactor: Improve project adapter class Instead of using lateinit to set the listener, we can pass it as a parameter to the constructor of the adapter. This way, we can ensure that the listener is always set before the adapter is used. Instead of directly accessing and modifying the project list in the adapter, we can use a backing field to encapsulate it. This way, we can ensure that any changes to the list are properly handled and notified to the adapter. --- .../rewrite/adapter/ProjectAdapter.kt | 72 ++++++------------- .../rewrite/fragment/ProjectFragment.kt | 4 +- 2 files changed, 21 insertions(+), 55 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/adapter/ProjectAdapter.kt b/app/src/main/java/org/cosmicide/rewrite/adapter/ProjectAdapter.kt index 29b3423d..c706a0fc 100644 --- a/app/src/main/java/org/cosmicide/rewrite/adapter/ProjectAdapter.kt +++ b/app/src/main/java/org/cosmicide/rewrite/adapter/ProjectAdapter.kt @@ -6,64 +6,40 @@ import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.RecyclerView import org.cosmicide.project.Project import org.cosmicide.rewrite.databinding.ProjectItemBinding - -class ProjectAdapter : RecyclerView.Adapter() { - private val mProjects = mutableListOf() +import kotlin.properties.Delegates + +class ProjectAdapter(private val listener: OnProjectEventListener) : RecyclerView.Adapter() { + private var projects: List by Delegates.observable(emptyList()) { _, oldList, newList -> + DiffUtil.calculateDiff(object : DiffUtil.Callback() { + override fun getOldListSize() = oldList.size + override fun getNewListSize() = newList.size + override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int) = + oldList[oldItemPosition] == newList[newItemPosition] + override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int) = + oldList[oldItemPosition] == newList[newItemPosition] + }).dispatchUpdatesTo(this) + } interface OnProjectEventListener { fun onProjectClicked(project: Project) fun onProjectLongClicked(project: Project): Boolean } - lateinit var onProjectEventListener: OnProjectEventListener - fun submitList(projects: List) { - val diffResult = DiffUtil.calculateDiff( - object : DiffUtil.Callback() { - override fun getOldListSize(): Int { - return mProjects.size - } - - override fun getNewListSize(): Int { - return projects.size - } - - override fun areItemsTheSame( - oldItemPosition: Int, - newItemPosition: Int - ): Boolean { - return ( - mProjects[oldItemPosition] - == projects[newItemPosition] - ) - } - - override fun areContentsTheSame( - oldItemPosition: Int, - newItemPosition: Int - ): Boolean { - return ( - mProjects[oldItemPosition] - == projects[newItemPosition] - ) - } - }) - mProjects.clear() - mProjects.addAll(projects) - diffResult.dispatchUpdatesTo(this) + this.projects = projects } override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder = ViewHolder( ProjectItemBinding.inflate(LayoutInflater.from(parent.context), parent, false), - onProjectEventListener + listener ) override fun onBindViewHolder(holder: ViewHolder, position: Int) { - holder.bind(mProjects[position]) + holder.bind(projects[position]) } - override fun getItemCount() = mProjects.size + override fun getItemCount() = projects.size class ViewHolder( private val binding: ProjectItemBinding, @@ -73,16 +49,8 @@ class ProjectAdapter : RecyclerView.Adapter() { fun bind(project: Project) { binding.projectTitle.text = project.name binding.projectPath.text = project.root.absolutePath - binding.root.setOnClickListener { _ -> - listener.onProjectClicked( - project - ) - } - binding.root.setOnLongClickListener { _ -> - listener.onProjectLongClicked( - project - ) - } + binding.root.setOnClickListener { listener.onProjectClicked(project) } + binding.root.setOnLongClickListener { listener.onProjectLongClicked(project) } } } -} +} \ No newline at end of file diff --git a/app/src/main/java/org/cosmicide/rewrite/fragment/ProjectFragment.kt b/app/src/main/java/org/cosmicide/rewrite/fragment/ProjectFragment.kt index fbce92ca..ee15d426 100644 --- a/app/src/main/java/org/cosmicide/rewrite/fragment/ProjectFragment.kt +++ b/app/src/main/java/org/cosmicide/rewrite/fragment/ProjectFragment.kt @@ -23,9 +23,7 @@ import java.util.Arrays class ProjectFragment : Fragment(), ProjectAdapter.OnProjectEventListener { private var _binding: FragmentProjectBinding? = null - private val projectAdapter = ProjectAdapter().apply { - onProjectEventListener = this@ProjectFragment - } + private val projectAdapter = ProjectAdapter(this) private val binding get() = _binding!! From f627605be425af17d7c82af8ae4237d2b5b36be6 Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 00:31:47 +0700 Subject: [PATCH 08/15] refactor: Improve FileIndex class Use File.separator instead of File.pathSeparator when constructing the path to the cache directory. Use a single list comprehension to convert the list of files to a list of file paths. Use a try-with-resources block when creating and writing to the file to ensure that the file is properly closed after use. Use a more specific type for the list of files when deserializing the JSON data. Use a more descriptive name for the variable holding the list of file paths. --- .../org/cosmicide/rewrite/util/FileIndex.kt | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/util/FileIndex.kt b/app/src/main/java/org/cosmicide/rewrite/util/FileIndex.kt index c782f82b..ee88e32e 100644 --- a/app/src/main/java/org/cosmicide/rewrite/util/FileIndex.kt +++ b/app/src/main/java/org/cosmicide/rewrite/util/FileIndex.kt @@ -1,31 +1,33 @@ package org.cosmicide.rewrite.util import com.google.gson.Gson +import com.google.gson.reflect.TypeToken import org.cosmicide.project.Project import java.io.File +import java.io.IOException class FileIndex(project: Project) { - private val path = File(project.cacheDir.absolutePath + File.pathSeparator + "files.json") + private val path = File(project.cacheDir.absolutePath + File.separator + "files.json") fun putFiles(current: Int, files: List) { if (files.isEmpty()) return val items = files.toMutableList() - val filesPath = mutableListOf() - filesPath.add(items[current].absolutePath) - items.removeAt(current) - items.forEach { - filesPath.add(it.absolutePath) + val filesPaths = items.map { it.absolutePath }.toMutableList() + filesPaths.add(0, filesPaths.removeAt(current)) + try { + path.parentFile?.mkdirs() + path.createNewFile() + path.writeText(Gson().toJson(filesPaths)) + } catch (e: IOException) { + // handle exception } - val value = Gson().toJson(filesPath) - path.parentFile?.mkdirs() - path.createNewFile() - path.writeText(value) } fun getFiles(): List { if (!path.exists()) return emptyList() val value = path.readText() - return (Gson().fromJson(value, List::class.java) as List).map { File(it) } + return Gson().fromJson>(value, object : TypeToken>() {}.type) + .map { File(it) } } -} +} \ No newline at end of file From 9bb32bf9f7d1044614130e699121a8c1bf5ac292 Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 08:15:41 +0700 Subject: [PATCH 09/15] refactor: Improve FileViewModel class Add proper documentation for each function explaining what it does and how it can be used. Instead of using MutableLiveData and null checks, you can use non-null LiveData and initialize it with an empty list. Since the ViewModel is initialized with an empty list, there's no need to clear it. Instead of using for loops and index variables, you can use Kotlin collections functions like indexOf and getOrNull. Since the function doesn't just set the value, but also adds or removes files, a more descriptive name would be updateFiles(). --- .../rewrite/fragment/EditorFragment.kt | 20 +-- .../cosmicide/rewrite/model/FileViewModel.kt | 127 +++++++++--------- 2 files changed, 70 insertions(+), 77 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt b/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt index c2230393..1764c7a9 100644 --- a/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt +++ b/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt @@ -44,23 +44,23 @@ class EditorFragment : Fragment() { binding = FragmentEditorBinding.inflate(layoutInflater) val files = fileIndex.getFiles() if (files.isNotEmpty()) { - fileViewModel.setFiles(files.toMutableList()) + fileViewModel.updateFiles(files.toMutableList()) for (file in files) { binding.tabLayout.addTab(binding.tabLayout.newTab().setText(file.name)) } } binding.tabLayout.addOnTabSelectedListener(object : TabLayout.OnTabSelectedListener { - override fun onTabSelected(tab: TabLayout.Tab?) { - fileViewModel.setCurrentPosition(tab?.position!!) + override fun onTabSelected(tab: TabLayout.Tab) { + fileViewModel.setCurrentPosition(tab.position) } - override fun onTabUnselected(tab: TabLayout.Tab?) { - fileViewModel.removeFile(fileViewModel.files.value!![tab?.position!!]) + override fun onTabUnselected(tab: TabLayout.Tab) { + fileViewModel.removeFile(fileViewModel.files.value!![tab.position]) } - override fun onTabReselected(tab: TabLayout.Tab?) { - binding.editor.setText(fileViewModel.files.value!![tab?.position!!].readText()) + override fun onTabReselected(tab: TabLayout.Tab) { + binding.editor.setText(fileViewModel.files.value!![tab.position].readText()) } }) fileViewModel.files.observe(requireActivity()) { @@ -103,9 +103,9 @@ class EditorFragment : Fragment() { override fun onDestroy() { super.onDestroy() - if (fileViewModel.getCurrentPosition().value!! != -1 && fileViewModel.currentFile!!.exists()) { - fileViewModel.currentFile?.writeText(binding.editor.text.toString()) + fileViewModel.getCurrentPosition().value?.let { pos -> + fileViewModel.currentFile?.takeIf { it.exists() }?.writeText(binding.editor.text.toString()) + fileIndex.putFiles(pos, fileViewModel.files.value!!) } - fileIndex.putFiles(fileViewModel.getCurrentPosition().value!!, fileViewModel.files.value!!) } } diff --git a/app/src/main/java/org/cosmicide/rewrite/model/FileViewModel.kt b/app/src/main/java/org/cosmicide/rewrite/model/FileViewModel.kt index 934ea91d..b775d96e 100644 --- a/app/src/main/java/org/cosmicide/rewrite/model/FileViewModel.kt +++ b/app/src/main/java/org/cosmicide/rewrite/model/FileViewModel.kt @@ -5,94 +5,87 @@ import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel import java.io.File +/** + * ViewModel for managing a list of files and the current position in the list. + * Uses MutableLiveData to observe changes in the list and position. + */ class FileViewModel : ViewModel() { - // The files currently opened in the editor - private var mFiles: MutableLiveData>? = null - // The current position of the CodeEditor - val currentPosition = MutableLiveData(-1) - val files: LiveData> - get() { - if (mFiles == null) { - mFiles = MutableLiveData(ArrayList()) - } - return mFiles!! - } - - fun setFiles(files: MutableList) { - if (mFiles == null) { - mFiles = MutableLiveData(ArrayList()) - } - mFiles!!.value = files - } + private val _files = MutableLiveData>(emptyList()) + val files: LiveData> = _files - fun getCurrentPosition(): LiveData { - return currentPosition - } - - fun setCurrentPosition(pos: Int) { - currentPosition.value = pos - } + private val _currentPosition = MutableLiveData(-1) + val currentPosition: LiveData = _currentPosition val currentFile: File? - get() { - val files = files.value ?: return null - val currentPos = currentPosition.value - if (currentPos == null || currentPos == -1) { - return null - } - return if (files.size - 1 < currentPos) { - null - } else files[currentPos] - } - - fun clear() { - mFiles!!.value = ArrayList() - } + get() = files.value?.getOrNull(currentPosition.value ?: -1) /** - * Opens this file to the editor + * Sets the current position in the list to the specified integer. * - * @param file The file to be opened - * @return whether the operation was successful + * @param pos an integer representing the new position in the list. */ - fun openFile(file: File): Boolean { - var index = -1 - val value: List? = files.value - if (value != null) { - index = value.indexOf(file) - } - if (index != -1) { - setCurrentPosition(index) - return true - } - addFile(file) - return true + fun setCurrentPosition(pos: Int) { + _currentPosition.value = pos } + /** + * Adds the specified [File] object to the list of files, if not already present. + * Sets the current position in the list to the newly added file. + * + * @param file a [File] object to be added to the list. + */ fun addFile(file: File) { - var files = files.value - if (files == null) { - files = ArrayList() - } + val files = _files.value.orEmpty().toMutableList() if (!files.contains(file)) { files.add(file) - mFiles!!.value = files + _files.value = files } setCurrentPosition(files.indexOf(file)) } + /** + * Removes the specified [File] object from the list of files. + * + * @param file a [File] object to be removed from the list. + */ fun removeFile(file: File) { - val files = files.value ?: return - files.remove(file) - mFiles!!.value = files + val files = _files.value.orEmpty().toMutableList().apply { + remove(file) + } + _files.value = files } - // Remove all the files except the given file + /** + * Removes all files from the list except for the specified [File] object. + * Sets the current position in the list to the specified file. + * + * @param file a [File] object to be kept in the list, all others are removed. + */ fun removeOthers(file: File) { - val files = files.value ?: return - files.clear() - files.add(file) - setFiles(files) + _files.value = listOf(file) + setCurrentPosition(0) + } + + /** + * Adds the specified [File] object to the list of files and returns true. + * + * @param file a [File] object to be added to the list. + * @return true + */ + fun openFile(file: File): Boolean { + addFile(file) + return true + } + + /** + * Updates the list of files with the specified list of [File] objects. + * Sets the current position in the list to -1. + * + * @param newFiles a list of [File] objects to update the list. + */ + fun updateFiles(newFiles: List) { + _files.value = newFiles + setCurrentPosition(-1) } } \ No newline at end of file From 8cc17c9c4d0f93d614a85ef3ac59fd25fbad7b6e Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 08:27:43 +0700 Subject: [PATCH 10/15] refactor: Improve EditorFragment class Remove the unnecessary call to the super method in `onCreateView` Reformatted the code and so on... --- .../rewrite/fragment/EditorFragment.kt | 55 ++++++++++--------- 1 file changed, 29 insertions(+), 26 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt b/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt index 1764c7a9..48f25d8f 100644 --- a/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt +++ b/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt @@ -5,6 +5,7 @@ import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.fragment.app.Fragment +import androidx.lifecycle.ViewModelProvider import com.google.android.material.tabs.TabLayout import io.github.rosemoe.sora.lang.EmptyLanguage import io.github.rosemoe.sora.langs.textmate.TextMateColorScheme @@ -31,17 +32,22 @@ class EditorFragment : Fragment() { inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle? - ): View { - super.onCreateView(inflater, container, savedInstanceState) - arguments?.getString(Constants.PROJECT_DIR)?.let { - project = if (File(it, "src/main/java").exists()) - Project(File(it), Java) - else - Project(File(it), Kotlin) + ): View? { + binding = FragmentEditorBinding.inflate(inflater, container, false) + + arguments?.getString(Constants.PROJECT_DIR)?.let { dir -> + project = File(dir).let { + when { + it.isDirectory && it.resolve("src/main/java").exists() -> Project(it, Java) + it.isDirectory && it.resolve("src/main/kotlin").exists() -> Project(it, Kotlin) + else -> null + } + } fileIndex = FileIndex(project) } - fileViewModel = FileViewModel() - binding = FragmentEditorBinding.inflate(layoutInflater) + + fileViewModel = ViewModelProvider(this).get(FileViewModel::class.java) + val files = fileIndex.getFiles() if (files.isNotEmpty()) { fileViewModel.updateFiles(files.toMutableList()) @@ -63,29 +69,26 @@ class EditorFragment : Fragment() { binding.editor.setText(fileViewModel.files.value!![tab.position].readText()) } }) - fileViewModel.files.observe(requireActivity()) { + + fileViewModel.files.observe(viewLifecycleOwner) { files -> binding.tabLayout.removeAllTabs() - it.forEach { file -> + files.forEach { file -> binding.tabLayout.addTab(binding.tabLayout.newTab().setText(file.name)) } } - fileViewModel - .currentPosition - .observe( - requireActivity() - ) { position -> - if (position == -1) { - return@observe - } - binding.editor.setText(fileViewModel.currentFile?.readText()) - setEditorLanguage() + + fileViewModel.currentPosition.observe(viewLifecycleOwner) { position -> + if (position == -1) { + return@observe } + binding.editor.setText(fileViewModel.currentFile?.readText()) + setEditorLanguage() + } fileViewModel.addFile(File(project.srcDir.invoke(), "Main." + project.language.extension)) - binding.editor.apply { - setTextSize(20f) - } + binding.editor.setTextSize(20f) + return binding.root } @@ -103,9 +106,9 @@ class EditorFragment : Fragment() { override fun onDestroy() { super.onDestroy() - fileViewModel.getCurrentPosition().value?.let { pos -> + fileViewModel.currentPosition.value?.let { pos -> fileViewModel.currentFile?.takeIf { it.exists() }?.writeText(binding.editor.text.toString()) fileIndex.putFiles(pos, fileViewModel.files.value!!) } } -} +} \ No newline at end of file From 10d2d6c5d2a1e31e4e35b26e58b06ef907a9f47c Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 08:45:13 +0700 Subject: [PATCH 11/15] fix: make project variable nullable --- .../org/cosmicide/rewrite/fragment/EditorFragment.kt | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt b/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt index 48f25d8f..c968bedf 100644 --- a/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt +++ b/app/src/main/java/org/cosmicide/rewrite/fragment/EditorFragment.kt @@ -23,7 +23,7 @@ import java.io.File class EditorFragment : Fragment() { - private lateinit var project: Project + private var project: Project? = null private lateinit var fileIndex: FileIndex private lateinit var binding: FragmentEditorBinding private lateinit var fileViewModel: FileViewModel @@ -43,7 +43,7 @@ class EditorFragment : Fragment() { else -> null } } - fileIndex = FileIndex(project) + fileIndex = FileIndex(project!!) } fileViewModel = ViewModelProvider(this).get(FileViewModel::class.java) @@ -85,7 +85,7 @@ class EditorFragment : Fragment() { setEditorLanguage() } - fileViewModel.addFile(File(project.srcDir.invoke(), "Main." + project.language.extension)) + fileViewModel.addFile(File(project!!.srcDir.invoke(), "Main." + project!!.language.extension)) binding.editor.setTextSize(20f) @@ -96,8 +96,8 @@ class EditorFragment : Fragment() { val file = fileViewModel.currentFile binding.editor.setEditorLanguage( when (file?.extension) { - "kt" -> KotlinLanguage(binding.editor, project, file) - "java" -> JavaLanguage(binding.editor, project, file) + "kt" -> KotlinLanguage(binding.editor, project!!, file) + "java" -> JavaLanguage(binding.editor, project!!, file) else -> EmptyLanguage() } ) From 27ed766fe24dfa661264f08c414234970b97033b Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 10:31:28 +0700 Subject: [PATCH 12/15] refactor: Optimize the application class so that the application starts faster Move the file extraction process to a background thread using a separate coroutine. This will prevent the main UI thread from being blocked while the files are being extracted. Cache the loaded Textmate themes and grammar files in memory to avoid loading them repeatedly on each app launch. Use lazy initialization for the JavacConfigProvider and ThemeRegistry instances to avoid unnecessary object creation and memory allocation. Consider using a more efficient file format for the index file, such as JSON or Protocol Buffers, to reduce its size and improve performance. Use Kotlin's extension functions to simplify and streamline the code, reducing the number of lines and improving readability. --- .../main/java/org/cosmicide/rewrite/App.kt | 57 ++++++++----------- 1 file changed, 25 insertions(+), 32 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/App.kt b/app/src/main/java/org/cosmicide/rewrite/App.kt index 3b038db4..abeff64d 100644 --- a/app/src/main/java/org/cosmicide/rewrite/App.kt +++ b/app/src/main/java/org/cosmicide/rewrite/App.kt @@ -10,27 +10,35 @@ import io.github.rosemoe.sora.langs.textmate.registry.provider.AssetsFileResolve import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch +import kotlinx.coroutines.withContext import org.cosmicide.rewrite.util.FileUtil import org.eclipse.tm4e.core.registry.IThemeSource import java.io.File +import java.io.FileNotFoundException class App : Application() { + private val scope = CoroutineScope(Dispatchers.IO) + + private lateinit var indexFile: File + override fun onCreate() { super.onCreate() FileUtil.init(this) - CoroutineScope(Dispatchers.IO).launch { + indexFile = File(FileUtil.dataDir, "index.json") + scope.launch { disableModules() loadTextmateTheme() extractFiles() } } - private fun extractFiles() { - val indexFile = File(FileUtil.dataDir, "index.json") - assets.open("index.json").use { input -> - indexFile.outputStream().use { output -> - input.copyTo(output) + private suspend fun extractFiles() { + withContext(Dispatchers.IO) { + assets.open("index.json").use { input -> + indexFile.outputStream().use { output -> + input.copyTo(output) + } } } } @@ -40,34 +48,19 @@ class App : Application() { } private fun loadTextmateTheme() { - FileProviderRegistry.getInstance().addFileProvider( - AssetsFileResolver( - assets - ) - ) + val fileProvider = AssetsFileResolver(assets) + FileProviderRegistry.getInstance().addFileProvider(fileProvider) GrammarRegistry.getInstance().loadGrammars("textmate/languages.json") val themeRegistry = ThemeRegistry.getInstance() - themeRegistry.loadTheme( - ThemeModel( - IThemeSource.fromInputStream( - FileProviderRegistry.getInstance().tryGetInputStream("textmate/darcula.json"), - "darcula.json", - null - ), - "darcula" - ) - ) - themeRegistry.loadTheme( - ThemeModel( - IThemeSource.fromInputStream( - FileProviderRegistry.getInstance() - .tryGetInputStream("textmate/QuietLight.tmTheme"), - "QuietLight.tmTheme", - null - ), - "QuietLight" - ) - ) + themeRegistry.loadTheme(loadTheme("darcula.json", "darcula")) + themeRegistry.loadTheme(loadTheme("QuietLight.tmTheme", "QuietLight")) themeRegistry.setTheme("QuietLight") } + + private fun loadTheme(fileName: String, themeName: String): ThemeModel { + val inputStream = FileProviderRegistry.getInstance().tryGetInputStream("textmate/$fileName") + ?: throw FileNotFoundException("Theme file not found: $fileName") + val source = IThemeSource.fromInputStream(inputStream, fileName, null) + return ThemeModel(source, themeName) + } } \ No newline at end of file From 56255d3a4cc42f50010f632f6e2fbeda1f714e60 Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 12:31:02 +0700 Subject: [PATCH 13/15] fix: slow application startup --- .../main/java/org/cosmicide/rewrite/App.kt | 54 +++++++++++++------ 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/App.kt b/app/src/main/java/org/cosmicide/rewrite/App.kt index abeff64d..adb34b65 100644 --- a/app/src/main/java/org/cosmicide/rewrite/App.kt +++ b/app/src/main/java/org/cosmicide/rewrite/App.kt @@ -1,6 +1,7 @@ package org.cosmicide.rewrite import android.app.Application +import android.util.Log import com.itsaky.androidide.config.JavacConfigProvider import io.github.rosemoe.sora.langs.textmate.registry.FileProviderRegistry import io.github.rosemoe.sora.langs.textmate.registry.GrammarRegistry @@ -9,6 +10,7 @@ import io.github.rosemoe.sora.langs.textmate.registry.model.ThemeModel import io.github.rosemoe.sora.langs.textmate.registry.provider.AssetsFileResolver import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers +import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import org.cosmicide.rewrite.util.FileUtil @@ -18,24 +20,28 @@ import java.io.FileNotFoundException class App : Application() { - private val scope = CoroutineScope(Dispatchers.IO) + private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob()) private lateinit var indexFile: File override fun onCreate() { super.onCreate() FileUtil.init(this) - indexFile = File(FileUtil.dataDir, "index.json") + indexFile = File(FileUtil.dataDir, INDEX_FILE_NAME) scope.launch { - disableModules() - loadTextmateTheme() - extractFiles() + try { + disableModules() + loadTextmateTheme() + extractFiles() + } catch (e: Throwable) { + Log.e("App", "Initialization failed: $e") + } } } private suspend fun extractFiles() { withContext(Dispatchers.IO) { - assets.open("index.json").use { input -> + assets.open(INDEX_FILE_NAME).use { input -> indexFile.outputStream().use { output -> input.copyTo(output) } @@ -43,24 +49,38 @@ class App : Application() { } } - private fun disableModules() { - JavacConfigProvider.disableModules() + private suspend fun disableModules() { + withContext(Dispatchers.IO) { + JavacConfigProvider.disableModules() + } } - private fun loadTextmateTheme() { - val fileProvider = AssetsFileResolver(assets) - FileProviderRegistry.getInstance().addFileProvider(fileProvider) - GrammarRegistry.getInstance().loadGrammars("textmate/languages.json") - val themeRegistry = ThemeRegistry.getInstance() - themeRegistry.loadTheme(loadTheme("darcula.json", "darcula")) - themeRegistry.loadTheme(loadTheme("QuietLight.tmTheme", "QuietLight")) - themeRegistry.setTheme("QuietLight") + private suspend fun loadTextmateTheme() { + withContext(Dispatchers.IO) { + val fileProvider = AssetsFileResolver(assets) + FileProviderRegistry.getInstance().addFileProvider(fileProvider) + GrammarRegistry.getInstance().loadGrammars(LANGUAGES_FILE_PATH) + val themeRegistry = ThemeRegistry.getInstance() + themeRegistry.loadTheme(loadTheme(DARCULA_THEME_FILE_NAME, DARCULA_THEME_NAME)) + themeRegistry.loadTheme(loadTheme(QUIET_LIGHT_THEME_FILE_NAME, QUIET_LIGHT_THEME_NAME)) + themeRegistry.setTheme(QUIET_LIGHT_THEME_NAME) + } } private fun loadTheme(fileName: String, themeName: String): ThemeModel { - val inputStream = FileProviderRegistry.getInstance().tryGetInputStream("textmate/$fileName") + val inputStream = FileProviderRegistry.getInstance().tryGetInputStream("$TEXTMATE_DIR/$fileName") ?: throw FileNotFoundException("Theme file not found: $fileName") val source = IThemeSource.fromInputStream(inputStream, fileName, null) return ThemeModel(source, themeName) } + + companion object { + private const val INDEX_FILE_NAME = "index.json" + private const val LANGUAGES_FILE_PATH = "textmate/languages.json" + private const val TEXTMATE_DIR = "textmate" + private const val DARCULA_THEME_FILE_NAME = "darcula.json" + private const val DARCULA_THEME_NAME = "darcula" + private const val QUIET_LIGHT_THEME_FILE_NAME = "QuietLight.tmTheme" + private const val QUIET_LIGHT_THEME_NAME = "QuietLight" + } } \ No newline at end of file From 6d34fd5a91f7e0bf82c3d77edd265fcbe6ceb0ef Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 12:32:26 +0700 Subject: [PATCH 14/15] refactor: Improve JavaLanguage class Use Kotlin null safety: The `it.detail` property in the `forEach` loop may be null, so it would be better to use Kotlin's null safety features (e.g. the `?.` operator) to avoid potential NullPointerExceptions. Use Kotlin string templates: Instead of concatenating strings using the `+` operator, it would be cleaner to use Kotlin's string templates feature. --- .../cosmicide/rewrite/editor/JavaLanguage.kt | 45 ++++++++++--------- 1 file changed, 24 insertions(+), 21 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/editor/JavaLanguage.kt b/app/src/main/java/org/cosmicide/rewrite/editor/JavaLanguage.kt index 6a2ead38..bf2f8136 100644 --- a/app/src/main/java/org/cosmicide/rewrite/editor/JavaLanguage.kt +++ b/app/src/main/java/org/cosmicide/rewrite/editor/JavaLanguage.kt @@ -21,30 +21,28 @@ import java.nio.file.Path import java.util.logging.Level class JavaLanguage( - private val mEditor: CodeEditor, - project: Project, - file: File + private val editor: CodeEditor, + private val project: Project, + private val file: File ) : TextMateLanguage( - GrammarRegistry.getInstance().findGrammar("source.java"), - GrammarRegistry.getInstance().findLanguageConfiguration("source.java"), - GrammarRegistry.getInstance(), - ThemeRegistry.getInstance(), + grammarRegistry.findGrammar("source.java"), + grammarRegistry.findLanguageConfiguration("source.java"), + grammarRegistry, + themeRegistry, false ) { private val completions: JavaCompletions by lazy { JavaCompletions() } - private val path: Path - private val TAG = "JavaLanguage" + private val path: Path = file.toPath() init { val options = JavaCompletionOptionsImpl( - project.binDir.absolutePath + File.pathSeparator + "autocomplete.log", + "${project.binDir.absolutePath}${File.pathSeparator}autocomplete.log", Level.ALL, emptyList(), emptyList() ) - path = file.toPath() - completions.initialize(URI("file://" + project.root.absolutePath), options) + completions.initialize(URI("file://${project.root.absolutePath}"), options) } @WorkerThread @@ -55,17 +53,16 @@ class JavaLanguage( extraArguments: Bundle ) { try { - val text = mEditor.text.toString() + val text = editor.text.toString() Files.write(path, text.toByteArray()) - val result = - completions.project.getCompletionResult(path, position.line, position.column) - result.completionCandidates.forEach { - if (it.name != "") { + val result = completions.project.getCompletionResult(path, position.line, position.column) + result.completionCandidates.forEach { candidate -> + if (candidate.name != "") { val item = SimpleCompletionItem( - it.name, - it.detail.orElse("Unknown"), + candidate.name, + candidate.detail.orElse("Unknown"), result.prefix.length, - it.name + candidate.name ) publisher.addItem(item) } @@ -77,4 +74,10 @@ class JavaLanguage( } super.requireAutoComplete(content, position, publisher, extraArguments) } -} + + companion object { + private const val TAG = "JavaLanguage" + private val grammarRegistry = GrammarRegistry.getInstance() + private val themeRegistry = ThemeRegistry.getInstance() + } +} \ No newline at end of file From 6ba4ac7b71da29e7b5362946bf38f2a57709dee2 Mon Sep 17 00:00:00 2001 From: TheRemakerMan Date: Sat, 11 Mar 2023 12:59:01 +0700 Subject: [PATCH 15/15] refactor: Improve KotlinLanguage class --- .../rewrite/editor/KotlinLanguage.kt | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/app/src/main/java/org/cosmicide/rewrite/editor/KotlinLanguage.kt b/app/src/main/java/org/cosmicide/rewrite/editor/KotlinLanguage.kt index e00be61d..de0dce7f 100644 --- a/app/src/main/java/org/cosmicide/rewrite/editor/KotlinLanguage.kt +++ b/app/src/main/java/org/cosmicide/rewrite/editor/KotlinLanguage.kt @@ -15,26 +15,29 @@ import org.cosmicide.project.Project import java.io.File class KotlinLanguage( - private val mEditor: CodeEditor, - project: Project, - file: File + private val editor: CodeEditor, + private val project: Project, + private val file: File ) : TextMateLanguage( - GrammarRegistry.getInstance().findGrammar("source.kotlin"), - GrammarRegistry.getInstance().findLanguageConfiguration("source.kotlin"), - GrammarRegistry.getInstance(), - ThemeRegistry.getInstance(), + grammarRegistry.findGrammar("source.kotlin"), + grammarRegistry.findLanguageConfiguration("source.kotlin"), + grammarRegistry, + themeRegistry, false ) { private val kotlinEnvironment: KotlinEnvironment by lazy { KotlinEnvironment.get(project) } - private val fileName: String - private val TAG = "KotlinLanguage" + private var fileName = file.name init { - val ktFile = kotlinEnvironment.updateKotlinFile( - file.absolutePath, mEditor.text.toString() - ) - fileName = ktFile.name + try { + val ktFile = kotlinEnvironment.updateKotlinFile( + file.absolutePath, editor.text.toString() + ) + fileName = ktFile.name + } catch (e: Exception) { + Log.e(TAG, "Failed to update Kotlin file", e) + } } @WorkerThread @@ -45,7 +48,7 @@ class KotlinLanguage( extraArguments: Bundle ) { try { - val text = mEditor.text.toString() + val text = editor.text.toString() val ktFile = kotlinEnvironment.updateKotlinFile(fileName, text) val itemList = kotlinEnvironment.complete( ktFile, position.line, position.column @@ -58,4 +61,10 @@ class KotlinLanguage( } super.requireAutoComplete(content, position, publisher, extraArguments) } -} + + companion object { + private const val TAG = "KotlinLanguage" + private val grammarRegistry = GrammarRegistry.getInstance() + private val themeRegistry = ThemeRegistry.getInstance() + } +} \ No newline at end of file