diff --git a/build.gradle.kts b/build.gradle.kts
index b4f7fa8..4a3a58e 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.4"
+version = "3.2.5"
repositories {
mavenCentral()
@@ -38,6 +38,12 @@ intellijPlatform {
}
changeNotes = """
+
[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.
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 38e10ed..8be6fcd 100644
--- a/src/main/java/com/sdk/dynform/tools/dynform/DynFormCompletionContributor.java
+++ b/src/main/java/com/sdk/dynform/tools/dynform/DynFormCompletionContributor.java
@@ -213,6 +213,22 @@ public class DynFormCompletionContributor extends CompletionContributor {
addGridsInFileRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>());
}
});
+
+ // XML completion for FORM-NAME in DATASET > FIELDS > FIELD
+ extend(CompletionType.BASIC, XmlPatterns.psiElement()
+ .inside(XmlPatterns.xmlAttributeValue()
+ .withParent(XmlPatterns.xmlAttribute().withName("FORM-NAME")
+ .withParent(XmlPatterns.xmlTag().withName("FIELD")
+ .withParent(XmlPatterns.xmlTag().withName("FIELDS")
+ .withParent(XmlPatterns.xmlTag().withName("DATASET")))))),
+ new CompletionProvider() {
+ @Override
+ protected void addCompletions(@NotNull CompletionParameters parameters,
+ @NotNull ProcessingContext context,
+ @NotNull CompletionResultSet resultSet) {
+ addFormFieldsForNameRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>());
+ }
+ });
}
private void addFieldsInTagRecursive(XmlTag container, @NotNull CompletionResultSet resultSet) {
@@ -438,4 +454,60 @@ public class DynFormCompletionContributor extends CompletionContributor {
}
return null;
}
+
+ private void addFormFieldsForNameRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set visited) {
+ if (file == null || !visited.add(file)) return;
+ if (!(file instanceof XmlFile xmlFile)) return;
+ XmlTag rootTag = xmlFile.getRootTag();
+ if (rootTag == null) return;
+
+ // 1. Search in current file FORM_ENTRY tags
+ for (XmlTag formTag : rootTag.findSubTags("FORM")) {
+ for (XmlTag entryTag : formTag.findSubTags("FORM_ENTRY")) {
+ // Collect hidden fields from FIELDS
+ XmlTag fieldsTag = entryTag.findFirstSubTag("FIELDS");
+ if (fieldsTag != null) {
+ for (XmlTag fieldTag : fieldsTag.findSubTags("FIELD")) {
+ if ("HIDDEN".equals(fieldTag.getAttributeValue("INPUTTYPE"))) {
+ String name = fieldTag.getAttributeValue("NAME");
+ if (name != null && !name.isEmpty()) {
+ resultSet.addElement(LookupElementBuilder.create(name)
+ .withIcon(com.intellij.icons.AllIcons.Nodes.Field)
+ .withTypeText("Hidden Field"));
+ }
+ }
+ }
+ }
+ // Collect any field/tag with NAME from LAYOUT
+ XmlTag layoutTag = entryTag.findFirstSubTag("LAYOUT");
+ if (layoutTag != null) {
+ addFieldsInLayoutRecursive(layoutTag, resultSet);
+ }
+ }
+ }
+
+ // 2. Search in included files
+ XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
+ if (includesTag != null) {
+ for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
+ String path = includeTag.getAttributeValue("FILE");
+ if (path != null) {
+ PsiFile includedFile = DynFormPathUtils.findIncludedFile(file, path);
+ addFormFieldsForNameRecursive(includedFile, resultSet, visited);
+ }
+ }
+ }
+ }
+
+ private void addFieldsInLayoutRecursive(XmlTag container, @NotNull CompletionResultSet resultSet) {
+ for (XmlTag subTag : container.getSubTags()) {
+ String name = subTag.getAttributeValue("NAME");
+ if (name != null && !name.isEmpty()) {
+ resultSet.addElement(LookupElementBuilder.create(name)
+ .withIcon(com.intellij.icons.AllIcons.Nodes.Field)
+ .withTypeText("Layout: " + subTag.getName()));
+ }
+ addFieldsInLayoutRecursive(subTag, resultSet);
+ }
+ }
}
diff --git a/src/main/java/com/sdk/dynform/tools/dynform/DynFormReferenceContributor.java b/src/main/java/com/sdk/dynform/tools/dynform/DynFormReferenceContributor.java
index 350be4a..586bce1 100644
--- a/src/main/java/com/sdk/dynform/tools/dynform/DynFormReferenceContributor.java
+++ b/src/main/java/com/sdk/dynform/tools/dynform/DynFormReferenceContributor.java
@@ -146,6 +146,23 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
}
});
+ // XML Reference for FORM-NAME in DATASET > FIELDS > FIELD
+ registrar.registerReferenceProvider(XmlPatterns.xmlAttributeValue()
+ .withParent(XmlPatterns.xmlAttribute().withName("FORM-NAME")
+ .withParent(XmlPatterns.xmlTag().withName("FIELD")
+ .withParent(XmlPatterns.xmlTag().withName("FIELDS")
+ .withParent(XmlPatterns.xmlTag().withName("DATASET"))))),
+ new PsiReferenceProvider() {
+ @NotNull
+ @Override
+ public PsiReference @NotNull [] getReferencesByElement(@NotNull PsiElement element, @NotNull ProcessingContext context) {
+ XmlAttributeValue attrValue = (XmlAttributeValue) element;
+ String value = attrValue.getValue();
+ if (value == null || value.isEmpty()) return PsiReference.EMPTY_ARRAY;
+ return new PsiReference[]{new DynFormFormNameReference(attrValue, new TextRange(1, value.length() + 1), value)};
+ }
+ });
+
// XML Reference for SRC in UPDATE-FIELDS
registrar.registerReferenceProvider(XmlPatterns.xmlAttributeValue()
.withParent(XmlPatterns.xmlAttribute().withName("SRC")
@@ -662,4 +679,63 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
return DynFormPathUtils.findIncludedFile(myElement.getContainingFile(), path);
}
}
+
+ private static class DynFormFormNameReference extends PsiReferenceBase {
+ private final String fieldName;
+
+ public DynFormFormNameReference(@NotNull XmlAttributeValue element, TextRange range, String fieldName) {
+ super(element, range, true);
+ this.fieldName = fieldName;
+ }
+
+ @Nullable
+ @Override
+ public PsiElement resolve() {
+ return findFieldInFormEntriesRecursive(myElement.getContainingFile(), fieldName, new HashSet<>());
+ }
+
+ @Nullable
+ private PsiElement findFieldInFormEntriesRecursive(PsiFile file, String name, 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;
+
+ // 1. Search in current file FORM_ENTRY tags
+ for (XmlTag formTag : rootTag.findSubTags("FORM")) {
+ for (XmlTag entryTag : formTag.findSubTags("FORM_ENTRY")) {
+ // Check hidden fields in FIELDS
+ XmlTag fieldsTag = entryTag.findFirstSubTag("FIELDS");
+ if (fieldsTag != null) {
+ for (XmlTag fieldTag : fieldsTag.findSubTags("FIELD")) {
+ if ("HIDDEN".equals(fieldTag.getAttributeValue("INPUTTYPE")) && name.equals(fieldTag.getAttributeValue("NAME"))) {
+ XmlAttribute nameAttr = fieldTag.getAttribute("NAME");
+ return nameAttr != null ? nameAttr.getValueElement() : fieldTag;
+ }
+ }
+ }
+ // Check fields in LAYOUT
+ XmlTag layoutTag = entryTag.findFirstSubTag("LAYOUT");
+ if (layoutTag != null) {
+ PsiElement found = findFieldInTag(layoutTag, name);
+ if (found != null) return found;
+ }
+ }
+ }
+
+ // 2. Search in included files
+ XmlTag includesTag = rootTag.findFirstSubTag("INCLUDES");
+ if (includesTag != null) {
+ for (XmlTag includeTag : includesTag.findSubTags("INCLUDE")) {
+ String path = includeTag.getAttributeValue("FILE");
+ if (path != null) {
+ PsiFile includedFile = DynFormPathUtils.findIncludedFile(file, path);
+ PsiElement found = findFieldInFormEntriesRecursive(includedFile, name, visited);
+ if (found != null) return found;
+ }
+ }
+ }
+ return null;
+ }
+ }
}
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index bb7a94c..333f669 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -34,6 +34,12 @@
]]>
[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.