Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Qute CodeAction(s) for similar text suggestions for UnknownProperty. #713

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,16 @@
import static com.redhat.qute.utils.StringUtils.isSimilar;

import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;

import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.Diagnostic;
import org.eclipse.lsp4j.Range;

import com.redhat.qute.commons.ResolvedJavaTypeInfo;
import com.redhat.qute.ls.commons.CodeActionFactory;
import com.redhat.qute.ls.commons.client.ConfigurationItemEdit;
import com.redhat.qute.ls.commons.client.ConfigurationItemEditType;
Expand All @@ -32,6 +33,8 @@
import com.redhat.qute.project.datamodel.JavaDataModelCache;
import com.redhat.qute.services.commands.QuteClientCommandConstants;
import com.redhat.qute.services.diagnostics.QuteErrorCode;
import com.redhat.qute.services.nativemode.JavaTypeAccessibiltyRule;
import com.redhat.qute.services.nativemode.JavaTypeFilter;
import com.redhat.qute.settings.QuteValidationSettings.Severity;
import com.redhat.qute.utils.QutePositionUtility;

Expand All @@ -54,29 +57,24 @@ public AbstractQuteCodeAction(JavaDataModelCache javaCache) {
}

/**
* Generate code action(s) for similar values (Did you mean ...?)
* Generate code action for similar value (Did you mean ...?)
*
* @param part the part node.
* @param availableValues the available values.
* @param template the Qute template.
* @param diagnostic the diagnostic.
* @param codeActions list of CodeActions.
* @param part the part node.
* @param value the value.
* @param template the Qute template.
* @param existingProperties the existing properties.
* @param diagnostic the diagnostic.
* @param codeActions list of CodeActions.
*/
protected void doCodeActionsForSimilarValues(Part part, Collection<String> availableValues, Template template,
Diagnostic diagnostic, List<CodeAction> codeActions) {
if (availableValues.isEmpty()) {
return;
}

Range rangeValue = QutePositionUtility.createRange(part);
protected void doCodeActionsForSimilarValue(Part part, String value, Template template,
datho7561 marked this conversation as resolved.
Show resolved Hide resolved
Set<String> existingProperties, Diagnostic diagnostic, List<CodeAction> codeActions) {
String partName = part.getPartName();
for (String value : availableValues) {
if (isSimilar(value, partName)) {
CodeAction similarCodeAction = CodeActionFactory.replace(
MessageFormat.format(DID_YOU_MEAN_TITLE, value), rangeValue, value, template.getTextDocument(),
diagnostic);
codeActions.add(similarCodeAction);
}
if (!existingProperties.contains(value) && isSimilar(value, partName)) {
Range rangeValue = QutePositionUtility.createRange(part);
CodeAction similarCodeAction = CodeActionFactory.replace(MessageFormat.format(DID_YOU_MEAN_TITLE, value),
rangeValue, value, template.getTextDocument(), diagnostic);
codeActions.add(similarCodeAction);
existingProperties.add(value);
}
}

Expand Down Expand Up @@ -117,6 +115,11 @@ public static CodeAction createConfigurationUpdateCodeAction(String title, Strin
Collections.singletonList(configItemEdit), diagnostics);
}

protected static boolean isIgnoreSuperclasses(ResolvedJavaTypeInfo baseType, JavaTypeAccessibiltyRule rule,
JavaTypeFilter filter) {
return filter != null && rule != null && filter.isIgnoreSuperclasses(baseType, rule);
}

/**
* Create code actions.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@
*******************************************************************************/
package com.redhat.qute.services.codeactions;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -60,23 +60,21 @@ public void doCodeActions(CodeActionRequest request, List<CompletableFuture<Void
doCodeActionsForSimilarValues(part, template, diagnostic, codeActions);

// CodeAction to set validation severity to ignore
doCodeActionToSetIgnoreSeverity(template, diagnostic,
QuteErrorCode.UndefinedNamespace, codeActions, UNDEFINED_NAMESPACE_SEVERITY_SETTING);
doCodeActionToSetIgnoreSeverity(template, diagnostic, QuteErrorCode.UndefinedNamespace, codeActions,
UNDEFINED_NAMESPACE_SEVERITY_SETTING);

} catch (BadLocationException e) {
LOGGER.log(Level.SEVERE, "Creation of undefined namespace code action failed", e);
}
}

private void doCodeActionsForSimilarValues(NamespacePart part, Template template, Diagnostic diagnostic,
List<CodeAction> codeActions) throws BadLocationException {
Collection<String> availableValues = collectAvailableValuesForNamespacePart(part, template);
doCodeActionsForSimilarValues(part, availableValues, template, diagnostic, codeActions);
}

private Collection<String> collectAvailableValuesForNamespacePart(NamespacePart node, Template template) {
String projectUri = template.getProjectUri();
return javaCache.getAllNamespaces(projectUri);
Set<String> existingProperties = new HashSet<>();
for (String namespace : javaCache.getAllNamespaces(projectUri)) {
doCodeActionsForSimilarValue(part, namespace, template, existingProperties, diagnostic, codeActions);
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@

import java.text.MessageFormat;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.logging.Level;
import java.util.logging.Logger;
Expand Down Expand Up @@ -88,8 +88,8 @@ public void doCodeActions(CodeActionRequest request, List<CompletableFuture<Void
doCodeActionToAddOptionalSuffix(template, diagnostic, codeActions);

// CodeAction to set validation severity to ignore
doCodeActionToSetIgnoreSeverity(template, diagnostic,
QuteErrorCode.UndefinedObject, codeActions, UNDEFINED_OBJECT_SEVERITY_SETTING);
doCodeActionToSetIgnoreSeverity(template, diagnostic, QuteErrorCode.UndefinedObject, codeActions,
UNDEFINED_OBJECT_SEVERITY_SETTING);

} catch (BadLocationException e) {
LOGGER.log(Level.SEVERE, "Creation of undefined object code action failed", e);
Expand All @@ -100,36 +100,10 @@ public void doCodeActions(CodeActionRequest request, List<CompletableFuture<Void
private void doCodeActionsForSimilarValues(ObjectPart part, Template template, Diagnostic diagnostic,
List<CodeAction> codeActions) throws BadLocationException {
int offset = template.offsetAt(diagnostic.getRange().getStart());
Collection<String> availableValues = collectAvailableValuesForObjectPart(part, template, offset);
super.doCodeActionsForSimilarValues(part, availableValues, template, diagnostic, codeActions);
}

private Collection<String> collectAvailableValuesForObjectPart(Node node, Template template, int offset) {
Collection<String> availableValues = new HashSet<>();
String projectUri = template.getProjectUri();
Set<String> existingProperties = new HashSet<>();

List<ValueResolver> globalResolvers = javaCache.getGlobalVariables(projectUri);
for (ValueResolver resolver : globalResolvers) {
availableValues.add(resolver.getName());
}

List<String> aliases = template.getChildren().stream() //
.filter(n -> n.getKind() == NodeKind.ParameterDeclaration) //
.map(n -> ((ParameterDeclaration) n).getAlias()) //
.filter(alias -> alias != null) //
.collect(Collectors.toList());
for (String alias : aliases) {
availableValues.add(alias);
}

ExtendedDataModelTemplate dataModel = javaCache.getDataModelTemplate(template).getNow(null);
if (dataModel != null) {
for (ExtendedDataModelParameter parameter : dataModel.getParameters()) {
availableValues.add(parameter.getKey());
}
}

Section section = node != null ? node.getParentSection() : null;
Section section = part != null ? part.getParentSection() : null;
if (section != null) {
if (section.getKind() == NodeKind.Section) {
boolean collect = true;
Expand All @@ -139,38 +113,34 @@ private Collection<String> collectAvailableValuesForObjectPart(Node node, Templa
// Completion is triggered after a #else inside a #for, we don't provide
// completion for metadata or aliases
collect = false;
} else {
// Completion for iterable section like #each, #for
String alias = iterableSection.getAlias();
if (!StringUtils.isEmpty(alias)) {
doCodeActionsForSimilarValue(part, alias, template, existingProperties, diagnostic,
codeActions);
}
}
}
if (collect) {
List<SectionMetadata> metadatas = section.getMetadata();
for (SectionMetadata metadata : metadatas) {
availableValues.add(metadata.getName());
doCodeActionsForSimilarValue(part, metadata.getName(), template, existingProperties, diagnostic,
codeActions);
}
}
}

switch (section.getSectionKind()) {
case EACH:
case FOR:
LoopSection iterableSection = ((LoopSection) section);
// Completion for iterable section like #each, #for
String alias = iterableSection.getAlias();
if (!StringUtils.isEmpty(alias)) {
if (!availableValues.contains(alias)) {
availableValues.add(alias);
}
}
break;
case LET:
case SET: {
// completion for parameters coming from #let, #set
List<Parameter> parameters = section.getParameters();
if (parameters != null) {
for (Parameter parameter : parameters) {
String parameterName = parameter.getName();
if (!availableValues.contains(parameterName)) {
availableValues.add(parameterName);
}
doCodeActionsForSimilarValue(part, parameterName, template, existingProperties, diagnostic,
codeActions);
}
}
break;
Expand All @@ -183,9 +153,8 @@ private Collection<String> collectAvailableValuesForObjectPart(Node node, Templa
if (parameter.isOptional()) {
// {#if foo??}
String parameterName = parameter.getName();
if (!availableValues.contains(parameterName)) {
availableValues.add(parameterName);
}
doCodeActionsForSimilarValue(part, parameterName, template, existingProperties, diagnostic,
codeActions);
}
}
}
Expand All @@ -195,17 +164,37 @@ private Collection<String> collectAvailableValuesForObjectPart(Node node, Templa
}
}

List<ValueResolver> globalResolvers = javaCache.getGlobalVariables(projectUri);
for (ValueResolver resolver : globalResolvers) {
doCodeActionsForSimilarValue(part, resolver.getName(), template, existingProperties, diagnostic,
codeActions);
}

List<String> aliases = template.getChildren().stream() //
.filter(n -> n.getKind() == NodeKind.ParameterDeclaration) //
.map(n -> ((ParameterDeclaration) n).getAlias()) //
.filter(alias -> alias != null) //
.collect(Collectors.toList());
for (String alias : aliases) {
doCodeActionsForSimilarValue(part, alias, template, existingProperties, diagnostic, codeActions);
}

ExtendedDataModelTemplate dataModel = javaCache.getDataModelTemplate(template).getNow(null);
if (dataModel != null) {
for (ExtendedDataModelParameter parameter : dataModel.getParameters()) {
doCodeActionsForSimilarValue(part, parameter.getKey(), template, existingProperties, diagnostic,
codeActions);
}
}

if (UserTagUtils.isUserTag(template)) {
Collection<SectionMetadata> specialKeysMetadatas = UserTagUtils.getSpecialKeys();
for (SectionMetadata metadata : specialKeysMetadatas) {
String name = metadata.getName();
if (!availableValues.contains(name)) {
availableValues.add(name);
}
doCodeActionsForSimilarValue(part, name, template, existingProperties, diagnostic, codeActions);
}
}

return availableValues;
}

private static void doCodeActionToInsertParameterDeclaration(ObjectPart part, Template template,
Expand Down
Loading