Skip to content

Commit

Permalink
Indentation settings for CodeAction
Browse files Browse the repository at this point in the history
When it recieves `textDocument/codeAction`,
the server updates the indentation settings with
the indentation settings of the current document.
It does this by requesting the settings
`xml.format.tabSize` and `xml.format.insertSpaces` from the client.
It does this right before generating the CodeActions for the document.

Signed-off-by: David Thompson <davthomp@redhat.com>
  • Loading branch information
datho7561 committed Oct 9, 2020
1 parent 7fe05f1 commit 7ef7e21
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 14 deletions.
Expand Up @@ -28,6 +28,8 @@
import java.util.function.Predicate;
import java.util.stream.Collectors;

import com.google.gson.JsonPrimitive;

import org.eclipse.lemminx.client.ExtendedClientCapabilities;
import org.eclipse.lemminx.client.LimitExceededWarner;
import org.eclipse.lemminx.client.LimitFeature;
Expand Down Expand Up @@ -59,6 +61,8 @@
import org.eclipse.lsp4j.CompletionItem;
import org.eclipse.lsp4j.CompletionList;
import org.eclipse.lsp4j.CompletionParams;
import org.eclipse.lsp4j.ConfigurationItem;
import org.eclipse.lsp4j.ConfigurationParams;
import org.eclipse.lsp4j.DefinitionParams;
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
import org.eclipse.lsp4j.DidCloseTextDocumentParams;
Expand Down Expand Up @@ -89,6 +93,7 @@
import org.eclipse.lsp4j.WorkspaceEdit;
import org.eclipse.lsp4j.jsonrpc.CancelChecker;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.eclipse.lsp4j.jsonrpc.validation.NonNull;
import org.eclipse.lsp4j.services.TextDocumentService;

/**
Expand Down Expand Up @@ -202,10 +207,35 @@ public CompletableFuture<Hover> hover(HoverParams params) {
});
}

private XMLFormattingOptions getFormattingSettings(String uri) {
// TODO: manage formattings per document URI (to support .editorconfig for
// instance).
return sharedSettings.getFormattingSettings();
/**
* Returns the indentation settings (`xml.format.tabSize` and
* `xml.format.insertSpaces`) for the document with the given URI.
*
* @param uri the uri of the document to get the indentation settings for
* @return the indentation settings (`xml.format.tabSize` and
* `xml.format.insertSpaces`) for the document with the given URI
*/
private CompletableFuture<XMLFormattingOptions> getIndentationSettings(@NonNull String uri) {
ConfigurationItem insertSpaces = new ConfigurationItem();
insertSpaces.setScopeUri(uri);
insertSpaces.setSection("xml.format.insertSpaces");

ConfigurationItem tabSize = new ConfigurationItem();
tabSize.setScopeUri(uri);
tabSize.setSection("xml.format.tabSize");

return xmlLanguageServer.getLanguageClient().configuration(new ConfigurationParams(Arrays.asList( //
insertSpaces, tabSize //
))).thenApply(indentationSettings -> {
XMLFormattingOptions newOptions = new XMLFormattingOptions();
if (indentationSettings.get(0) != null) {
newOptions.setInsertSpaces(((JsonPrimitive) indentationSettings.get(0)).getAsBoolean());
}
if (indentationSettings.get(1) != null) {
newOptions.setTabSize(((JsonPrimitive) indentationSettings.get(1)).getAsInt());
}
return newOptions;
});
}

@Override
Expand Down Expand Up @@ -383,9 +413,18 @@ public CompletableFuture<List<? extends CodeLens>> codeLens(CodeLensParams param

@Override
public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActionParams params) {
return computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> {
String uri = params.getTextDocument().getUri();
return getXMLLanguageService()
String uri = params.getTextDocument().getUri();
return getIndentationSettings(uri)
.handle((XMLFormattingOptions indentationSettings, Throwable err) -> {
if (indentationSettings != null) {
sharedSettings.getFormattingSettings().merge(indentationSettings);
}
return null;
})
.thenCombine(computeDOMAsync(params.getTextDocument(), (cancelChecker, xmlDocument) -> {
return xmlDocument;
}), (void_, xmlDocument) -> {
return (List<Either<Command, CodeAction>>) getXMLLanguageService()
.doCodeActions(params.getContext(), params.getRange(), xmlDocument, sharedSettings) //
.stream() //
.map(ca -> {
Expand Down Expand Up @@ -416,7 +455,7 @@ public void didSave(DidSaveTextDocumentParams params) {

/**
* Update settings of the language service.
*
*
* @param settings
*/
public void updateSettings(Object settings) {
Expand All @@ -431,7 +470,7 @@ void doSave(String uri) {

/**
* Save settings or XML file.
*
*
* @param context
*/
void doSave(SaveContext context) {
Expand Down Expand Up @@ -518,7 +557,7 @@ public SharedSettings getSharedSettings() {

/**
* Returns the text document from the given uri.
*
*
* @param uri the uri
* @return the text document from the given uri.
*/
Expand All @@ -534,7 +573,7 @@ public boolean documentIsOpen(String uri) {
/**
* Compute the DOM Document for a given uri in a future and then apply the given
* function.
*
*
* @param <R>
* @param documentIdentifier the document indetifier.
* @param code a bi function that accepts a {@link CancelChecker}
Expand Down
Expand Up @@ -445,7 +445,7 @@ public void Issue862() throws Exception {
"</article>";
testCodeActionsFor(xml, d, ca(d, te(2, 0, 2, 0, "[\n\t<!ENTITY nbsp \"entity-value\">\n]")));
}

@Test
public void EntityNotDeclaredDoctypeEmptySubset() throws Exception {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" + //
Expand Down Expand Up @@ -508,12 +508,57 @@ public void NotationDeclUnterminated() throws Exception {

@Test
public void EntityNotDeclared() throws Exception {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + "<!DOCTYPE article [\r\n"
+ " <!ELEMENT article (#PCDATA)>\r\n" + "]>\r\n" + "<article>\r\n" + " &nbsp;\r\n" + "</article>";
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + //
"<!DOCTYPE article [\r\n" + //
" <!ELEMENT article (#PCDATA)>\r\n" + //
"]>\r\n" + //
"<article>\r\n" + //
" &nbsp;\r\n" + //
"</article>";

XMLAssert.testDiagnosticsFor(xml, d(5, 1, 7, DTDErrorCode.EntityNotDeclared));
}

@Test
public void EntityNotDeclaredRespectsIndentSettings1() throws Exception {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + //
"<!DOCTYPE article [\r\n" + //
" <!ELEMENT article (#PCDATA)>\r\n" + //
"]>\r\n" + //
"<article>\r\n" + //
" &nbsp;\r\n" + //
"</article>";
SharedSettings settings = new SharedSettings();
settings.getPreferences().setQuoteStyle(QuoteStyle.singleQuotes);
settings.getFormattingSettings().setEnforceQuoteStyle(EnforceQuoteStyle.preferred);
settings.getFormattingSettings().setInsertSpaces(true);
settings.getFormattingSettings().setTabSize(6);
Diagnostic d = d(5, 1, 5, 7, DTDErrorCode.EntityNotDeclared,
"The entity \"nbsp\" was referenced, but not declared.");
XMLAssert.testDiagnosticsFor(xml, d);
testCodeActionsFor(xml, d, settings, ca(d, te(2, 29, 2, 29, "\r\n <!ENTITY nbsp \'entity-value\'>")));
}

@Test
public void EntityNotDeclaredRespectsIndentSettings2() throws Exception {
String xml = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n" + //
"<!DOCTYPE article [\r\n" + //
" <!ELEMENT article (#PCDATA)>\r\n" + //
"]>\r\n" + //
"<article>\r\n" + //
" &nbsp;\r\n" + //
"</article>";
SharedSettings settings = new SharedSettings();
settings.getPreferences().setQuoteStyle(QuoteStyle.singleQuotes);
settings.getFormattingSettings().setEnforceQuoteStyle(EnforceQuoteStyle.preferred);
settings.getFormattingSettings().setInsertSpaces(true);
settings.getFormattingSettings().setTabSize(3);
Diagnostic d = d(5, 1, 5, 7, DTDErrorCode.EntityNotDeclared,
"The entity \"nbsp\" was referenced, but not declared.");
XMLAssert.testDiagnosticsFor(xml, d);
testCodeActionsFor(xml, d, settings, ca(d, te(2, 29, 2, 29, "\r\n <!ENTITY nbsp \'entity-value\'>")));
}

@Test
public void ElementDeclUnterminated() throws Exception {
String xml = "<?xml version = \"1.0\"?>\r\n" + //
Expand Down

0 comments on commit 7ef7e21

Please sign in to comment.