diff --git a/.intellijPlatform/coroutines-javaagent-legacy.jar b/.intellijPlatform/coroutines-javaagent-legacy.jar
index 40dce35..7bde603 100644
Binary files a/.intellijPlatform/coroutines-javaagent-legacy.jar and b/.intellijPlatform/coroutines-javaagent-legacy.jar differ
diff --git a/.intellijPlatform/self-update.lock b/.intellijPlatform/self-update.lock
index 28f6604..e5d60f1 100644
--- a/.intellijPlatform/self-update.lock
+++ b/.intellijPlatform/self-update.lock
@@ -1 +1 @@
-2026-04-18
\ No newline at end of file
+2026-04-22
\ No newline at end of file
diff --git a/build.gradle.kts b/build.gradle.kts
index c449662..c32cc6e 100644
--- a/build.gradle.kts
+++ b/build.gradle.kts
@@ -4,7 +4,7 @@ plugins {
id("org.jetbrains.intellij.platform") version "2.7.0"
}
group = "com.sdk.dynform.tools"
-version = "3.2.6"
+version = "3.2.7"
repositories {
mavenCentral()
@@ -38,18 +38,19 @@ intellijPlatform {
}
changeNotes = """
+
[3.2.7]
+
+ - Persistent Generation Context: Generator now remembers the last used directory for Action Beans and Dataset XMLs independently per project.
+ - Configurable Auto-Open: Added new settings to toggle automatic file opening after generation and customize the table limit.
+ - Enhanced Path Portability: i18n and XSD configurations now strictly use project-relative paths, ensuring settings remain valid across different environments.
+ - Refined File Navigation: Improved the File Browser to prioritize starting at the current configured directory while maintaining strict project-scope visibility.
+
[3.2.6]
- Structural Validation: Introduced a new Annotator to validate that all fields used in
<LAYOUT> and <FILTERS> are correctly defined in their respective <FIELDS> sections.
- Generator Logic Update: Refined the column width calculation for NUMBER and DATE types in the ActionBean generator for better XML compatibility.
- Improved File Opening: Switched to
FileEditorManagerEx for opening generated files, ensuring better window focus and management in recent IDE versions.
- [3.2.5]
-
- - Dataset to Form Mapping: Implemented comprehensive reference and completion support for the
FORM-NAME attribute in DATASET > FIELDS > FIELD.
- - Smart Field Resolution:
FORM-NAME now correctly resolves to hidden fields in FORM_ENTRY > FIELDS and any named fields within FORM_ENTRY > LAYOUT.
- - Recursive Form Scanning: Enhanced field discovery to scan across all form entries in the current and recursively included
.frml files.
-
[3.2.3]
- Advanced Data Referencing: Implemented comprehensive reference and completion support for
<FOREIGN-DATASETS> and <MASTER-DATA> structures.
diff --git a/src/main/java/com/sdk/dynform/tools/dynform/DynFormCompletionContributor.java b/src/main/java/com/sdk/dynform/tools/dynform/DynFormCompletionContributor.java
index 8be6fcd..98fa80a 100644
--- a/src/main/java/com/sdk/dynform/tools/dynform/DynFormCompletionContributor.java
+++ b/src/main/java/com/sdk/dynform/tools/dynform/DynFormCompletionContributor.java
@@ -2,6 +2,8 @@ package com.sdk.dynform.tools.dynform;
import com.intellij.codeInsight.completion.*;
import com.intellij.codeInsight.lookup.LookupElementBuilder;
+import com.intellij.openapi.project.Project;
+import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.patterns.PlatformPatterns;
import com.intellij.patterns.XmlPatterns;
import com.intellij.psi.*;
@@ -229,6 +231,20 @@ public class DynFormCompletionContributor extends CompletionContributor {
addFormFieldsForNameRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>());
}
});
+
+ // XML completion for INCLUDE:FILE
+ extend(CompletionType.BASIC, XmlPatterns.psiElement()
+ .inside(XmlPatterns.xmlAttributeValue()
+ .withParent(XmlPatterns.xmlAttribute().withName("FILE")
+ .withParent(XmlPatterns.xmlTag().withName("INCLUDE")))),
+ new CompletionProvider() {
+ @Override
+ protected void addCompletions(@NotNull CompletionParameters parameters,
+ @NotNull ProcessingContext context,
+ @NotNull CompletionResultSet resultSet) {
+ addFileIncludeCompletions(parameters, resultSet);
+ }
+ });
}
private void addFieldsInTagRecursive(XmlTag container, @NotNull CompletionResultSet resultSet) {
@@ -254,7 +270,7 @@ public class DynFormCompletionContributor extends CompletionContributor {
private void addDatasetsInFileRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set visited) {
if (file == null || !visited.add(file)) return;
-
+
// 1. Add datasets from current file
addDatasetsInFile(file, resultSet);
@@ -391,7 +407,7 @@ public class DynFormCompletionContributor extends CompletionContributor {
private PsiElement findDatasetInFileRecursiveForCompletion(PsiFile file, String id, Set visited) {
if (file == null || !visited.add(file)) return null;
if (!(file instanceof XmlFile xmlFile)) return null;
-
+
XmlTag rootTag = xmlFile.getRootTag();
if (rootTag == null) return null;
@@ -455,6 +471,78 @@ public class DynFormCompletionContributor extends CompletionContributor {
return null;
}
+ private void addFileIncludeCompletions(@NotNull CompletionParameters parameters, @NotNull CompletionResultSet resultSet) {
+ String value = parameters.getPosition().getText().replace(CompletionUtil.DUMMY_IDENTIFIER_TRIMMED, "");
+ PsiFile contextFile = parameters.getOriginalFile();
+ Project project = contextFile.getProject();
+
+ if (value.startsWith("#")) {
+ // Suggest files in the current module's view/frm
+ VirtualFile moduleDir = DynFormPathUtils.findModuleDir(contextFile);
+ if (moduleDir != null) {
+ VirtualFile frmDir = moduleDir.findFileByRelativePath("view/frm");
+ if (frmDir != null) {
+ addFrmlFilesRecursive(frmDir, "#", "", resultSet);
+ }
+ }
+ } else if (value.startsWith("/")) {
+ // Suggest modules or files in modules
+ String path = value.substring(1);
+ int firstSlash = path.indexOf("/");
+ if (firstSlash < 0) {
+ // Suggest modules
+ List modules = DynFormPathUtils.getAllModules(project);
+ for (String module : modules) {
+ resultSet.addElement(LookupElementBuilder.create("/" + module + "/")
+ .withIcon(com.intellij.icons.AllIcons.Nodes.Module)
+ .withPresentableText("/" + module));
+ }
+ } else {
+ // Suggest files in the selected module
+ String moduleName = path.substring(0, firstSlash);
+ VirtualFile moduleBase = DynFormPathUtils.getModuleBaseDir(project);
+ if (moduleBase != null) {
+ VirtualFile frmDir = moduleBase.findFileByRelativePath(moduleName + "/view/frm");
+ if (frmDir != null) {
+ addFrmlFilesRecursive(frmDir, "/" + moduleName + "/", "", resultSet);
+ }
+ }
+ }
+ } else {
+ // Suggest relative files (basic implementation: current directory)
+ VirtualFile currentDir = contextFile.getVirtualFile().getParent();
+ if (currentDir != null) {
+ for (VirtualFile child : currentDir.getChildren()) {
+ if (child.isDirectory()) {
+ resultSet.addElement(LookupElementBuilder.create(child.getName() + "/")
+ .withIcon(com.intellij.icons.AllIcons.Nodes.Folder));
+ } else if (child.getName().endsWith(".frml")) {
+ resultSet.addElement(LookupElementBuilder.create(child.getName())
+ .withIcon(com.intellij.icons.AllIcons.FileTypes.Xml));
+ }
+ }
+ }
+ // Also suggest starting with # or /
+ resultSet.addElement(LookupElementBuilder.create("#")
+ .withTailText(" (Current Module)"));
+ resultSet.addElement(LookupElementBuilder.create("/")
+ .withTailText(" (Cross Module)"));
+ }
+ }
+
+ private void addFrmlFilesRecursive(VirtualFile dir, String prefix, String subPath, @NotNull CompletionResultSet resultSet) {
+ for (VirtualFile child : dir.getChildren()) {
+ String currentSubPath = subPath.isEmpty() ? child.getName() : subPath + "/" + child.getName();
+ if (child.isDirectory()) {
+ addFrmlFilesRecursive(child, prefix, currentSubPath, resultSet);
+ } else if (child.getName().endsWith(".frml")) {
+ resultSet.addElement(LookupElementBuilder.create(prefix + currentSubPath)
+ .withIcon(com.intellij.icons.AllIcons.FileTypes.Xml)
+ .withPresentableText(currentSubPath));
+ }
+ }
+ }
+
private void addFormFieldsForNameRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set visited) {
if (file == null || !visited.add(file)) return;
if (!(file instanceof XmlFile xmlFile)) return;
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index 00656df..404dd0b 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -34,18 +34,19 @@
]]>
[3.2.7]
+
+ - Persistent Generation Context: Generator now remembers the last used directory for Action Beans and Dataset XMLs independently per project.
+ - Configurable Auto-Open: Added new settings to toggle automatic file opening after generation and customize the table limit.
+ - Enhanced Path Portability: i18n and XSD configurations now strictly use project-relative paths, ensuring settings remain valid across different environments.
+ - Refined File Navigation: Improved the File Browser to prioritize starting at the current configured directory while maintaining strict project-scope visibility.
+
[3.2.6]
- Structural Validation: Introduced a new Annotator to validate that all fields used in
<LAYOUT> and <FILTERS> are correctly defined in their respective <FIELDS> sections.
- Generator Logic Update: Refined the column width calculation for NUMBER and DATE types in the ActionBean generator for better XML compatibility.
- Improved File Opening: Switched to
FileEditorManagerEx for opening generated files, ensuring better window focus and management in recent IDE versions.
- [3.2.5]
-
- - Dataset to Form Mapping: Implemented comprehensive reference and completion support for the
FORM-NAME attribute in DATASET > FIELDS > FIELD.
- - Smart Field Resolution:
FORM-NAME now correctly resolves to hidden fields in FORM_ENTRY > FIELDS and any named fields within FORM_ENTRY > LAYOUT.
- - Recursive Form Scanning: Enhanced field discovery to scan across all form entries in the current and recursively included
.frml files.
-
[3.2.4]
- Persistent Generation Directories: Generator now remembers the last used directory for Action Beans and Dataset XMLs independently per project.