Skip to content

Commit c757aaf

Browse files
committed
Code action for undefined section tag
Signed-off-by: azerr <azerr@redhat.com>
1 parent 70e6df1 commit c757aaf

18 files changed

+192
-22
lines changed

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/QuteLanguageServer.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.concurrent.TimeUnit;
2222
import java.util.logging.Logger;
2323

24+
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
2425
import org.eclipse.lsp4j.InitializeParams;
2526
import org.eclipse.lsp4j.InitializeResult;
2627
import org.eclipse.lsp4j.InitializedParams;
@@ -256,4 +257,8 @@ public CompletableFuture<DataModelProject<DataModelTemplate<DataModelParameter>>
256257
public CompletableFuture<List<UserTagInfo>> getUserTags(QuteUserTagParams params) {
257258
return getLanguageClient().getUserTags(params);
258259
}
260+
261+
public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
262+
textDocumentService.didChangeWatchedFiles(params);
263+
}
259264
}

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/QuteTextDocumentService.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.eclipse.lsp4j.CompletionParams;
2626
import org.eclipse.lsp4j.DefinitionParams;
2727
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
28+
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
2829
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
2930
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
3031
import org.eclipse.lsp4j.DidSaveTextDocumentParams;
@@ -268,4 +269,8 @@ public void dataModelChanged(JavaDataModelChangeEvent event) {
268269
public void validationSettingsChanged() {
269270
templateFileTextDocumentService.validationSettingsChanged();
270271
}
272+
273+
public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
274+
templateFileTextDocumentService.didChangeWatchedFiles(params);
275+
}
271276
}

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/QuteWorkspaceService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ public void didChangeConfiguration(DidChangeConfigurationParams params) {
5656

5757
@Override
5858
public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
59-
59+
quteLanguageServer.didChangeWatchedFiles(params);
6060
}
6161

6262
@Override

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/ls/template/TemplateFileTextDocumentService.java

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
import org.eclipse.lsp4j.DefinitionParams;
3131
import org.eclipse.lsp4j.Diagnostic;
3232
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
33+
import org.eclipse.lsp4j.DidChangeWatchedFilesParams;
3334
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
3435
import org.eclipse.lsp4j.DidOpenTextDocumentParams;
3536
import org.eclipse.lsp4j.DidSaveTextDocumentParams;
@@ -361,4 +362,11 @@ public void dataModelChanged(JavaDataModelChangeEvent event) {
361362
});
362363
}
363364

365+
public void didChangeWatchedFiles(DidChangeWatchedFilesParams params) {
366+
// trigger validation for all opened Qute template files
367+
documents.all().stream().forEach(document -> {
368+
triggerValidationFor((QuteTextDocument) document);
369+
});
370+
}
371+
364372
}

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/QuteProject.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -294,4 +294,13 @@ public void collectUserTagSuggestions(CompletionRequest completionRequest, Strin
294294
CompletionList list) {
295295
tagRegistry.collectUserTagSuggestions(completionRequest, prefixFilter, suffixToFind, list);
296296
}
297+
298+
/**
299+
* Returns the src/main/resources/templates/tags directory.
300+
*
301+
* @return the src/main/resources/templates/tags directory.
302+
*/
303+
public Path getTagsDir() {
304+
return tagRegistry.getTagsDir();
305+
}
297306
}

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/project/tags/UserTagRegistry.java

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
import com.redhat.qute.commons.usertags.UserTagInfo;
2424
import com.redhat.qute.ls.api.QuteUserTagProvider;
2525
import com.redhat.qute.services.completions.CompletionRequest;
26+
import com.redhat.qute.utils.UserTagUtils;
2627

2728
/**
2829
* User tag (from source and binary) registry.
@@ -34,8 +35,6 @@
3435
*/
3536
public class UserTagRegistry {
3637

37-
private static final String TAGS_DIR_NAME = "tags";
38-
3938
private final String projectUri;
4039

4140
private final Path tagsDir;
@@ -49,7 +48,7 @@ public class UserTagRegistry {
4948

5049
public UserTagRegistry(String projectUri, Path templateBaseDir, QuteUserTagProvider userTagProvider) {
5150
this.projectUri = projectUri;
52-
this.tagsDir = templateBaseDir.resolve(TAGS_DIR_NAME);
51+
this.tagsDir = templateBaseDir.resolve(UserTagUtils.TAGS_DIR);
5352
this.userTagProvider = userTagProvider;
5453
this.completionsSourceUserTag = new QuteCompletionsForSourceUserTagSection();
5554
this.completionsBinaryUserTag = new QuteCompletionsForBinaryUserTagSection();
@@ -70,7 +69,7 @@ public Collection<UserTag> getSourceUserTags() {
7069
*/
7170
private void refresh() {
7271
// Loop for files from src/main/resources/tags to update list of user tags.
73-
completionsSourceUserTag.refresh(tagsDir);
72+
completionsSourceUserTag.refresh(getTagsDir());
7473
// Update from the 'templates.tags' entries of JARs of the classpath
7574
completionsBinaryUserTag.refresh(getBinaryUserTags());
7675
}
@@ -128,4 +127,12 @@ protected CompletableFuture<List<UserTagInfo>> getBinaryUserTags(QuteUserTagPara
128127
return userTagProvider.getUserTags(params);
129128
}
130129

130+
/**
131+
* Returns the src/main/resources/templates/tags directory.
132+
*
133+
* @return the src/main/resources/templates/tags directory.
134+
*/
135+
public Path getTagsDir() {
136+
return tagsDir;
137+
}
131138
}

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteCodeActions.java

Lines changed: 72 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,15 @@
1414
import static com.redhat.qute.ls.commons.CodeActionFactory.createCommand;
1515
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_ITERABLE;
1616
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_NAME;
17+
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_TAG;
1718

1819
import java.text.MessageFormat;
1920
import java.util.ArrayList;
2021
import java.util.Collections;
2122
import java.util.List;
2223
import java.util.concurrent.CompletableFuture;
24+
import java.util.logging.Level;
25+
import java.util.logging.Logger;
2326

2427
import org.eclipse.lsp4j.CodeAction;
2528
import org.eclipse.lsp4j.CodeActionContext;
@@ -37,7 +40,9 @@
3740
import com.redhat.qute.parser.template.Expression;
3841
import com.redhat.qute.parser.template.Node;
3942
import com.redhat.qute.parser.template.NodeKind;
43+
import com.redhat.qute.parser.template.Section;
4044
import com.redhat.qute.parser.template.Template;
45+
import com.redhat.qute.project.QuteProject;
4146
import com.redhat.qute.services.commands.QuteClientCommandConstants;
4247
import com.redhat.qute.services.diagnostics.QuteErrorCode;
4348
import com.redhat.qute.settings.SharedSettings;
@@ -51,7 +56,11 @@
5156
*/
5257
class QuteCodeActions {
5358

54-
private static final String DECLARE_UNDEFINED_VARIABLE_TITLE = "Declare `{0}` with parameter declaration.";
59+
private static final Logger LOGGER = Logger.getLogger(QuteCodeActions.class.getName());
60+
61+
private static final String UNDEFINED_VARIABLE_CODEACTION_TITLE = "Declare `{0}` with parameter declaration.";
62+
63+
private static final String UNDEFINED_SECTION_TAG_CODEACTION_TITLE = "Create the user tag file `{0}`.";
5564

5665
// Enable/Disable Qute validation
5766

@@ -79,21 +88,37 @@ public CompletableFuture<List<CodeAction>> doCodeActions(Template template, Code
7988
doCodeActionToDisableValidation(template, diagnostics, codeActions);
8089
}
8190
for (Diagnostic diagnostic : diagnostics) {
82-
if (QuteErrorCode.UndefinedVariable.isQuteErrorCode(diagnostic.getCode())) {
83-
// The following Qute template:
84-
// {undefinedVariable}
85-
//
86-
// will provide a quickfix like:
87-
//
88-
// Declare `undefinedVariable` with parameter declaration."
89-
doCodeActionsForUndefinedVariable(template, diagnostic, codeActions);
91+
QuteErrorCode errorCode = QuteErrorCode.getErrorCode(diagnostic.getCode());
92+
if (errorCode != null) {
93+
switch (errorCode) {
94+
case UndefinedVariable:
95+
// The following Qute template:
96+
// {undefinedVariable}
97+
//
98+
// will provide a quickfix like:
99+
//
100+
// Declare `undefinedVariable` with parameter declaration."
101+
doCodeActionsForUndefinedVariable(template, diagnostic, codeActions);
102+
break;
103+
case UndefinedSectionTag:
104+
// The following Qute template:
105+
// {#undefinedTag }
106+
//
107+
// will provide a quickfix like:
108+
//
109+
// Create `undefinedTag`"
110+
doCodeActionsForUndefinedSectionTag(template, diagnostic, codeActions);
111+
break;
112+
default:
113+
break;
114+
}
90115
}
91116
}
92117
}
93118
return CompletableFuture.completedFuture(codeActions);
94119
}
95120

96-
private void doCodeActionsForUndefinedVariable(Template template, Diagnostic diagnostic,
121+
private static void doCodeActionsForUndefinedVariable(Template template, Diagnostic diagnostic,
97122
List<CodeAction> codeActions) {
98123
try {
99124
String varName = null;
@@ -119,7 +144,7 @@ private void doCodeActionsForUndefinedVariable(Template template, Diagnostic dia
119144
TextDocument document = template.getTextDocument();
120145
String lineDelimiter = document.lineDelimiter(0);
121146

122-
String title = MessageFormat.format(DECLARE_UNDEFINED_VARIABLE_TITLE, varName);
147+
String title = MessageFormat.format(UNDEFINED_VARIABLE_CODEACTION_TITLE, varName);
123148

124149
Position position = new Position(0, 0);
125150

@@ -144,7 +169,7 @@ private void doCodeActionsForUndefinedVariable(Template template, Diagnostic dia
144169
}
145170
}
146171

147-
public void doCodeActionToDisableValidation(Template template, List<Diagnostic> diagnostics,
172+
private static void doCodeActionToDisableValidation(Template template, List<Diagnostic> diagnostics,
148173
List<CodeAction> codeActions) {
149174
String templateUri = template.getUri();
150175
// Disable Qute validation for the project
@@ -159,7 +184,6 @@ public void doCodeActionToDisableValidation(Template template, List<Diagnostic>
159184
CodeAction disableValidationForTemplateQuickFix = createConfigurationUpdateCodeAction(title, templateUri,
160185
QUTE_VALIDATION_EXCLUDED_SECTION, templateUri, ConfigurationItemEditType.add, diagnostics);
161186
codeActions.add(disableValidationForTemplateQuickFix);
162-
163187
}
164188

165189
/**
@@ -180,4 +204,39 @@ private static CodeAction createConfigurationUpdateCodeAction(String title, Stri
180204
return createCommand(title, QuteClientCommandConstants.COMMAND_CONFIGURATION_UPDATE,
181205
Collections.singletonList(configItemEdit), diagnostics);
182206
}
207+
208+
private static void doCodeActionsForUndefinedSectionTag(Template template, Diagnostic diagnostic,
209+
List<CodeAction> codeActions) {
210+
QuteProject project = template.getProject();
211+
if (project == null) {
212+
return;
213+
}
214+
try {
215+
String tagName = null;
216+
JsonObject data = (JsonObject) diagnostic.getData();
217+
if (data != null) {
218+
tagName = data.get(DIAGNOSTIC_DATA_TAG).getAsString();
219+
} else {
220+
int offset = template.offsetAt(diagnostic.getRange().getStart());
221+
Node node = template.findNodeAt(offset);
222+
node = QutePositionUtility.findBestNode(offset, node);
223+
if (node.getKind() == NodeKind.Section) {
224+
Section section = (Section) node;
225+
tagName = section.getTag();
226+
}
227+
}
228+
if (tagName == null) {
229+
return;
230+
}
231+
232+
// TODO : use a settings to know the preferred file extension
233+
String preferedFileExtension = ".html";
234+
String tagFileUri = project.getTagsDir().resolve(tagName + preferedFileExtension).toUri().toString();
235+
String title = MessageFormat.format(UNDEFINED_SECTION_TAG_CODEACTION_TITLE, tagName);
236+
CodeAction createUserTagFile = CodeActionFactory.createFile(title, tagFileUri, "", diagnostic);
237+
codeActions.add(createUserTagFile);
238+
} catch (BadLocationException e) {
239+
LOGGER.log(Level.SEVERE, "Creation of undefined user tag code action failed", e);
240+
}
241+
}
183242
}

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/QuteDiagnostics.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -304,6 +304,8 @@ private static void validateSectionTag(Section section, Template template,
304304
Range range = QutePositionUtility.selectStartTagName(section);
305305
Diagnostic diagnostic = createDiagnostic(range, DiagnosticSeverity.Error,
306306
QuteErrorCode.UndefinedSectionTag, tagName);
307+
// Create data information helpful for code action
308+
diagnostic.setData(DiagnosticDataFactory.createUndefinedSectionTagData(tagName));
307309
diagnostics.add(diagnostic);
308310
}
309311
}

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/diagnostics/DiagnosticDataFactory.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_ITERABLE;
1515
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_NAME;
16+
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.DIAGNOSTIC_DATA_TAG;
1617
import static com.redhat.qute.services.diagnostics.QuteDiagnosticContants.QUTE_SOURCE;
1718

1819
import org.eclipse.lsp4j.Diagnostic;
@@ -21,6 +22,12 @@
2122

2223
import com.google.gson.JsonObject;
2324

25+
/**
26+
* Diagnostic factory.
27+
*
28+
* @author Angelo ZERR
29+
*
30+
*/
2431
public class DiagnosticDataFactory {
2532

2633
public static JsonObject createUndefinedVariableData(String partName, boolean iterable) {
@@ -30,6 +37,12 @@ public static JsonObject createUndefinedVariableData(String partName, boolean it
3037
return data;
3138
}
3239

40+
public static JsonObject createUndefinedSectionTagData(String tagName) {
41+
JsonObject data = new JsonObject();
42+
data.addProperty(DIAGNOSTIC_DATA_TAG, tagName);
43+
return data;
44+
}
45+
3346
public static Diagnostic createDiagnostic(Range range, DiagnosticSeverity severity, IQuteErrorCode errorCode,
3447
Object... arguments) {
3548
String message = errorCode.getMessage(arguments);

qute.ls/com.redhat.qute.ls/src/main/java/com/redhat/qute/services/diagnostics/QuteDiagnosticContants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,4 +23,5 @@ private QuteDiagnosticContants() {
2323

2424
public static final String DIAGNOSTIC_DATA_ITERABLE = "iterable";
2525

26+
public static final String DIAGNOSTIC_DATA_TAG = "tag";
2627
}

0 commit comments

Comments
 (0)