diff --git a/editor/src/main/java/com/itsaky/androidide/editor/snippets/AbstractSnippetVariableResolver.kt b/editor/src/main/java/com/itsaky/androidide/editor/snippets/AbstractSnippetVariableResolver.kt
new file mode 100644
index 000000000..391d252bc
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/snippets/AbstractSnippetVariableResolver.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.editor.snippets
+
+import io.github.rosemoe.sora.widget.snippet.variable.ISnippetVariableResolver
+
+/**
+ * Base class for snippet variable resolvers.
+ *
+ * @author Akash Yadav
+ */
+interface AbstractSnippetVariableResolver : ISnippetVariableResolver, AutoCloseable {
+ override fun close() {
+ }
+}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/snippets/FileVariableResolver.kt b/editor/src/main/java/com/itsaky/androidide/editor/snippets/FileVariableResolver.kt
new file mode 100644
index 000000000..b70dee2f8
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/snippets/FileVariableResolver.kt
@@ -0,0 +1,61 @@
+/*
+ * 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.editor.snippets
+
+import com.itsaky.androidide.editor.ui.IDEEditor
+import com.itsaky.androidide.projects.ProjectManager
+import io.github.rosemoe.sora.widget.snippet.variable.FileBasedSnippetVariableResolver
+
+/**
+ * Resolver for resolving snippet variables related to the file opened in an editor.
+ *
+ * @author Akash Yadav
+ */
+class FileVariableResolver(editor: IDEEditor) : FileBasedSnippetVariableResolver(), AbstractSnippetVariableResolver {
+
+ var editor: IDEEditor? = editor
+ private set
+
+ companion object {
+ private const val TM_FILENAME = "TM_FILENAME"
+ private const val TM_FILENAME_BASE = "TM_FILENAME_BASE"
+ private const val TM_DIRECTORY = "TM_DIRECTORY"
+ private const val TM_FILEPATH = "TM_FILEPATH"
+ private const val RELATIVE_FILEPATH = "RELATIVE_FILEPATH"
+ }
+
+ override fun resolve(name: String): String {
+ val file = editor?.file ?: return ""
+ return when (name) {
+ TM_FILENAME -> file.name
+ TM_FILENAME_BASE -> file.nameWithoutExtension
+ TM_DIRECTORY -> file.parentFile?.absolutePath ?: ""
+ TM_FILEPATH -> file.absolutePath
+ RELATIVE_FILEPATH -> file.relativeTo(ProjectManager.getProjectDir()).absolutePath
+ else -> ""
+ }
+ }
+
+ override fun getResolvableNames(): Array {
+ return arrayOf(TM_FILENAME, TM_FILENAME_BASE, TM_DIRECTORY, TM_FILEPATH, RELATIVE_FILEPATH)
+ }
+
+ override fun close() {
+ editor = null
+ }
+}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/snippets/WorkspaceVariableResolver.kt b/editor/src/main/java/com/itsaky/androidide/editor/snippets/WorkspaceVariableResolver.kt
new file mode 100644
index 000000000..9b18d37d4
--- /dev/null
+++ b/editor/src/main/java/com/itsaky/androidide/editor/snippets/WorkspaceVariableResolver.kt
@@ -0,0 +1,48 @@
+/*
+ * 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.editor.snippets
+
+import com.itsaky.androidide.projects.ProjectManager
+import io.github.rosemoe.sora.widget.snippet.variable.WorkspaceBasedSnippetVariableResolver
+
+/**
+ * Resolver for resolving snippet variables related to the opened workspace folder (project).
+ *
+ * @author Akash Yadav
+ */
+class WorkspaceVariableResolver :
+ WorkspaceBasedSnippetVariableResolver(), AbstractSnippetVariableResolver {
+
+ companion object {
+ private const val WORKSPACE_NAME = "WORKSPACE_NAME"
+ private const val WORKSPACE_FOLDER = "WORKSPACE_FOLDER"
+ }
+
+ override fun resolve(name: String): String {
+ val directory = ProjectManager.getProjectDir()
+ return when (name) {
+ WORKSPACE_NAME -> directory.name
+ WORKSPACE_FOLDER -> directory.absolutePath
+ else -> ""
+ }
+ }
+
+ override fun getResolvableNames(): Array {
+ return arrayOf(WORKSPACE_NAME, WORKSPACE_FOLDER)
+ }
+}
diff --git a/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.java b/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.java
index d21c68292..7da326db0 100644
--- a/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.java
+++ b/editor/src/main/java/com/itsaky/androidide/editor/ui/IDEEditor.java
@@ -46,6 +46,9 @@ import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguage;
import com.itsaky.androidide.editor.language.treesitter.TreeSitterLanguageProvider;
import com.itsaky.androidide.editor.schemes.IDEColorScheme;
import com.itsaky.androidide.editor.schemes.IDEColorSchemeProvider;
+import com.itsaky.androidide.editor.snippets.AbstractSnippetVariableResolver;
+import com.itsaky.androidide.editor.snippets.FileVariableResolver;
+import com.itsaky.androidide.editor.snippets.WorkspaceVariableResolver;
import com.itsaky.androidide.eventbus.events.editor.ChangeType;
import com.itsaky.androidide.eventbus.events.editor.ColorSchemeInvalidatedEvent;
import com.itsaky.androidide.eventbus.events.editor.DocumentChangeEvent;
@@ -80,6 +83,7 @@ import io.github.rosemoe.sora.widget.CodeEditor;
import io.github.rosemoe.sora.widget.IDEEditorSearcher;
import io.github.rosemoe.sora.widget.component.EditorAutoCompletion;
import io.github.rosemoe.sora.widget.component.EditorTextActionWindow;
+import io.github.rosemoe.sora.widget.snippet.variable.ISnippetVariableResolver;
import java.io.File;
import java.util.concurrent.CompletableFuture;
import kotlin.io.FilesKt;
@@ -426,6 +430,8 @@ public class IDEEditor extends CodeEditor implements IEditor, ILspEditor {
if (server != null) {
this.languageClient = server.getClient();
+ getSnippetController().setFileVariableResolver(new FileVariableResolver(this));
+ getSnippetController().setWorkspaceVariableResolver(new WorkspaceVariableResolver());
}
}
@@ -755,8 +761,8 @@ public class IDEEditor extends CodeEditor implements IEditor, ILspEditor {
new Position(end.line, end.column, end.index));
final var changedText = event.getChangedText().toString();
- final var changeEvent = new DocumentChangeEvent(file, changedText, getText().toString(), ++fileVersion, type,
- changeDelta, changeRange);
+ final var changeEvent = new DocumentChangeEvent(file, changedText, getText().toString(),
+ ++fileVersion, type, changeDelta, changeRange);
// Notify FileManager first
FileManager.INSTANCE.onDocumentContentChange(changeEvent);
@@ -819,6 +825,19 @@ public class IDEEditor extends CodeEditor implements IEditor, ILspEditor {
public void release() {
ensureWindowsDismissed();
super.release();
+ ISnippetVariableResolver resolver = getSnippetController().getFileVariableResolver();
+ if (resolver instanceof AbstractSnippetVariableResolver) {
+ ((AbstractSnippetVariableResolver) resolver).close();
+ }
+
+ resolver = getSnippetController().getWorkspaceVariableResolver();
+ if (resolver instanceof AbstractSnippetVariableResolver) {
+ ((AbstractSnippetVariableResolver) resolver).close();
+ }
+
+ getSnippetController().setFileVariableResolver(null);
+ getSnippetController().setWorkspaceVariableResolver(null);
+
if (this.actionsMenu != null) {
this.actionsMenu.destroy();
}