feat(dynform): reference and completion for FORM-NAME attribute
- Added comprehensive reference and completion support for FORM-NAME in DATASET > FIELDS > FIELD. - Implemented smart field resolution to target hidden fields in FORM_ENTRY > FIELDS and named fields in FORM_ENTRY > LAYOUT. - Enhanced form scanning to recursively discover fields across all included .frml files. - Bumped plugin version to 3.2.5.
This commit is contained in:
@@ -4,7 +4,7 @@ plugins {
|
|||||||
id("org.jetbrains.intellij.platform") version "2.7.0"
|
id("org.jetbrains.intellij.platform") version "2.7.0"
|
||||||
}
|
}
|
||||||
group = "com.sdk.dynform.tools"
|
group = "com.sdk.dynform.tools"
|
||||||
version = "3.2.4"
|
version = "3.2.5"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
@@ -38,6 +38,12 @@ intellijPlatform {
|
|||||||
}
|
}
|
||||||
|
|
||||||
changeNotes = """
|
changeNotes = """
|
||||||
|
<h2>[3.2.5]</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Dataset to Form Mapping:</strong> Implemented comprehensive reference and completion support for the <code>FORM-NAME</code> attribute in <code>DATASET > FIELDS > FIELD</code>.</li>
|
||||||
|
<li><strong>Smart Field Resolution:</strong> <code>FORM-NAME</code> now correctly resolves to hidden fields in <code>FORM_ENTRY > FIELDS</code> and any named fields within <code>FORM_ENTRY > LAYOUT</code>.</li>
|
||||||
|
<li><strong>Recursive Form Scanning:</strong> Enhanced field discovery to scan across all form entries in the current and recursively included <code>.frml</code> files.</li>
|
||||||
|
</ul>
|
||||||
<h2>[3.2.4]</h2>
|
<h2>[3.2.4]</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>Persistent Generation Directories:</strong> Generator now remembers the last used directory for Action Beans and Dataset XMLs independently per project.</li>
|
<li><strong>Persistent Generation Directories:</strong> Generator now remembers the last used directory for Action Beans and Dataset XMLs independently per project.</li>
|
||||||
|
|||||||
@@ -213,6 +213,22 @@ public class DynFormCompletionContributor extends CompletionContributor {
|
|||||||
addGridsInFileRecursive(parameters.getOriginalFile(), resultSet, new HashSet<>());
|
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<CompletionParameters>() {
|
||||||
|
@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) {
|
private void addFieldsInTagRecursive(XmlTag container, @NotNull CompletionResultSet resultSet) {
|
||||||
@@ -438,4 +454,60 @@ public class DynFormCompletionContributor extends CompletionContributor {
|
|||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void addFormFieldsForNameRecursive(PsiFile file, @NotNull CompletionResultSet resultSet, Set<PsiFile> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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
|
// XML Reference for SRC in UPDATE-FIELDS
|
||||||
registrar.registerReferenceProvider(XmlPatterns.xmlAttributeValue()
|
registrar.registerReferenceProvider(XmlPatterns.xmlAttributeValue()
|
||||||
.withParent(XmlPatterns.xmlAttribute().withName("SRC")
|
.withParent(XmlPatterns.xmlAttribute().withName("SRC")
|
||||||
@@ -662,4 +679,63 @@ public class DynFormReferenceContributor extends PsiReferenceContributor {
|
|||||||
return DynFormPathUtils.findIncludedFile(myElement.getContainingFile(), path);
|
return DynFormPathUtils.findIncludedFile(myElement.getContainingFile(), path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static class DynFormFormNameReference extends PsiReferenceBase<XmlAttributeValue> {
|
||||||
|
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<PsiFile> 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -34,6 +34,12 @@
|
|||||||
]]></description>
|
]]></description>
|
||||||
|
|
||||||
<change-notes><![CDATA[
|
<change-notes><![CDATA[
|
||||||
|
<h2>[3.2.5]</h2>
|
||||||
|
<ul>
|
||||||
|
<li><strong>Dataset to Form Mapping:</strong> Implemented comprehensive reference and completion support for the <code>FORM-NAME</code> attribute in <code>DATASET > FIELDS > FIELD</code>.</li>
|
||||||
|
<li><strong>Smart Field Resolution:</strong> <code>FORM-NAME</code> now correctly resolves to hidden fields in <code>FORM_ENTRY > FIELDS</code> and any named fields within <code>FORM_ENTRY > LAYOUT</code>.</li>
|
||||||
|
<li><strong>Recursive Form Scanning:</strong> Enhanced field discovery to scan across all form entries in the current and recursively included <code>.frml</code> files.</li>
|
||||||
|
</ul>
|
||||||
<h2>[3.2.4]</h2>
|
<h2>[3.2.4]</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><strong>Persistent Generation Directories:</strong> Generator now remembers the last used directory for Action Beans and Dataset XMLs independently per project.</li>
|
<li><strong>Persistent Generation Directories:</strong> Generator now remembers the last used directory for Action Beans and Dataset XMLs independently per project.</li>
|
||||||
|
|||||||
Reference in New Issue
Block a user