Skip to content

Commit

Permalink
Improve User tag snippet completion
Browse files Browse the repository at this point in the history
Fixes redhat-developer#784

Signed-off-by: azerr <azerr@redhat.com>
  • Loading branch information
angelozerr committed Feb 3, 2023
1 parent 5a1b1cf commit 6e1ced7
Show file tree
Hide file tree
Showing 11 changed files with 322 additions and 356 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,16 @@ public BinaryUserTag(UserTagInfo tagInfo) {
super(tagInfo.getFileName());
this.uri = tagInfo.getUri();
this.content = tagInfo.getContent();
super.setBody(createBody());
}

@Override
public String getUri() {
return uri;
}

@Override
public String getContent() {
return content;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,12 @@
*******************************************************************************/
package com.redhat.qute.project.tags;

import java.io.FileInputStream;
import java.io.InputStream;
import java.nio.file.Path;

import com.redhat.qute.utils.IOUtils;

/**
* Source user tag.
*
Expand All @@ -26,6 +30,7 @@ public class SourceUserTag extends UserTag {
public SourceUserTag(String fileName, Path path) {
super(fileName);
this.path = path;
super.setBody(createBody());
}

@Override
Expand All @@ -41,4 +46,15 @@ public String getUri() {
public Path getPath() {
return path;
}

@Override
public String getContent() {
try (InputStream input = new FileInputStream(path.toFile())) {
return IOUtils.convertStreamToString(input);

} catch (Exception e) {

}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,17 @@
*******************************************************************************/
package com.redhat.qute.project.tags;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;

import com.redhat.qute.ls.commons.snippets.Snippet;
import com.redhat.qute.ls.commons.snippets.SnippetsBuilder;
import com.redhat.qute.parser.template.Template;
import com.redhat.qute.parser.template.TemplateParser;
import com.redhat.qute.services.snippets.QuteSnippetContext;
import com.redhat.qute.utils.UserTagUtils;

Expand All @@ -29,17 +37,62 @@ public abstract class UserTag extends Snippet {

private final String fileName;
private final String templateId;
private Map<String, UserTagParameter> parameters;

public UserTag(String fileName) {
String name = UserTagUtils.getUserTagName(fileName);
super.setLabel(name);
super.setPrefixes(Arrays.asList(name));
super.setBody(Arrays.asList("{#" + name + " /}$0"));
super.setContext(QuteSnippetContext.IN_TEXT);
this.fileName = fileName;
this.templateId = UserTagUtils.getTemplateId(name);
}

protected List<String> createBody() {
String name = getLabel();
List<String> body = new ArrayList<>();
Collection<UserTagParameter> parameters = getParameters().values();

boolean hasNestedContent = false;
int index = 1;
StringBuilder first = new StringBuilder("{#");
first.append(name);
for (UserTagParameter parameter : parameters) {
if (parameter.isRequired()) {
switch (parameter.getPartName()) {
case UserTagUtils.IT_OBJECT_PART_NAME:
first.append(" ");
SnippetsBuilder.placeholders(index++, parameter.getPartName(), first);
break;
case UserTagUtils.NESTED_CONTENT_OBJECT_PART_NAME:
hasNestedContent = true;
break;
default:
first.append(" ");
first.append(parameter.getPartName());
first.append("=");
SnippetsBuilder.placeholders(index++, parameter.getPartName(), first);
break;
}
}
}
if (hasNestedContent) {
if (!parameters.isEmpty()) {
first.append(" ");
}
first.append("}");
} else {
first.append(" /}");
SnippetsBuilder.tabstops(0, first);
}
body.add(first.toString());
if (hasNestedContent) {
body.add("\t" + SnippetsBuilder.tabstops(index++));
body.add("{/" + name + "}" + SnippetsBuilder.tabstops(0));
}
return body;
}

/**
* Returns the user tag name.
*
Expand Down Expand Up @@ -73,4 +126,36 @@ public String getTemplateId() {
* @return the Qute template file Uri.
*/
public abstract String getUri();

/**
* Returns the content of the user tag.
*
* @return the content of the user tag.
*/
public abstract String getContent();

public Map<String, UserTagParameter> getParameters() {
if (parameters == null) {
parameters = collectParameters();
}
return parameters;
}

private Map<String, UserTagParameter> collectParameters() {
Template template = getTemplate();
if (template == null) {
return Collections.emptyMap();
}
UserTagParameterCollector collector = new UserTagParameterCollector();
template.accept(collector);
return collector.getParameters();
}

private Template getTemplate() {
String content = getContent();
if (content == null) {
return null;
}
return TemplateParser.parse(content, getFileName());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package com.redhat.qute.project.tags;

import com.redhat.qute.parser.expression.ObjectPart;

public class UserTagParameter {

private final ObjectPart part;

private boolean required;

public UserTagParameter(ObjectPart part) {
this.part = part;
}

public ObjectPart getPart() {
return part;
}

public void setRequired(Boolean required) {
this.required = required;
}

public Boolean isRequired() {
return required;
}

public String getPartName() {
return part.getPartName();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package com.redhat.qute.project.tags;

import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import com.redhat.qute.parser.expression.MethodPart;
import com.redhat.qute.parser.expression.ObjectPart;
import com.redhat.qute.parser.expression.Part;
import com.redhat.qute.parser.expression.Parts;
import com.redhat.qute.parser.expression.Parts.PartKind;
import com.redhat.qute.parser.template.ASTVisitor;
import com.redhat.qute.parser.template.Parameter;
import com.redhat.qute.parser.template.Section;
import com.redhat.qute.parser.template.sections.IfSection;
import com.redhat.qute.parser.template.sections.LetSection;
import com.redhat.qute.utils.StringUtils;

public class UserTagParameterCollector extends ASTVisitor {

private final Map<String, UserTagParameter> parameters;

private final List<List<String>> stack;

public UserTagParameterCollector() {
parameters = new LinkedHashMap<>();
stack = new ArrayList<>();
}

@Override
public boolean visit(IfSection node) {
addStack(node);
return super.visit(node);
}

public boolean visit(LetSection node) {
// addStack(node);
return super.visit(node);
}

private void addStack(Section node) {
List<String> optionalParameterNames = null;
List<Parameter> parameters = node.getParameters();
for (Parameter parameter : parameters) {
String name = parameter.getName();
if (!StringUtils.isEmpty(name) && (parameter.isOptional())) {
if (optionalParameterNames == null) {
optionalParameterNames = new ArrayList<>();
}
optionalParameterNames.add(name);
}
}
stack.add(optionalParameterNames != null ? optionalParameterNames : Collections.emptyList());
}

@Override
public void endVisit(IfSection node) {
removeStack();
super.endVisit(node);
}

@Override
public void endVisit(LetSection node) {
// removeStack();
super.endVisit(node);
}

private void removeStack() {
stack.remove(stack.size() - 1);
}

@Override
public boolean visit(ObjectPart node) {
if (node.getNamespace() == null) {
String partName = node.getPartName();
UserTagParameter parameter = parameters.get(partName);
if (parameter == null) {
parameter = new UserTagParameter(node);
parameters.put(partName, parameter);
}
if (!parameter.isRequired()) {
boolean ignore = false;
for (List<String> optionalNames : stack) {
if (optionalNames.contains(partName)) {
ignore = true;
}
}
if (!ignore) {
boolean required = false;
Parts parts = node.getParent();
int index = parts.getPartIndex(node);
if (index + 1 < parts.getChildCount()) {
Part next = parts.getChild(index + 1);
if (next != null && next.getPartKind() == PartKind.Method) {
MethodPart methodPart = (MethodPart) next;
if (!("?:".equals(methodPart.getPartName()) || "or".equals(methodPart.getPartName()))) {
required = true;
}
}
} else {
required = true;
}
parameter.setRequired(required);
}
}
}
return super.visit(node);
}

public Map<String, UserTagParameter> getParameters() {
return parameters;
}
}
Loading

0 comments on commit 6e1ced7

Please sign in to comment.