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

Formatter Maven plugin #864

Merged
merged 41 commits into from
Dec 11, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
cf5ef6e
Created formatter interface
maria77102 Oct 23, 2024
b124d3a
Implement interface + first Test
maria77102 Oct 23, 2024
777832c
Fix formatting test + implementation
maria77102 Oct 28, 2024
b7d3057
Enhanced test suite
maria77102 Oct 28, 2024
d2c7c2c
Implement suggested changes
maria77102 Oct 30, 2024
619d38c
Improved interface methods/exception handling and added logging
maria77102 Nov 6, 2024
a57b7ee
Added formatting tool method
maria77102 Nov 6, 2024
c8bc3b4
Add dependencies for logging in tools project
maria77102 Nov 6, 2024
6e09f6d
Improve implementation of command line tool
maria77102 Nov 6, 2024
abca32a
Formatting java code
maria77102 Nov 7, 2024
5591d3d
Made formatting happen in-memory
maria77102 Nov 7, 2024
b36f60c
Update logs when resource saved
maria77102 Nov 7, 2024
2f84974
Fixed logger class name
maria77102 Nov 7, 2024
7cf4bd2
Starting code for formatter plugin
maria77102 Nov 7, 2024
116995c
Merge branch 'main' into formatter-maven-plugin
maria77102 Nov 7, 2024
b65a756
Incorporate 'format' goal in existing plugin
maria77102 Nov 8, 2024
6ca9578
Cleanup files
maria77102 Nov 8, 2024
6e23194
Add test cases for edge cases and unusual behavior
maria77102 Nov 19, 2024
f8cd98e
Update code to deal with runtime exceptions
maria77102 Nov 19, 2024
956fb9c
Fix formatting errors with Choice and parenthesis
maria77102 Nov 19, 2024
e1165ac
Implement suggested changes
maria77102 Nov 19, 2024
ebcb6c2
Merge branch 'main' into formatter-maven-plugin
maria77102 Nov 20, 2024
a497664
Fix comment
maria77102 Nov 20, 2024
60038cd
Implement suggestion
maria77102 Nov 21, 2024
29d5c03
Fix only exists serialization issue
maria77102 Nov 21, 2024
a002f3e
Merge branch 'main' into formatter-maven-plugin
maria77102 Nov 21, 2024
0a6f1a9
Cleanup test
maria77102 Nov 21, 2024
bf9fd47
Update plugin to also use user-given formatting options
maria77102 Nov 26, 2024
da7f54b
Update plugin to use formatting options
maria77102 Nov 27, 2024
ed517eb
Update formatting strategy to avoid serialization
maria77102 Nov 27, 2024
2686331
Add handler support to service for processing formatted content
maria77102 Nov 28, 2024
2043ada
Implemented suggested changes
maria77102 Nov 28, 2024
7f60399
Update cmd tool + cleanup
maria77102 Dec 3, 2024
f977ebe
Format closing brackets to collapse in nested constructors
maria77102 Dec 4, 2024
7d81fc5
Introduce FormattingOptionsAdaptor for shared FormattingOptions logic
maria77102 Dec 5, 2024
f4b3fa4
Formatted collapsable closing brackets in nested constructors
maria77102 Dec 5, 2024
5126286
Fix collapsing closing brackets logic
maria77102 Dec 10, 2024
cc1a731
Add endpoint for default formatting options
maria77102 Dec 10, 2024
3786efc
Implement suggested changes
maria77102 Dec 10, 2024
b6333ee
Fix failing test
maria77102 Dec 10, 2024
fd93377
Cleanup code
maria77102 Dec 11, 2024
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 @@ -24,18 +24,15 @@

import org.eclipse.lsp4j.FormattingOptions;
import org.eclipse.lsp4j.TextEdit;
import org.eclipse.xtext.formatting.IIndentationInformation;
import org.eclipse.xtext.formatting2.IFormatter2;
import org.eclipse.xtext.formatting2.regionaccess.ITextReplacement;
import org.eclipse.xtext.ide.server.Document;
import org.eclipse.xtext.ide.server.formatting.FormattingService;
import org.eclipse.xtext.preferences.ITypedPreferenceValues;
import org.eclipse.xtext.preferences.MapBasedPreferenceValues;
import org.eclipse.xtext.resource.XtextResource;
import org.eclipse.xtext.util.TextRegion;

import com.google.common.base.Strings;
import com.regnosys.rosetta.formatting2.RosettaFormatterPreferenceKeys;
import com.regnosys.rosetta.formatting2.FormattingOptionsAdaptor;

/**
* This class allows passing additional formatting parameters as defined in
Expand All @@ -47,55 +44,17 @@
* - expose injected fields to child classes (make them protected)
*/
public class RosettaFormattingService extends FormattingService {
public static String PREFERENCE_INDENTATION_KEY = "indentation";
public static String PREFERENCE_MAX_LINE_WIDTH_KEY = "maxLineWidth";
public static String PREFERENCE_CONDITIONAL_MAX_LINE_WIDTH_KEY = "conditionalMaxLineWidth";

@Inject
private Provider<IFormatter2> formatter2Provider;

@Inject
private IIndentationInformation indentationInformation;

protected ITypedPreferenceValues createPreferences(FormattingOptions options) {
MapBasedPreferenceValues preferences = new MapBasedPreferenceValues();

String indent = indentationInformation.getIndentString();
if (options != null) {
if (options.isInsertSpaces()) {
indent = Strings.padEnd("", options.getTabSize(), ' ');
}
}
preferences.put(PREFERENCE_INDENTATION_KEY, indent);

if (options == null) {
return preferences;
}
private FormattingOptionsAdaptor formattingOptionsAdapter;

Number conditionalMaxLineWidth = options.getNumber(PREFERENCE_CONDITIONAL_MAX_LINE_WIDTH_KEY);
if (conditionalMaxLineWidth != null) {
preferences.put(RosettaFormatterPreferenceKeys.conditionalMaxLineWidth, conditionalMaxLineWidth.intValue());
}
Number maxLineWidth = options.getNumber(PREFERENCE_MAX_LINE_WIDTH_KEY);
if (maxLineWidth != null) {
preferences.put(RosettaFormatterPreferenceKeys.maxLineWidth, maxLineWidth.intValue());
if (conditionalMaxLineWidth == null) {
int defaultConditionalMaxLineWidth = RosettaFormatterPreferenceKeys.conditionalMaxLineWidth.toValue(RosettaFormatterPreferenceKeys.conditionalMaxLineWidth.getDefaultValue());
int defaultMaxLineWidth = RosettaFormatterPreferenceKeys.maxLineWidth.toValue(RosettaFormatterPreferenceKeys.maxLineWidth.getDefaultValue());
double defaultRatio = (double)defaultConditionalMaxLineWidth / defaultMaxLineWidth;
preferences.put(RosettaFormatterPreferenceKeys.conditionalMaxLineWidth, (int)(maxLineWidth.doubleValue() * defaultRatio));
}
}

return preferences;
}

@Override
public List<TextEdit> format(XtextResource resource, Document document, int offset, int length,
FormattingOptions options) {
List<TextEdit> result = new ArrayList<>();
if (this.formatter2Provider != null) {
ITypedPreferenceValues preferences = createPreferences(options);
ITypedPreferenceValues preferences = formattingOptionsAdapter.createPreferences(options);
List<ITextReplacement> replacements = format2(resource, new TextRegion(offset, length), preferences);
for (ITextReplacement r : replacements) {
result.add(toTextEdit(document, r.getReplacementText(), r.getOffset(), r.getLength()));
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package com.regnosys.rosetta.ide.server;

import java.util.concurrent.CompletableFuture;

import org.eclipse.lsp4j.FormattingOptions;
import org.eclipse.lsp4j.jsonrpc.services.JsonRequest;
import org.eclipse.lsp4j.services.LanguageServer;

public interface RosettaLanguageServer extends LanguageServer{

@JsonRequest
CompletableFuture<FormattingOptions> getDefaultFormattingOptions();
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,25 @@
import org.eclipse.xtext.resource.IResourceServiceProvider;
import org.eclipse.xtext.util.CancelIndicator;

import com.regnosys.rosetta.formatting2.FormattingOptionsAdaptor;
import com.regnosys.rosetta.ide.inlayhints.IInlayHintsResolver;
import com.regnosys.rosetta.ide.inlayhints.IInlayHintsService;
import com.regnosys.rosetta.ide.semantictokens.ISemanticTokensService;
import com.regnosys.rosetta.ide.semantictokens.SemanticToken;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.CompletableFuture;

import javax.inject.Inject;

/**
* TODO: contribute to Xtext.
*
*/
public class RosettaLanguageServerImpl extends LanguageServerImpl {
public class RosettaLanguageServerImpl extends LanguageServerImpl implements RosettaLanguageServer{
@Inject FormattingOptionsAdaptor formattingOptionsAdapter;

@Override
protected ServerCapabilities createServerCapabilities(InitializeParams params) {
Expand Down Expand Up @@ -170,4 +175,14 @@ protected SemanticTokens semanticTokensRange(SemanticTokensRangeParams params, C
public CompletableFuture<SemanticTokens> semanticTokensRange(SemanticTokensRangeParams params) {
return this.getRequestManager().runRead((cancelIndicator) -> this.semanticTokensRange(params, cancelIndicator));
}

@Override
public CompletableFuture<FormattingOptions> getDefaultFormattingOptions() {
try {
return CompletableFuture.completedFuture(formattingOptionsAdapter.readFormattingOptions(null));
} catch (IOException e) {
// should never happen, since null path always leads to default options being returned
return CompletableFuture.failedFuture(e);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.regnosys.rosetta.ide.formatting
import org.junit.jupiter.api.Test
import com.regnosys.rosetta.ide.tests.AbstractRosettaLanguageServerTest
import org.eclipse.lsp4j.FormattingOptions
import com.regnosys.rosetta.formatting2.FormattingOptionsAdaptor

class FormattingTest extends AbstractRosettaLanguageServerTest {
@Test
Expand All @@ -23,7 +24,7 @@ class FormattingTest extends AbstractRosettaLanguageServerTest {
testFormatting(
[
val options = new FormattingOptions
options.putNumber(RosettaFormattingService.PREFERENCE_MAX_LINE_WIDTH_KEY, 10)
options.putNumber(FormattingOptionsAdaptor.PREFERENCE_MAX_LINE_WIDTH_KEY, 10)
it.options = options
],
[
Expand Down Expand Up @@ -67,7 +68,7 @@ class FormattingTest extends AbstractRosettaLanguageServerTest {
testFormatting(
[
val options = new FormattingOptions
options.putNumber(RosettaFormattingService.PREFERENCE_CONDITIONAL_MAX_LINE_WIDTH_KEY, 10)
options.putNumber(FormattingOptionsAdaptor.PREFERENCE_CONDITIONAL_MAX_LINE_WIDTH_KEY, 10)
it.options = options
],
[
Expand Down
1 change: 1 addition & 0 deletions rosetta-lang/model/RosettaExpression.xcore
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,7 @@ class JoinOperation extends RosettaBinaryOperation {

class RosettaOnlyExistsExpression extends RosettaExpression {
contains RosettaExpression[] args
boolean hasParentheses
}

/**
Expand Down
4 changes: 4 additions & 0 deletions rosetta-lang/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-yaml</artifactId>
</dependency>
<dependency>
<groupId>org.eclipse.lsp4j</groupId>
<artifactId>org.eclipse.lsp4j</artifactId>
</dependency>
<!-- This dependency is only necessary to make it work in Eclipse. TODO:
remove this and figure out a better way. -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -789,7 +789,7 @@ RosettaCalcConditionalExpression returns RosettaExpression:
;

RosettaCalcOnlyExists returns RosettaExpression:
{RosettaOnlyExistsExpression} (args+=RosettaOnlyExistsElement | ('(' args+=RosettaOnlyExistsElement (',' args+=RosettaOnlyExistsElement)* ')')) 'only' 'exists'
{RosettaOnlyExistsExpression} (args+=RosettaOnlyExistsElement | (hasParentheses?='(' args+=RosettaOnlyExistsElement (',' args+=RosettaOnlyExistsElement)* ')')) 'only' 'exists'
;

RosettaOnlyExistsElement returns RosettaExpression:
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
package com.regnosys.rosetta.formatting2;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;

import org.eclipse.emf.mwe.core.resources.ResourceLoader;
import org.eclipse.lsp4j.FormattingOptions;
import org.eclipse.xtext.preferences.ITypedPreferenceValues;
import org.eclipse.xtext.preferences.MapBasedPreferenceValues;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.base.Strings;

public class FormattingOptionsAdaptor {
public static String PREFERENCE_INDENTATION_KEY = "indentation";
public static String PREFERENCE_MAX_LINE_WIDTH_KEY = "maxLineWidth";
public static String PREFERENCE_CONDITIONAL_MAX_LINE_WIDTH_KEY = "conditionalMaxLineWidth";

private static final String DEFAULT_FORMATTING_OPTIONS_PATH = "default-formatting-options.json";

public ITypedPreferenceValues createPreferences(FormattingOptions options) {
MapBasedPreferenceValues preferences = new MapBasedPreferenceValues();

String indent = "\t";
if (options != null) {
if (options.isInsertSpaces()) {
indent = Strings.padEnd("", options.getTabSize(), ' ');
}
}
preferences.put(PREFERENCE_INDENTATION_KEY, indent);

if (options == null) {
return preferences;
}

Number conditionalMaxLineWidth = options.getNumber(PREFERENCE_CONDITIONAL_MAX_LINE_WIDTH_KEY);
if (conditionalMaxLineWidth != null) {
preferences.put(RosettaFormatterPreferenceKeys.conditionalMaxLineWidth, conditionalMaxLineWidth.intValue());
}
Number maxLineWidth = options.getNumber(PREFERENCE_MAX_LINE_WIDTH_KEY);
if (maxLineWidth != null) {
preferences.put(RosettaFormatterPreferenceKeys.maxLineWidth, maxLineWidth.intValue());
if (conditionalMaxLineWidth == null) {
int defaultConditionalMaxLineWidth = RosettaFormatterPreferenceKeys.conditionalMaxLineWidth
.toValue(RosettaFormatterPreferenceKeys.conditionalMaxLineWidth.getDefaultValue());
int defaultMaxLineWidth = RosettaFormatterPreferenceKeys.maxLineWidth
.toValue(RosettaFormatterPreferenceKeys.maxLineWidth.getDefaultValue());
double defaultRatio = (double) defaultConditionalMaxLineWidth / defaultMaxLineWidth;
preferences.put(RosettaFormatterPreferenceKeys.conditionalMaxLineWidth,
(int) (maxLineWidth.doubleValue() * defaultRatio));
}
}

return preferences;
}

public FormattingOptions readFormattingOptions(String optionsPath) throws IOException {
InputStream resourceStream;
// If path not given, use default one
if (optionsPath == null) {
// Retrieve resource as an InputStream
resourceStream = ResourceLoader.class.getClassLoader().getResourceAsStream(DEFAULT_FORMATTING_OPTIONS_PATH);
} else {
resourceStream = new FileInputStream(optionsPath);
}

// Create an ObjectMapper, read JSON into a Map
ObjectMapper objectMapper = new ObjectMapper();
Map<String, Object> map = null;
map = objectMapper.readValue(resourceStream, Map.class);

// Create a FormattingOptions object
FormattingOptions formattingOptions = new FormattingOptions();

// Populate the FormattingOptions object
for (Map.Entry<String, Object> entry : map.entrySet()) {
String key = entry.getKey();
Object value = entry.getValue();

if (value instanceof String) {
formattingOptions.putString(key, (String) value);
} else if (value instanceof Number) {
formattingOptions.putNumber(key, (Number) value);
} else if (value instanceof Boolean) {
formattingOptions.putBoolean(key, (Boolean) value);
} else {
throw new IllegalArgumentException("Unsupported value type for key: " + key);
}
}
return formattingOptions;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
import org.eclipse.xtext.preferences.TypedPreferenceKey;

public class FormattingUtil {
private ITextRegionExtensions getTextRegionExt(IFormattableDocument doc) {
public ITextRegionExtensions getTextRegionExt(IFormattableDocument doc) {
return doc.getRequest().getTextRegionAccess().getExtensions();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package com.regnosys.rosetta.formatting2;

import org.eclipse.emf.ecore.resource.Resource;

/**
* Functional interface for handling a formatted resource and its corresponding
* formatted text.
* <p>
* This interface allows customization of how formatted resources are processed,
* such as saving the content, logging it, or using it for validations or
* assertions in tests.
* </p>
*/
@FunctionalInterface
public interface IFormattedResourceAcceptor {

/**
* Accepts a formatted resource and its formatted content for further
* processing.
*
* @param resource the {@link Resource} that was formatted
* @param formattedText the formatted content as a {@link String}
*/
void accept(Resource resource, String formattedText);
}
Loading
Loading