Skip to content

Commit

Permalink
Allow code actions to be created if no Diagnostic is provided #1516
Browse files Browse the repository at this point in the history
  • Loading branch information
vrubezhny committed May 15, 2023
1 parent 7f66820 commit ab6533f
Show file tree
Hide file tree
Showing 4 changed files with 94 additions and 29 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 Angelo ZERR
* Copyright (c) 2018, 2023 Angelo ZERR
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -45,35 +45,54 @@ public XMLCodeActions(XMLExtensionsRegistry extensionsRegistry) {
}

public List<CodeAction> doCodeActions(CodeActionContext context, Range range, DOMDocument document,
SharedSettings sharedSettings, CancelChecker cancelChecker) {
SharedSettings sharedSettings, CancelChecker cancelChecker) throws CancellationException {
cancelChecker.checkCanceled();

List<CodeAction> codeActions = new ArrayList<>();
List<Diagnostic> diagnostics = context.getDiagnostics();

// The first pass is for CodeAction participants that have to react on a certain diagnostic code
if (diagnostics != null) {
for (Diagnostic diagnostic : context.getDiagnostics()) {
for (ICodeActionParticipant codeActionParticipant : extensionsRegistry.getCodeActionsParticipants()) {
try {
for (Diagnostic diagnostic : diagnostics) {
if (diagnostic != null) { // Never run this cycle if diagnostic is null
for (ICodeActionParticipant codeActionParticipant : extensionsRegistry.getCodeActionsParticipants()) {
cancelChecker.checkCanceled();
CodeActionRequest request = new CodeActionRequest(diagnostic, range, document,
extensionsRegistry, sharedSettings);
codeActionParticipant.doCodeAction(request, codeActions, cancelChecker);
} catch (CancellationException e) {
throw e;
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error while processing code actions for the participant '"
+ codeActionParticipant.getClass().getName() + "'.", e);
try {
CodeActionRequest request = new CodeActionRequest(diagnostic, range, document,
extensionsRegistry, sharedSettings);
codeActionParticipant.doCodeAction(request, codeActions, cancelChecker);
} catch (CancellationException e) {
throw e;
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error while processing code actions for the participant '"
+ codeActionParticipant.getClass().getName() + "'.", e);
}
}
}
}
}

// The second pass is for CodeAction participants that have to create CodeActions independently of diagnostics
for (ICodeActionParticipant codeActionParticipant : extensionsRegistry.getCodeActionsParticipants()) {
cancelChecker.checkCanceled();
try {
CodeActionRequest request = new CodeActionRequest(null, range, document,
extensionsRegistry, sharedSettings);
codeActionParticipant.doCodeActionUnconditional(request, codeActions, cancelChecker);
} catch (CancellationException e) {
throw e;
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error while processing code actions for the participant '"
+ codeActionParticipant.getClass().getName() + "'.", e);
}
}

cancelChecker.checkCanceled();
return codeActions;
}

public CodeAction resolveCodeAction(CodeAction unresolved, DOMDocument document, SharedSettings sharedSettings,
CancelChecker cancelChecker) {
CancelChecker cancelChecker) throws CancellationException {
ResolveCodeActionRequest request = new ResolveCodeActionRequest(unresolved, document, extensionsRegistry,
sharedSettings);
String participantId = request.getParticipantId();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018 Angelo ZERR.
* Copyright (c) 2018, 2023 Angelo ZERR.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -35,6 +35,17 @@ public interface ICodeActionParticipant {
*/
void doCodeAction(ICodeActionRequest request, List<CodeAction> codeActions, CancelChecker cancelChecker);

/**
* Collect the code action in the given <code>codeActions</code> for the given
* code action request <code>request</code> independently of diagnostic provided.
*
* @param request the code action request.
* @param codeActions list of code actions to fill.
* @param cancelChecker the cancel checker.
*/
default void doCodeActionUnconditional(ICodeActionRequest request, List<CodeAction> codeActions, CancelChecker cancelChecker) {
}

/**
* Returns the codeAction resolver participant identified by the given
* <code>participantId</code> and null otherwise.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/**
* Copyright (c) 2018, 2022 Angelo ZERR
* Copyright (c) 2018, 2023 Angelo ZERR
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v2.0
* which accompanies this distribution, and is available at
Expand Down Expand Up @@ -878,7 +878,7 @@ public static List<CodeAction> testCodeActionsFor(String xml, Diagnostic diagnos
SharedSettings settings = new SharedSettings();
settings.getFormattingSettings().setTabSize(4);
settings.getFormattingSettings().setInsertSpaces(false);
return testCodeActionsFor(xml, diagnostic, null, null, settings, null, index, expected);
return testCodeActionsFor(xml, diagnostic, null, null, null, settings, null, index, expected);
}

public static List<CodeAction> testCodeActionsFor(String xml, String fileURI, Diagnostic diagnostic,
Expand All @@ -901,7 +901,7 @@ public static List<CodeAction> testCodeActionsFor(String xml, String fileURI, Di
SharedSettings settings = new SharedSettings();
settings.getFormattingSettings().setTabSize(4);
settings.getFormattingSettings().setInsertSpaces(false);
return testCodeActionsFor(xml, diagnostic, catalogPath, fileURI, settings, null, -1, expected);
return testCodeActionsFor(xml, diagnostic, null, catalogPath, fileURI, settings, null, -1, expected);
}

public static List<CodeAction> testCodeActionsFor(String xml, Diagnostic diagnostic, String catalogPath,
Expand All @@ -912,26 +912,33 @@ public static List<CodeAction> testCodeActionsFor(String xml, Diagnostic diagnos
public static List<CodeAction> testCodeActionsFor(String xml, Diagnostic diagnostic, String catalogPath,
SharedSettings sharedSettings, XMLLanguageService xmlLanguageService, CodeAction... expected)
throws BadLocationException {
return testCodeActionsFor(xml, diagnostic, catalogPath, null, sharedSettings, xmlLanguageService, -1, expected);
return testCodeActionsFor(xml, diagnostic, null, catalogPath, null, sharedSettings, xmlLanguageService, -1, expected);
}

public static List<CodeAction> testCodeActionsFor(String xml, Diagnostic diagnostic, String catalogPath,
public static List<CodeAction> testCodeActionsFor(String xml, Range range, String catalogPath,
SharedSettings sharedSettings, XMLLanguageService xmlLanguageService, CodeAction... expected)
throws BadLocationException {
return testCodeActionsFor(xml, null, range, catalogPath, null, sharedSettings, xmlLanguageService, -1, expected);
}
public static List<CodeAction> testCodeActionsFor(String xml, Diagnostic diagnostic, Range range, String catalogPath,
String fileURI, SharedSettings sharedSettings, XMLLanguageService xmlLanguageService, int index,
CodeAction... expected) throws BadLocationException {
int offset = xml.indexOf('|');
Range range = null;

if (offset != -1) {
xml = xml.substring(0, offset) + xml.substring(offset + 1);
}
TextDocument document = new TextDocument(xml.toString(), fileURI != null ? fileURI : FILE_URI);

// Use range from the text (if marked by "|"-char or from diagnostics
if (offset != -1) {
Position position = document.positionAt(offset);
range = new Range(position, position);
} else {
} else if (range == null && diagnostic != null) {
range = diagnostic.getRange();
}

// Otherwise, range is to be specified in parameters
assertNotNull(range, "Range cannot be null");

if (xmlLanguageService == null) {
xmlLanguageService = new XMLLanguageService();
Expand Down Expand Up @@ -979,9 +986,11 @@ public static void assertCodeActions(List<CodeAction> actual, CodeAction... expe
ca.setTitle("");
if (ca.getDiagnostics() != null) {
ca.getDiagnostics().forEach(d -> {
d.setSeverity(null);
d.setMessage("");
d.setSource(null);
if (d != null) {
d.setSeverity(null);
d.setMessage("");
d.setSource(null);
}
});
}
});
Expand Down Expand Up @@ -1114,6 +1123,10 @@ public static Either<TextDocumentEdit, ResourceOperation> teOp(String uri, int s
Collections.singletonList(te(startLine, startChar, endLine, endChar, newText))));
}

public static Either<TextDocumentEdit, ResourceOperation> teOp(String uri, TextEdit... te) {
return Either.forLeft(new TextDocumentEdit(new VersionedTextDocumentIdentifier(uri, 0), Arrays.asList(te)));
}

// ------------------- Hover assert

public static void assertHover(String value) throws BadLocationException {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2020 Red Hat Inc. and others.
* Copyright (c) 2020, 2023 Red Hat Inc. and others.
* All rights reserved. This program and the accompanying materials
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v20.html
Expand Down Expand Up @@ -50,6 +50,8 @@
import org.eclipse.lemminx.services.DocumentSymbolsResult;
import org.eclipse.lemminx.services.SymbolInformationResult;
import org.eclipse.lemminx.services.XMLLanguageService;
import org.eclipse.lemminx.services.extensions.codeaction.ICodeActionParticipant;
import org.eclipse.lemminx.services.extensions.codeaction.ICodeActionRequest;
import org.eclipse.lemminx.services.extensions.completion.ICompletionParticipant;
import org.eclipse.lemminx.services.extensions.completion.ICompletionRequest;
import org.eclipse.lemminx.services.extensions.completion.ICompletionResponse;
Expand All @@ -60,6 +62,7 @@
import org.eclipse.lemminx.settings.XMLSymbolFilter;
import org.eclipse.lemminx.settings.XMLSymbolSettings;
import org.eclipse.lemminx.utils.XMLBuilder;
import org.eclipse.lsp4j.CodeAction;
import org.eclipse.lsp4j.CodeLens;
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.Diagnostic;
Expand Down Expand Up @@ -114,8 +117,21 @@ public ErrorParticipantLanguageService() {
throw new RuntimeException("This participant is broken");
});
this.registerCodeActionParticipant((request, codeActions, cancelChecker) -> {
// This Code Action Participant should add its code actions based on diagnostic code
Diagnostic diagnostic = request.getDiagnostic();
codeActions.add(ca(diagnostic, te(0, 0, 0, 0, "a")));
if (diagnostic != null) {
codeActions.add(ca(diagnostic, te(0, 0, 0, 0, "a")));
}
});
this.registerCodeActionParticipant(new ICodeActionParticipant () {
public void doCodeAction(ICodeActionRequest request, List<CodeAction> codeActions, CancelChecker cancelChecker) {
// Nothing to do for a diagnostic, even if provided
}
public void doCodeActionUnconditional(ICodeActionRequest request, List<CodeAction> codeActions, CancelChecker cancelChecker) {
// This Code Action Participant should add its code actions independently of
// diagnostic provided
codeActions.add(ca(null, te(0, 0, 0, 0, "b")));
}
});

this.registerCodeLensParticipant((request, lenses, cancelChecker) -> {
Expand Down Expand Up @@ -367,7 +383,13 @@ public void findDocumentSymbols(DOMDocument document, DocumentSymbolsResult symb
public void testCodeAction() throws BadLocationException {
Diagnostic diagnostic = d(0, 0, 2, XMLSyntaxErrorCode.ElementUnterminated);
testCodeActionsFor("", diagnostic, (String) null, null, new ErrorParticipantLanguageService(),
ca(diagnostic, te(0, 0, 0, 0, "a")));
ca(diagnostic, te(0, 0, 0, 0, "a")), ca(null, te(0, 0, 0, 0, "b")));
}

@Test
public void testCodeActionNullDiagnostic() throws BadLocationException {
testCodeActionsFor("", r(0,0, 0, 0), (String) null, null, new ErrorParticipantLanguageService(),
ca(null, te(0, 0, 0, 0, "b")));
}

@Test
Expand Down

0 comments on commit ab6533f

Please sign in to comment.