diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml
index 46d507c83..882b7c7d4 100644
--- a/.idea/codeStyles/Project.xml
+++ b/.idea/codeStyles/Project.xml
@@ -41,7 +41,7 @@
-
+
diff --git a/app/src/main/java/com/itsaky/androidide/EditorActivity.java b/app/src/main/java/com/itsaky/androidide/EditorActivity.java
index 952d4e229..be9123fa9 100755
--- a/app/src/main/java/com/itsaky/androidide/EditorActivity.java
+++ b/app/src/main/java/com/itsaky/androidide/EditorActivity.java
@@ -102,6 +102,7 @@ import com.itsaky.androidide.models.LogLine;
import com.itsaky.androidide.models.Range;
import com.itsaky.androidide.models.SaveResult;
import com.itsaky.androidide.models.SearchResult;
+import com.itsaky.androidide.projects.FileManager;
import com.itsaky.androidide.projects.ProjectManager;
import com.itsaky.androidide.projects.api.Project;
import com.itsaky.androidide.services.GradleBuildService;
@@ -109,10 +110,12 @@ import com.itsaky.androidide.services.LogReceiver;
import com.itsaky.androidide.shell.ShellServer;
import com.itsaky.androidide.tooling.api.messages.result.SimpleVariantData;
import com.itsaky.androidide.tooling.api.messages.result.TaskExecutionResult;
+import com.itsaky.androidide.utils.BootClasspathProvider;
import com.itsaky.androidide.utils.CharSequenceInputStream;
import com.itsaky.androidide.utils.DialogUtils;
import com.itsaky.androidide.utils.EditorActivityActions;
import com.itsaky.androidide.utils.EditorBottomSheetBehavior;
+import com.itsaky.androidide.utils.Environment;
import com.itsaky.androidide.utils.ILogger;
import com.itsaky.androidide.utils.LSPUtils;
import com.itsaky.androidide.utils.RecursiveFileSearcher;
@@ -161,6 +164,7 @@ public class EditorActivity extends StudioActivity
private static final int ACTION_ID_ALL = 102;
private static final ILogger LOG = ILogger.newInstance("EditorActivity");
private final EditorEventListener mBuildEventListener = new EditorEventListener();
+ private final FileTreeActionHandler mFileActionsHandler = new FileTreeActionHandler();
private ActivityEditorBinding mBinding;
private LayoutDiagnosticInfoBinding mDiagnosticInfoBinding;
private EditorBottomSheetTabAdapter bottomSheetTabAdapter;
@@ -174,9 +178,6 @@ public class EditorActivity extends StudioActivity
private ActivityResultLauncher mUIDesignerLauncher;
private EditorBottomSheetBehavior extends View> mEditorBottomSheet;
private EditorViewModel mViewModel;
-
- private final FileTreeActionHandler mFileActionsHandler = new FileTreeActionHandler();
-
private GradleBuildService mBuildService;
private final ServiceConnection mGradleServiceConnection =
new ServiceConnection() {
@@ -196,21 +197,6 @@ public class EditorActivity extends StudioActivity
}
};
- @Override
- public void onBackPressed() {
- if (mBinding.getRoot().isDrawerOpen(GravityCompat.END)) {
- mBinding.getRoot().closeDrawer(GravityCompat.END);
- } else if (mBinding.getRoot().isDrawerOpen(GravityCompat.START)) {
- mBinding.getRoot().closeDrawer(GravityCompat.START);
- } else if (getDaemonStatusFragment().isShowing()) {
- getDaemonStatusFragment().dismiss();
- } else if (mEditorBottomSheet.getState() == BottomSheetBehavior.STATE_EXPANDED) {
- mEditorBottomSheet.setState(BottomSheetBehavior.STATE_COLLAPSED);
- } else {
- confirmProjectClose();
- }
- }
-
@SuppressLint("RestrictedApi")
@Override
public boolean onCreateOptionsMenu(Menu menu) {
@@ -1046,10 +1032,6 @@ public class EditorActivity extends StudioActivity
execTasks(null, "lintRelease");
}
- /////////////////////////////////////////////////
- ////////////// PRIVATE APIS /////////////////////
- /////////////////////////////////////////////////
-
public void cleanAndRebuild() {
execTasks(null, "clean", "build");
}
@@ -1141,26 +1123,6 @@ public class EditorActivity extends StudioActivity
}
}
- @Override
- protected void onSaveInstanceState(@NonNull final Bundle outState) {
- outState.putString(KEY_PROJECT_PATH, ProjectManager.INSTANCE.getProjectDirPath());
- super.onSaveInstanceState(outState);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- mFileActionsHandler.register();
- ProjectManager.INSTANCE.register();
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- mFileActionsHandler.unregister();
- ProjectManager.INSTANCE.unregister();
- }
-
// TODO Replace with events
private void dispatchOnResumeToEditors() {
CompletableFuture.runAsync(
@@ -1186,6 +1148,48 @@ public class EditorActivity extends StudioActivity
});
}
+ @Override
+ protected void onSaveInstanceState(@NonNull final Bundle outState) {
+ outState.putString(KEY_PROJECT_PATH, ProjectManager.INSTANCE.getProjectDirPath());
+ super.onSaveInstanceState(outState);
+ }
+
+ @Override
+ public void onBackPressed() {
+ if (mBinding.getRoot().isDrawerOpen(GravityCompat.END)) {
+ mBinding.getRoot().closeDrawer(GravityCompat.END);
+ } else if (mBinding.getRoot().isDrawerOpen(GravityCompat.START)) {
+ mBinding.getRoot().closeDrawer(GravityCompat.START);
+ } else if (getDaemonStatusFragment().isShowing()) {
+ getDaemonStatusFragment().dismiss();
+ } else if (mEditorBottomSheet.getState() == BottomSheetBehavior.STATE_EXPANDED) {
+ mEditorBottomSheet.setState(BottomSheetBehavior.STATE_COLLAPSED);
+ } else {
+ confirmProjectClose();
+ }
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ // Make sure we list and store the bootstrap classes
+ CompletableFuture.runAsync(
+ () ->
+ BootClasspathProvider.update(
+ Collections.singleton(Environment.ANDROID_JAR.getAbsolutePath())));
+
+ mFileActionsHandler.register();
+ FileManager.INSTANCE.register();
+ }
+
+ @Override
+ protected void onStop() {
+ super.onStop();
+ mFileActionsHandler.unregister();
+ FileManager.INSTANCE.unregister();
+ }
+
@Override
protected void onDestroy() {
closeProject(false);
diff --git a/app/src/main/java/com/itsaky/androidide/adapters/SearchListAdapter.kt b/app/src/main/java/com/itsaky/androidide/adapters/SearchListAdapter.kt
index 91a6cf0d5..f3df600a1 100755
--- a/app/src/main/java/com/itsaky/androidide/adapters/SearchListAdapter.kt
+++ b/app/src/main/java/com/itsaky/androidide/adapters/SearchListAdapter.kt
@@ -1,6 +1,5 @@
/**
- * ********************************************************************************** This file is
- * part of AndroidIDE.
+ * 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
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/FileManager.kt b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/FileManager.kt
new file mode 100644
index 000000000..e0b2afce6
--- /dev/null
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/FileManager.kt
@@ -0,0 +1,170 @@
+/*
+ * 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 .
+ */
+
+package com.itsaky.androidide.projects
+
+import com.itsaky.androidide.eventbus.events.EventReceiver
+import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent
+import com.itsaky.androidide.eventbus.events.editor.DocumentCloseEvent
+import com.itsaky.androidide.eventbus.events.editor.DocumentOpenEvent
+import com.itsaky.androidide.models.Range
+import com.itsaky.androidide.progress.ProcessCancelledException
+import com.itsaky.androidide.progress.ProgressManager
+import com.itsaky.androidide.projects.models.ActiveDocument
+import com.itsaky.androidide.utils.ILogger
+import java.io.BufferedReader
+import java.io.InputStream
+import java.nio.charset.Charset
+import java.nio.file.Files
+import java.nio.file.Path
+import java.time.Instant
+import org.apache.commons.io.FileUtils
+import org.greenrobot.eventbus.Subscribe
+import org.greenrobot.eventbus.ThreadMode.BACKGROUND
+
+/**
+ * Manages active documents.
+ *
+ * @author Akash Yadav
+ */
+object FileManager : EventReceiver {
+
+ private val log = ILogger.newInstance(javaClass.simpleName)
+ private val activeDocuments: MutableMap = mutableMapOf()
+
+ fun isActive(file: Path): Boolean {
+ return this.activeDocuments.containsKey(file.normalize())
+ }
+
+ fun getActiveDocument(file: Path): ActiveDocument? {
+ return this.activeDocuments[file.normalize()]
+ }
+
+ fun getDocumentContents(file: Path): String {
+ val document = getActiveDocument(file)
+ if (document != null) {
+ return document.content
+ }
+
+ return getFileContents(file)
+ }
+
+ fun getLastModified(file: Path): Instant {
+ val document = getActiveDocument(file)
+ if (document != null) {
+ return document.modified
+ }
+
+ return getLastModifiedFromDisk(file)
+ }
+
+ fun getReader(file: Path): BufferedReader {
+ val document = getActiveDocument(file)
+ if (document != null) {
+ return document.content.reader().buffered()
+ }
+
+ return createFileReader(file)
+ }
+
+ fun getInputStream(file: Path): InputStream {
+ val document = getActiveDocument(file)
+ if (document != null) {
+ return document.content.byteInputStream().buffered()
+ }
+
+ return createFileInputStream(file)
+ }
+
+ @Subscribe(threadMode = BACKGROUND)
+ @Suppress("unused")
+ fun onDocumentOpen(event: DocumentOpenEvent) {
+ activeDocuments[event.openedFile.normalize()] = createDocument(event)
+ }
+
+ @Subscribe(threadMode = BACKGROUND)
+ @Suppress("unused")
+ fun onDocumentContentChange(event: DocumentChangeEvent) {
+ activeDocuments[event.changedFile.normalize()] = createDocument(event)
+ }
+
+ @Subscribe(threadMode = BACKGROUND)
+ @Suppress("unused")
+ fun onDocumentClose(event: DocumentCloseEvent) {
+ activeDocuments.remove(event.closedFile.normalize())
+ }
+
+ private fun createDocument(event: DocumentOpenEvent): ActiveDocument {
+ return ActiveDocument(
+ file = event.openedFile,
+ content = event.text,
+ changeRange = Range.NONE,
+ version = event.version,
+ changDelta = 0,
+ modified = Instant.now()
+ )
+ }
+
+ private fun createDocument(event: DocumentChangeEvent): ActiveDocument {
+ return ActiveDocument(
+ file = event.changedFile,
+ content = event.newText,
+ changeRange = event.changeRange,
+ version = event.version,
+ changDelta = event.changeDelta,
+ modified = Instant.now()
+ )
+ }
+
+ private fun createFileReader(file: Path): BufferedReader {
+ return try {
+ Files.newBufferedReader(file)
+ } catch (noFile: java.nio.file.NoSuchFileException) {
+ log.warn("No such file", noFile)
+ "".reader().buffered()
+ } catch (cancelled: ProcessCancelledException) {
+ "".reader().buffered()
+ }
+ }
+
+ private fun createFileInputStream(file: Path): InputStream {
+ return try {
+ Files.newInputStream(file)
+ } catch (noFile: java.nio.file.NoSuchFileException) {
+ log.warn("No such file", noFile)
+ "".byteInputStream()
+ } catch (cancelled: ProcessCancelledException) {
+ "".byteInputStream()
+ }
+ }
+
+ private fun getLastModifiedFromDisk(file: Path): Instant {
+ return Files.getLastModifiedTime(file).toInstant()
+ }
+
+ private fun getFileContents(file: Path): String {
+ return try {
+ ProgressManager.abortIfCancelled()
+ FileUtils.readFileToString(file.toFile(), Charset.defaultCharset())
+ } catch (noFile: java.nio.file.NoSuchFileException) {
+ log.warn("No such file", noFile)
+ ""
+ } catch (cancelled: ProcessCancelledException) {
+ ""
+ }
+ }
+}
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/ProjectManager.kt b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/ProjectManager.kt
index 985fe4b52..0f5091fb5 100644
--- a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/ProjectManager.kt
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/ProjectManager.kt
@@ -16,45 +16,24 @@
*/
package com.itsaky.androidide.projects
-import com.itsaky.androidide.eventbus.events.EventReceiver
-import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent
-import com.itsaky.androidide.eventbus.events.editor.DocumentCloseEvent
-import com.itsaky.androidide.eventbus.events.editor.DocumentOpenEvent
import com.itsaky.androidide.eventbus.events.project.ProjectInitializedEvent
-import com.itsaky.androidide.progress.ProcessCancelledException
-import com.itsaky.androidide.progress.ProgressManager.Companion.abortIfCancelled
import com.itsaky.androidide.projects.api.AndroidModule
import com.itsaky.androidide.projects.api.ModuleProject
import com.itsaky.androidide.projects.api.Project
import com.itsaky.androidide.projects.builder.BuildService
-import com.itsaky.androidide.projects.models.ActiveDocument
import com.itsaky.androidide.projects.util.ProjectTransformer
import com.itsaky.androidide.tooling.api.IProject
-import com.itsaky.androidide.utils.BootClasspathProvider
-import com.itsaky.androidide.utils.Environment
import com.itsaky.androidide.utils.ILogger
-import java.io.BufferedInputStream
-import java.io.BufferedReader
import java.io.File
-import java.io.InputStream
-import java.io.StringReader
-import java.nio.charset.Charset
-import java.nio.file.Files
import java.nio.file.Path
-import java.time.Instant
-import java.util.*
-import java.util.concurrent.*
-import org.apache.commons.io.FileUtils
import org.greenrobot.eventbus.EventBus
-import org.greenrobot.eventbus.Subscribe
-import org.greenrobot.eventbus.ThreadMode.BACKGROUND
/**
* Manages projects in AndroidIDE.
*
* @author Akash Yadav
*/
-object ProjectManager : EventReceiver {
+object ProjectManager {
private val log = ILogger.newInstance(javaClass.simpleName)
lateinit var projectPath: String
@@ -146,24 +125,6 @@ object ProjectManager : EventReceiver {
return findModuleForFile(file.toFile())
}
- fun isDocumentActive(file: Path): Boolean {
- if (!checkInit()) {
- return false
- }
-
- for (module in this.rootProject!!.subModules) {
- if (module !is ModuleProject) {
- continue
- }
-
- if (module.isActive(file)) {
- return true
- }
- }
-
- return false
- }
-
fun containsSourceFile(file: Path): Boolean {
if (!checkInit()) {
return false
@@ -183,144 +144,10 @@ object ProjectManager : EventReceiver {
return false
}
- fun getActiveDocument(file: Path): ActiveDocument? {
- if (!checkInit()) {
- return null
- }
-
- for (module in this.rootProject!!.subModules) {
- if (module !is ModuleProject) {
- continue
- }
-
- val document = module.getActiveDocument(file)
- if (document != null) {
- return document
- }
- }
-
- return null
- }
-
- fun getLastModified(file: Path): Instant {
- if (!checkInit()) {
- return getLastModifiedFromDisk(file)
- }
-
- val document = getActiveDocument(file)
- if (document != null) {
- return document.modified
- }
-
- return getLastModifiedFromDisk(file)
- }
-
- fun getDocumentContents(file: Path): String {
- if (!checkInit()) {
- return getFileContents(file)
- }
-
- val document = getActiveDocument(file)
- if (document != null) {
- return document.content
- }
-
- return getFileContents(file)
- }
-
- fun getReader(file: Path): BufferedReader {
- if (!checkInit()) {
- return createFileReader(file)
- }
-
- val document = getActiveDocument(file)
- if (document != null) {
- return BufferedReader(StringReader(document.content))
- }
-
- return createFileReader(file)
- }
-
- fun getInputStream(file: Path): InputStream {
- if (!checkInit()) {
- return createFileInputStream(file)
- }
-
- val document = getActiveDocument(file)
- if (document != null) {
- BufferedInputStream(document.content.byteInputStream())
- }
-
- return createFileInputStream(file)
- }
-
//////////////////////////////////////////////////////////////////////////////////////////
////// TODO Subscribe to file creation/deletion/rename events and update source map //////
//////////////////////////////////////////////////////////////////////////////////////////
- override fun register() {
- super.register()
-
- // Make sure we list and store the bootstrap classes
- CompletableFuture.runAsync {
- BootClasspathProvider.update(Collections.singleton(Environment.ANDROID_JAR.absolutePath))
- }
- }
-
- @Subscribe(threadMode = BACKGROUND)
- @Suppress("unused")
- fun onDocumentOpen(event: DocumentOpenEvent) {
- if (!checkInit()) {
- return
- }
-
- for (subModule in this.rootProject!!.subModules) {
- if (subModule !is ModuleProject) {
- continue
- }
-
- if (subModule.onDocumentOpen(event)) {
- break
- }
- }
- }
-
- @Subscribe(threadMode = BACKGROUND)
- @Suppress("unused")
- fun onDocumentClose(event: DocumentCloseEvent) {
- if (!checkInit()) {
- return
- }
-
- for (subModule in this.rootProject!!.subModules) {
- if (subModule !is ModuleProject) {
- continue
- }
-
- if (subModule.onDocumentClose(event)) {
- break
- }
- }
- }
-
- @Subscribe(threadMode = BACKGROUND)
- @Suppress("unused")
- fun onDocumentContentChange(event: DocumentChangeEvent) {
- if (!checkInit()) {
- return
- }
-
- for (subModule in this.rootProject!!.subModules) {
- if (subModule !is ModuleProject) {
- continue
- }
-
- if (subModule.onDocumentChanged(event)) {
- break
- }
- }
- }
-
private fun isInitialized() = rootProject != null
private fun checkInit(): Boolean {
@@ -331,45 +158,4 @@ object ProjectManager : EventReceiver {
log.warn("Project is not initialized yet!")
return false
}
-
- private fun createFileReader(file: Path): BufferedReader {
- return try {
- Files.newBufferedReader(file)
- } catch (noFile: java.nio.file.NoSuchFileException) {
- log.warn("No such file", noFile)
- "".reader().buffered()
- } catch (cancelled: ProcessCancelledException) {
- log.debug("createFileReader(): cancelled")
- "".reader().buffered()
- }
- }
-
- private fun createFileInputStream(file: Path): InputStream {
- return try {
- Files.newInputStream(file)
- } catch (noFile: java.nio.file.NoSuchFileException) {
- log.warn("No such file", noFile)
- "".byteInputStream()
- } catch (cancelled: ProcessCancelledException) {
- log.debug("createFileInputStream(): cancelled")
- "".byteInputStream()
- }
- }
-
- private fun getLastModifiedFromDisk(file: Path): Instant {
- return Files.getLastModifiedTime(file).toInstant()
- }
-
- private fun getFileContents(file: Path): String {
- return try {
- abortIfCancelled()
- FileUtils.readFileToString(file.toFile(), Charset.defaultCharset())
- } catch (noFile: java.nio.file.NoSuchFileException) {
- log.warn("No such file", noFile)
- ""
- } catch (cancelled: ProcessCancelledException) {
- log.debug("getFileContents(): cancelled")
- ""
- }
- }
}
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/ModuleProject.kt b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/ModuleProject.kt
index 39b90ebc6..cc8381975 100644
--- a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/ModuleProject.kt
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/api/ModuleProject.kt
@@ -18,22 +18,15 @@
package com.itsaky.androidide.projects.api
import android.text.TextUtils
-import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent
-import com.itsaky.androidide.eventbus.events.editor.DocumentCloseEvent
-import com.itsaky.androidide.eventbus.events.editor.DocumentOpenEvent
-import com.itsaky.androidide.models.Range
-import com.itsaky.androidide.projects.models.ActiveDocument
+import com.itsaky.androidide.tooling.api.model.GradleTask
import com.itsaky.androidide.utils.ClassTrie
+import com.itsaky.androidide.utils.ClasspathReader
import com.itsaky.androidide.utils.DocumentUtils
+import com.itsaky.androidide.utils.ILogger
import com.itsaky.androidide.utils.SourceClassTrie
import com.itsaky.androidide.utils.SourceClassTrie.SourceNode
-import com.itsaky.androidide.tooling.api.model.GradleTask
-import com.itsaky.androidide.utils.ClasspathReader
-import com.itsaky.androidide.utils.ILogger
import java.io.File
import java.nio.file.Path
-import java.time.Instant
-import java.util.concurrent.*
/**
* A module project. Base class for [AndroidModule] and [JavaModule].
@@ -63,12 +56,6 @@ abstract class ModuleProject(
@JvmField val compileJavaSourceClasses = SourceClassTrie()
@JvmField val compileClasspathClasses = ClassTrie()
- /**
- * Map of documents that are open in the editor. Keys here are the canonical paths of the
- * documents.
- */
- val activeDocuments: MutableMap = ConcurrentHashMap()
-
/**
* Get the source directories of this module (non-transitive i.e for this module only).
*
@@ -105,59 +92,6 @@ abstract class ModuleProject(
*/
abstract fun getCompileModuleProjects(): List
- /**
- * Called by [com.itsaky.androidide.projects.ProjectManager] when a document is opened.
- *
- * @param event The event descriptor.
- * @return `true` if this module consumed the event. `false` otherwise.
- */
- fun onDocumentOpen(event: DocumentOpenEvent): Boolean {
- if (!isCacheable(event.openedFile) || !isFromThisModule(event.openedFile)) {
- return false
- }
-
- activeDocuments[event.openedFile.normalize()] = createDocument(event)
- return true
- }
-
- /**
- * Called by [com.itsaky.androidide.projects.ProjectManager] when a document is changed.
- *
- * @param event The event descriptor.
- * @return `true` if this module consumed the event. `false` otherwise.
- */
- fun onDocumentChanged(event: DocumentChangeEvent): Boolean {
- if (!isCacheable(event.changedFile) || !isFromThisModule(event.changedFile)) {
- return false
- }
-
- activeDocuments[event.changedFile.normalize()] = createDocument(event)
- return true
- }
-
- /**
- * Called by [com.itsaky.androidide.projects.ProjectManager] when a document is closed.
- *
- * @param event The event descriptor.
- * @return `true` if this module consumed the event. `false` otherwise.
- */
- fun onDocumentClose(event: DocumentCloseEvent): Boolean {
- if (!isCacheable(event.closedFile) || !isFromThisModule(event.closedFile)) {
- return false
- }
-
- activeDocuments.remove(event.closedFile.normalize())
- return true
- }
-
- fun isActive(file: Path): Boolean {
- return this.activeDocuments.containsKey(file.normalize())
- }
-
- fun getActiveDocument(file: Path): ActiveDocument? {
- return this.activeDocuments[file.normalize()]
- }
-
/** Finds the source files and classes from source directories and classpaths and indexes them. */
@Suppress("UnstableApiUsage")
fun indexSourcesAndClasspaths() {
@@ -229,35 +163,8 @@ abstract class ModuleProject(
.filterIsInstance(SourceNode::class.java)
}
- protected open fun isCacheable(file: Path): Boolean {
- // For now, we only cache Java files
- return DocumentUtils.isJavaFile(file)
- }
-
- protected open fun isFromThisModule(file: Path): Boolean {
+ open fun isFromThisModule(file: Path): Boolean {
// TODO This can be probably improved
return file.startsWith(this.projectDir.toPath())
}
-
- protected open fun createDocument(event: DocumentOpenEvent): ActiveDocument {
- return ActiveDocument(
- file = event.openedFile,
- content = event.text,
- changeRange = Range.NONE,
- version = event.version,
- changDelta = 0,
- modified = Instant.now()
- )
- }
-
- protected open fun createDocument(event: DocumentChangeEvent): ActiveDocument {
- return ActiveDocument(
- file = event.changedFile,
- content = event.newText,
- changeRange = event.changeRange,
- version = event.version,
- changDelta = event.changeDelta,
- modified = Instant.now()
- )
- }
}
diff --git a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/util/StringSearch.java b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/util/StringSearch.java
index 9de04c4c9..0695b4cd1 100644
--- a/build-tools/projects/src/main/java/com/itsaky/androidide/projects/util/StringSearch.java
+++ b/build-tools/projects/src/main/java/com/itsaky/androidide/projects/util/StringSearch.java
@@ -17,7 +17,7 @@
package com.itsaky.androidide.projects.util;
-import com.itsaky.androidide.projects.ProjectManager;
+import com.itsaky.androidide.projects.FileManager;
import com.itsaky.androidide.projects.models.ActiveDocument;
import com.itsaky.androidide.utils.Cache;
@@ -201,13 +201,8 @@ public class StringSearch {
private static final ByteBuffer SEARCH_BUFFER = ByteBuffer.allocateDirect(1024 * 1024);
private static String tryGetActiveDocContent(Path file) {
- if (ProjectManager.INSTANCE.isDocumentActive(file)) {
- final ActiveDocument document = ProjectManager.INSTANCE.getActiveDocument(file);
-
- if (document == null) {
- return null;
- }
-
+ final ActiveDocument document = FileManager.INSTANCE.getActiveDocument(file);
+ if (document != null) {
return document.getContent();
}
@@ -378,7 +373,7 @@ public class StringSearch {
public static String packageName(Path file) {
Pattern packagePattern = Pattern.compile("^package +(.*);");
Pattern startOfClass = Pattern.compile("^[\\w ]*class +\\w+");
- try (BufferedReader lines = ProjectManager.INSTANCE.getReader(file)) {
+ try (BufferedReader lines = FileManager.INSTANCE.getReader(file)) {
for (String line = lines.readLine(); line != null; line = lines.readLine()) {
if (startOfClass.matcher(line).find()) return "";
Matcher matchPackage = packagePattern.matcher(line);
diff --git a/common/src/main/java/com/itsaky/androidide/utils/Cache.java b/common/src/main/java/com/itsaky/androidide/utils/Cache.java
index b1bf2fbff..eac3b402a 100644
--- a/common/src/main/java/com/itsaky/androidide/utils/Cache.java
+++ b/common/src/main/java/com/itsaky/androidide/utils/Cache.java
@@ -30,6 +30,9 @@ import java.util.Objects;
public class Cache {
private static final ILogger LOG = ILogger.newInstance("Cache");
+ // Cannot access FileManager from this module
+ private static Object FileManager_INSTANCE;
+ private static Method FileManager_getLastModified;
private final Map, Value> map = new HashMap<>();
public boolean has(Path file, K k) {
@@ -54,6 +57,39 @@ public class Cache {
return value.created.isBefore(modified);
}
+ private static Instant getLastModified(Path file) {
+ initProjectManagerInstance();
+
+ try {
+ return (Instant) FileManager_getLastModified.invoke(FileManager_INSTANCE, file);
+ } catch (Throwable err) {
+ LOG.error("Cannot get last modified from ProjectManager", err);
+ return Instant.now();
+ }
+ }
+
+ private static void initProjectManagerInstance() {
+ if (FileManager_INSTANCE == null) {
+ try {
+ final var klass = Class.forName("com.itsaky.androidide.projects.FileManager");
+ final var field = klass.getDeclaredField("INSTANCE");
+ if (!field.isAccessible()) {
+ field.setAccessible(true);
+ }
+
+ FileManager_INSTANCE = field.get(null);
+
+ FileManager_getLastModified = klass.getDeclaredMethod("getLastModified", Path.class);
+ if (!FileManager_getLastModified.isAccessible()) {
+ FileManager_getLastModified.setAccessible(true);
+ }
+ } catch (Throwable err) {
+ LOG.error("Cannot reflect ProjectManager INSTANCE", err);
+ throw new RuntimeException(err);
+ }
+ }
+ }
+
public void load(Path file, K k, V v) {
// TODO limit total size of cache
Key key = new Key<>(file, k);
@@ -102,41 +138,4 @@ public class Cache {
this.value = value;
}
}
-
- // Cannot access ProjectManager from this module
- private static Object ProjectManager_INSTANCE;
- private static Method ProjectManager_getLastModified;
-
- private static Instant getLastModified(Path file) {
- initProjectManagerInstance();
-
- try {
- return (Instant) ProjectManager_getLastModified.invoke(ProjectManager_INSTANCE, file);
- } catch (Throwable err) {
- LOG.error("Cannot get last modified from ProjectManager", err);
- return Instant.now();
- }
- }
-
- private static void initProjectManagerInstance() {
- if (ProjectManager_INSTANCE == null) {
- try {
- final var klass = Class.forName("com.itsaky.androidide.projects.ProjectManager");
- final var field = klass.getDeclaredField("INSTANCE");
- if (!field.isAccessible()) {
- field.setAccessible(true);
- }
-
- ProjectManager_INSTANCE = field.get(null);
-
- ProjectManager_getLastModified = klass.getDeclaredMethod("getLastModified", Path.class);
- if (!ProjectManager_getLastModified.isAccessible()) {
- ProjectManager_getLastModified.setAccessible(true);
- }
- } catch (Throwable err) {
- LOG.error("Cannot reflect ProjectManager INSTANCE", err);
- throw new RuntimeException(err);
- }
- }
- }
}
diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/CompileBatch.java b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/CompileBatch.java
index fa272f3d9..372f9e6d4 100644
--- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/CompileBatch.java
+++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/CompileBatch.java
@@ -29,6 +29,7 @@ import com.itsaky.androidide.javac.services.partial.DiagnosticListenerImpl;
import com.itsaky.androidide.lsp.java.parser.Parser;
import com.itsaky.androidide.lsp.java.visitors.MethodRangeScanner;
import com.itsaky.androidide.models.Range;
+import com.itsaky.androidide.projects.FileManager;
import com.itsaky.androidide.projects.ProjectManager;
import com.itsaky.androidide.projects.api.AndroidModule;
import com.itsaky.androidide.projects.api.ModuleProject;
@@ -246,7 +247,7 @@ public class CompileBatch implements AutoCloseable {
private String errorText(javax.tools.Diagnostic extends javax.tools.JavaFileObject> err) {
Path file = Paths.get(err.getSource().toUri());
- CharSequence contents = ProjectManager.INSTANCE.getDocumentContents(file);
+ CharSequence contents = FileManager.INSTANCE.getDocumentContents(file);
int begin = (int) err.getStartPosition();
int end = (int) err.getEndPosition();
return substring(contents, begin, end);
diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/JavaCompilerService.java b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/JavaCompilerService.java
index c6742700a..3c5b045ec 100644
--- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/JavaCompilerService.java
+++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/JavaCompilerService.java
@@ -33,6 +33,7 @@ import com.itsaky.androidide.lsp.java.parser.Parser;
import com.itsaky.androidide.lsp.java.utils.Extractors;
import com.itsaky.androidide.lsp.java.visitors.FindTypeDeclarations;
import com.itsaky.androidide.models.Range;
+import com.itsaky.androidide.projects.FileManager;
import com.itsaky.androidide.projects.ProjectManager;
import com.itsaky.androidide.projects.api.ModuleProject;
import com.itsaky.androidide.projects.util.StringSearch;
@@ -131,7 +132,7 @@ public class JavaCompilerService implements CompilerProvider {
List list = new ArrayList<>();
Pattern importClass = Pattern.compile("^import +([\\w.]+\\.\\w+);");
Pattern importStar = Pattern.compile("^import +([\\w.]+\\.\\*);");
- try (BufferedReader lines = ProjectManager.INSTANCE.getReader(file)) {
+ try (BufferedReader lines = FileManager.INSTANCE.getReader(file)) {
for (String line = lines.readLine(); line != null; line = lines.readLine()) {
// If we reach a class declaration, stop looking for imports
// TODO This could be a little more specific
diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/SourceFileObject.java b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/SourceFileObject.java
index d71817e9a..6b990196c 100644
--- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/SourceFileObject.java
+++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/compiler/SourceFileObject.java
@@ -18,7 +18,7 @@
package com.itsaky.androidide.lsp.java.compiler;
import com.itsaky.androidide.lsp.util.PathUtils;
-import com.itsaky.androidide.projects.ProjectManager;
+import com.itsaky.androidide.projects.FileManager;
import com.itsaky.androidide.utils.DocumentUtils;
import java.io.ByteArrayInputStream;
@@ -117,7 +117,7 @@ public class SourceFileObject implements JavaFileObject {
byte[] bytes = contents.getBytes();
return new ByteArrayInputStream(bytes);
}
- return ProjectManager.INSTANCE.getInputStream(path);
+ return FileManager.INSTANCE.getInputStream(path);
}
@Override
@@ -130,7 +130,7 @@ public class SourceFileObject implements JavaFileObject {
if (contents != null) {
return new StringReader(contents);
}
- return ProjectManager.INSTANCE.getReader(path);
+ return FileManager.INSTANCE.getReader(path);
}
@Override
@@ -138,7 +138,7 @@ public class SourceFileObject implements JavaFileObject {
if (contents != null) {
return contents;
}
- return ProjectManager.INSTANCE.getDocumentContents(this.path);
+ return FileManager.INSTANCE.getDocumentContents(this.path);
}
@Override
@@ -151,7 +151,7 @@ public class SourceFileObject implements JavaFileObject {
if (contents != null) {
return modified.toEpochMilli();
}
- return ProjectManager.INSTANCE.getLastModified(this.path).toEpochMilli();
+ return FileManager.INSTANCE.getLastModified(this.path).toEpochMilli();
}
@Override
diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/DiagnosticsProvider.kt b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/DiagnosticsProvider.kt
index 2e28c8e7b..4673c5e0c 100644
--- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/DiagnosticsProvider.kt
+++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/DiagnosticsProvider.kt
@@ -26,6 +26,7 @@ import com.itsaky.androidide.lsp.models.DiagnosticSeverity
import com.itsaky.androidide.lsp.models.DiagnosticSeverity.WARNING
import com.itsaky.androidide.lsp.util.PathUtils.Companion.isSameFile
import com.itsaky.androidide.models.Range
+import com.itsaky.androidide.projects.FileManager
import com.itsaky.androidide.projects.ProjectManager
import com.sun.source.tree.BlockTree
import com.sun.source.tree.ClassTree
@@ -192,7 +193,7 @@ object DiagnosticsProvider {
}
}
val file = Paths.get(root.sourceFile.toUri())
- val contents = ProjectManager.getDocumentContents(file)
+ val contents = FileManager.getDocumentContents(file)
var name = unusedEl.simpleName
if (name.contentEquals("")) {
name = unusedEl.enclosingElement.simpleName
diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/JavaDiagnosticProvider.kt b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/JavaDiagnosticProvider.kt
index 6732e1f83..99a19dc6a 100644
--- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/JavaDiagnosticProvider.kt
+++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/JavaDiagnosticProvider.kt
@@ -20,6 +20,7 @@ import com.itsaky.androidide.lsp.java.compiler.CompileTask
import com.itsaky.androidide.lsp.java.compiler.JavaCompilerService
import com.itsaky.androidide.lsp.java.providers.DiagnosticsProvider.findDiagnostics
import com.itsaky.androidide.lsp.java.utils.CancelChecker
+import com.itsaky.androidide.projects.FileManager
import com.itsaky.androidide.projects.ProjectManager
import com.itsaky.androidide.utils.ILogger
import java.nio.file.Path
@@ -51,7 +52,7 @@ class JavaDiagnosticProvider(private val completionChecker: Supplier) {
return com.itsaky.androidide.lsp.models.DiagnosticResult.NO_UPDATE
}
- val modifiedAt = ProjectManager.getLastModified(file)
+ val modifiedAt = FileManager.getLastModified(file)
val analyzedAt = analyzeTimestamps[file]
if (analyzedAt?.isAfter(modifiedAt) == true) {
diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/completion/ScopeCompletionProvider.kt b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/completion/ScopeCompletionProvider.kt
index 5369ac517..159447678 100644
--- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/completion/ScopeCompletionProvider.kt
+++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/providers/completion/ScopeCompletionProvider.kt
@@ -34,6 +34,7 @@ import com.itsaky.androidide.lsp.models.CompletionResult
import com.itsaky.androidide.lsp.models.InsertTextFormat.SNIPPET
import com.itsaky.androidide.lsp.models.MatchLevel.NO_MATCH
import com.itsaky.androidide.progress.ProgressManager.Companion.abortIfCancelled
+import com.itsaky.androidide.projects.FileManager
import com.itsaky.androidide.projects.ProjectManager
import com.squareup.javapoet.MethodSpec.Builder
import com.sun.source.tree.ClassTree
@@ -159,7 +160,7 @@ class ScopeCompletionProvider(
// Print the method details and the annotations
// Print the method details and the annotations
val indent =
- EditHelper.indent(ProjectManager.getDocumentContents(completingFile), cursor.toInt())
+ EditHelper.indent(FileManager.getDocumentContents(completingFile), cursor.toInt())
val builder: Builder
try {
builder = buildMethod(method, types, type)
diff --git a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/visitors/SemanticHighlighter.java b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/visitors/SemanticHighlighter.java
index 8c7f10b1d..5f0900b34 100644
--- a/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/visitors/SemanticHighlighter.java
+++ b/lsp/java/src/main/java/com/itsaky/androidide/lsp/java/visitors/SemanticHighlighter.java
@@ -26,6 +26,7 @@ import com.itsaky.androidide.lsp.models.HighlightToken;
import com.itsaky.androidide.lsp.models.HighlightTokenKind;
import com.itsaky.androidide.models.Position;
import com.itsaky.androidide.models.Range;
+import com.itsaky.androidide.projects.FileManager;
import com.itsaky.androidide.projects.ProjectManager;
import com.itsaky.androidide.utils.ILogger;
import com.sun.source.tree.ClassTree;
@@ -213,7 +214,7 @@ public class SemanticHighlighter extends TreePathScanner