Skip to content

Commit

Permalink
Re-add support for line endings being configurable. (#960)
Browse files Browse the repository at this point in the history
* Re-add support for line endings being configurable.

closes #935

* Format file

* Update Src/CSharpier.Cli/Options/CaseInsensitiveEnumConverter.cs

Co-authored-by: Lasath Fernando <devel@lasath.org>

---------

Co-authored-by: Lasath Fernando <devel@lasath.org>
  • Loading branch information
belav and shocklateboy92 authored Sep 17, 2023
1 parent 85c6a68 commit 2ad4e5d
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 12 deletions.
44 changes: 39 additions & 5 deletions Docs/Configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ hide_table_of_contents: true
CSharpier has support for a configuration file. You can use any of the following files
- A ```.csharpierrc``` file in JSON or YAML.
- A ```.csharpierrc.json``` or ```.csharpierrc.yaml``` file.
- A ```.editorconfig``` file. See EditorConfig section below.

The configuration file will be resolved starting from the location of the file being formatted, and searching up the file tree until a config file is (or isn’t) found.

Expand All @@ -14,35 +15,49 @@ JSON
{
"printWidth": 100,
"useTabs": false,
"tabWidth": 4
"tabWidth": 4,
"endOfLine": "auto"
}
```
YAML
```yaml
printWidth: 100
useTabs: false
tabWidth: 4
endOfLine: auto
```
#### Print Width
Specify at what point the printer will wrap content. This is not a hard limit. Some lines will be shorter or longer.
Default 100
Default `100`
#### Use Tabs
_First available in 0.17.0_

Indent lines with tabs instead of spaces.

Default false
Default `false`
#### Tab Width
_First available in 0.17.0_

Specify the number of spaces used per indentation level.

Default 4
Default `4`

#### End of Line
_First available in 0.26.0_

Valid options:

- "auto" - Maintain existing line endings (mixed values within one file are normalised by looking at what's used after the first line)
- "lf" – Line Feed only (\n), common on Linux and macOS as well as inside git repos
- "crlf" - Carriage Return + Line Feed characters (\r\n), common on Windows

Default `auto`


#### Preprocessor Symbol Sets
**Removed in 0.25.0**
_Removed in 0.25.0_

Currently CSharpier only has basic support for understanding how to format code inside of `#if` directives.
It will attempt to determine which sets of preprocessor symbols are needed for roslyn to parse all the code in each file.
Expand All @@ -62,3 +77,22 @@ For example in the following code block, the following symbol sets would be need
When supplying symbol sets, they will be used for all files being formatted. This will slow down formatting, and determining all symbol sets needed across all files won't be straight forward.

The long term plan is to improve Csharpier's ability to determine the symbol sets itself and to allow specifying them for individual files.

### EditorConfig

CSharpier supports configuration via an `.editorconfig` file. A `.csahrpierrc*` file in the same directory will take priority.

```ini
[*]
# Non-configurable behaviors
charset = utf-8
insert_final_newline = true
trim_trailing_whitespace = true
# Configurable behaviors
# end_of_line = lf - there is no 'auto' with a .editorconfig
indent_style = space
indent_size = 4
max_line_length = 100
```
12 changes: 12 additions & 0 deletions Src/CSharpier.Cli/EditorConfig/EditorConfigSections.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ public PrinterOptions ConvertToPrinterOptions(string filePath)
printerOptions.TabWidth = resolvedConfiguration.IndentSize ?? printerOptions.TabWidth;
}

if (resolvedConfiguration.EndOfLine is { } endOfLine)
{
printerOptions.EndOfLine = endOfLine;
}

return printerOptions;
}

Expand All @@ -43,6 +48,7 @@ private class ResolvedConfiguration
public int? IndentSize { get; }
public int? TabWidth { get; }
public int? MaxLineLength { get; }
public EndOfLine? EndOfLine { get; }

public ResolvedConfiguration(List<Section> sections)
{
Expand Down Expand Up @@ -81,6 +87,12 @@ public ResolvedConfiguration(List<Section> sections)
? tabWidthValue
: this.IndentSize;
}

var endOfLine = sections.LastOrDefault(o => o.EndOfLine != null)?.EndOfLine;
if (Enum.TryParse(endOfLine, true, out EndOfLine result))
{
this.EndOfLine = result;
}
}
}
}
2 changes: 2 additions & 0 deletions Src/CSharpier.Cli/EditorConfig/Section.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ public class Section
public string? IndentSize { get; }
public string? TabWidth { get; }
public string? MaxLineLength { get; }
public string? EndOfLine { get; }

public Section(SectionData section, string directory)
{
Expand All @@ -20,6 +21,7 @@ public Section(SectionData section, string directory)
this.IndentSize = section.Keys["indent_size"];
this.TabWidth = section.Keys["tab_width"];
this.MaxLineLength = section.Keys["max_line_length"];
this.EndOfLine = section.Keys["end_of_line"];
}

public bool IsMatch(string fileName)
Expand Down
36 changes: 36 additions & 0 deletions Src/CSharpier.Cli/Options/CaseInsensitiveEnumConverter.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace CSharpier.Cli.Options;

using System.Text.Json;
using System.Text.Json.Serialization;

internal class CaseInsensitiveEnumConverter<TEnum> : JsonConverter<TEnum>
where TEnum : struct
{
public override TEnum Read(
ref Utf8JsonReader reader,
Type typeToConvert,
JsonSerializerOptions options
)
{
if (reader.TokenType != JsonTokenType.String)
{
throw new JsonException(
$"Expected a string for enum parsing, but got {reader.TokenType}."
);
}

var enumText = reader.GetString();
if (Enum.TryParse(enumText, ignoreCase: true, out TEnum result))
{
return result;
}

throw new JsonException($"Unable to parse '{enumText}' to enum of type {typeof(TEnum)}.");
}

public override void Write(Utf8JsonWriter writer, TEnum value, JsonSerializerOptions options)
{
var enumText = value.ToString();
writer.WriteStringValue(enumText);
}
}
8 changes: 6 additions & 2 deletions Src/CSharpier.Cli/Options/ConfigurationFileOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,16 +2,20 @@ namespace CSharpier.Cli.Options;

using System.IO.Abstractions;
using System.Text.Json;
using System.Text.Json.Serialization;
using Microsoft.Extensions.Logging;
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;

public class ConfigurationFileOptions
internal class ConfigurationFileOptions
{
public int PrintWidth { get; init; } = 100;
public int TabWidth { get; init; } = 4;
public bool UseTabs { get; init; }

[JsonConverter(typeof(CaseInsensitiveEnumConverter<EndOfLine>))]
public EndOfLine EndOfLine { get; init; }

private static readonly string[] validExtensions = { ".csharpierrc", ".json", ".yml", ".yaml" };

internal static PrinterOptions CreatePrinterOptionsFromPath(
Expand All @@ -34,7 +38,7 @@ ConfigurationFileOptions configurationFileOptions
TabWidth = configurationFileOptions.TabWidth,
UseTabs = configurationFileOptions.UseTabs,
Width = configurationFileOptions.PrintWidth,
EndOfLine = EndOfLine.Auto
EndOfLine = configurationFileOptions.EndOfLine
};
}

Expand Down
11 changes: 7 additions & 4 deletions Src/CSharpier.Tests/OptionsProviderTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,13 +50,14 @@ public async Task Should_Return_Json_Extension_Options()
"c:/test/.csharpierrc.json",
@"{
""printWidth"": 10,
""preprocessorSymbolSets"": [""1,2"", ""3""]
""endOfLine"": ""crlf""
}"
);

var result = await context.CreateProviderAndGetOptionsFor("c:/test", "c:/test/test.cs");

result.Width.Should().Be(10);
result.EndOfLine.Should().Be(EndOfLine.CRLF);
}

[TestCase("yaml")]
Expand All @@ -68,15 +69,14 @@ public async Task Should_Return_Yaml_Extension_Options(string extension)
$"c:/test/.csharpierrc.{extension}",
@"
printWidth: 10
preprocessorSymbolSets:
- 1,2
- 3
endOfLine: crlf
"
);

var result = await context.CreateProviderAndGetOptionsFor("c:/test", "c:/test/test.cs");

result.Width.Should().Be(10);
result.EndOfLine.Should().Be(EndOfLine.CRLF);
}

[TestCase("{ \"printWidth\": 10 }")]
Expand Down Expand Up @@ -203,6 +203,7 @@ public async Task Should_Support_EditorConfig_Basic()
indent_style = space
indent_size = 2
max_line_length = 10
end_of_line = crlf
"
);

Expand All @@ -211,6 +212,7 @@ public async Task Should_Support_EditorConfig_Basic()
result.UseTabs.Should().BeFalse();
result.TabWidth.Should().Be(2);
result.Width.Should().Be(10);
result.EndOfLine.Should().Be(EndOfLine.CRLF);
}

[TestCase("tab_width")]
Expand Down Expand Up @@ -459,6 +461,7 @@ private static void ShouldHaveDefaultOptions(PrinterOptions printerOptions)
printerOptions.Width.Should().Be(100);
printerOptions.TabWidth.Should().Be(4);
printerOptions.UseTabs.Should().BeFalse();
printerOptions.EndOfLine.Should().Be(EndOfLine.Auto);
}

private class TestContext
Expand Down
2 changes: 1 addition & 1 deletion Src/CSharpier/PrinterOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ internal class PrinterOptions
public bool UseTabs { get; set; }
public int TabWidth { get; set; } = 4;
public int Width { get; set; } = 100;
public EndOfLine EndOfLine { get; init; } = EndOfLine.Auto;
public EndOfLine EndOfLine { get; set; } = EndOfLine.Auto;
public bool TrimInitialLines { get; init; } = true;

public const int WidthUsedByTests = 100;
Expand Down

0 comments on commit 2ad4e5d

Please sign in to comment.