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

Support passing an editorconfig to --config-path #1460

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
23 changes: 23 additions & 0 deletions Src/CSharpier.Cli.Tests/CliTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -133,6 +133,29 @@ public async Task Should_Support_Config_Path()
result.Should().Be("var myVariable =\n someLongValue;\n");
}

[Test]
public async Task Should_Support_Config_Path_With_Editorconfig()
{
const string fileContent = "var myVariable = someLongValue;";
var fileName = "TooWide.cs";
await this.WriteFileAsync(fileName, fileContent);
await this.WriteFileAsync(
"config/.editorconfig",
"""
[*]
max_line_length = 10
"""
);

await new CsharpierProcess()
.WithArguments("--config-path config/.editorconfig . ")
.ExecuteAsync();

var result = await this.ReadAllTextAsync(fileName);

result.Should().Be("var myVariable =\n someLongValue;\n");
}

[Test]
public async Task Should_Return_Error_When_No_DirectoryOrFile_And_Not_Piping_StdIn()
{
Expand Down
12 changes: 6 additions & 6 deletions Src/CSharpier.Cli.Tests/EditorConfig/SectionTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,28 +9,28 @@ namespace CSharpier.Cli.Tests.EditorConfig;
public class SectionTests
{
[Test]
public void Test1()
public void BasicWildcardGlob()
{
var path = "/test/test.cs";
var result = new Section(new SectionData("*.cs"), "/test").IsMatch(path);
var result = new Section(new SectionData("*.cs"), "/test").IsMatch(path, false);

result.Should().BeTrue();
}

[Test]
public void Test2()
public void BasicGroupGlob()
{
var path = "/test/test.cs";
var result = new Section(new SectionData("*.{cs}"), "/test").IsMatch(path);
var result = new Section(new SectionData("*.{cs}"), "/test").IsMatch(path, false);

result.Should().BeTrue();
}

[Test]
public void Test3()
public void GroupWithTwoOptionsGlob()
{
var path = "/test/test.cs";
var result = new Section(new SectionData("*.{csx,cs}"), "/test").IsMatch(path);
var result = new Section(new SectionData("*.{csx,cs}"), "/test").IsMatch(path, false);

result.Should().BeTrue();
}
Expand Down
6 changes: 4 additions & 2 deletions Src/CSharpier.Cli/EditorConfig/EditorConfigSections.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@ internal class EditorConfigSections
public required string DirectoryName { get; init; }
public required IReadOnlyCollection<Section> SectionsIncludingParentFiles { get; init; }

public PrinterOptions? ConvertToPrinterOptions(string filePath)
public PrinterOptions? ConvertToPrinterOptions(string filePath, bool ignoreDirectory)
{
var sections = this.SectionsIncludingParentFiles.Where(o => o.IsMatch(filePath)).ToList();
var sections = this
.SectionsIncludingParentFiles.Where(o => o.IsMatch(filePath, ignoreDirectory))
.ToList();
var resolvedConfiguration = new ResolvedConfiguration(sections);

var formatter =
Expand Down
10 changes: 8 additions & 2 deletions Src/CSharpier.Cli/EditorConfig/Globber.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,20 +10,26 @@ internal static class Globber
AllowSingleBraceSets = true,
};

public static GlobMatcher Create(string files, string directory)
public static GlobMatcher Create(string files, string? directory)
{
var pattern = FixGlob(files, directory);
return GlobMatcher.Create(pattern, globOptions);
}

private static string FixGlob(string glob, string directory)
private static string FixGlob(string glob, string? directory)
{
glob = glob.IndexOf('/') switch
{
-1 => "**/" + glob,
0 => glob[1..],
_ => glob,
};

if (directory is null)
{
return glob;
}

directory = directory.Replace(@"\", "/");
if (!directory.EndsWith("/"))
{
Expand Down
7 changes: 5 additions & 2 deletions Src/CSharpier.Cli/EditorConfig/Section.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ namespace CSharpier.Cli.EditorConfig;
internal class Section(SectionData section, string directory)
{
private readonly GlobMatcher matcher = Globber.Create(section.SectionName, directory);
private readonly GlobMatcher noDirectoryMatcher = Globber.Create(section.SectionName, null);

public string? IndentStyle { get; } = section.Keys["indent_style"];
public string? IndentSize { get; } = section.Keys["indent_size"];
Expand All @@ -13,8 +14,10 @@ internal class Section(SectionData section, string directory)
public string? EndOfLine { get; } = section.Keys["end_of_line"];
public string? Formatter { get; } = section.Keys["csharpier_formatter"];

public bool IsMatch(string fileName)
public bool IsMatch(string fileName, bool ignoreDirectory)
{
return this.matcher.IsMatch(fileName);
return ignoreDirectory
? this.noDirectoryMatcher.IsMatch(fileName)
: this.matcher.IsMatch(fileName);
}
}
50 changes: 37 additions & 13 deletions Src/CSharpier.Cli/Options/OptionsProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,23 @@ internal class OptionsProvider
private readonly List<CSharpierConfigData> csharpierConfigs;
private readonly IgnoreFile ignoreFile;
private readonly ConfigurationFileOptions? specifiedConfigFile;
private readonly bool hasSpecificEditorConfig;
private readonly IFileSystem fileSystem;

private OptionsProvider(
IList<EditorConfigSections> editorConfigs,
List<CSharpierConfigData> csharpierConfigs,
IgnoreFile ignoreFile,
ConfigurationFileOptions? specifiedPrinterOptions,
bool hasSpecificEditorConfig,
IFileSystem fileSystem
)
{
this.editorConfigs = editorConfigs;
this.csharpierConfigs = csharpierConfigs;
this.ignoreFile = ignoreFile;
this.specifiedConfigFile = specifiedPrinterOptions;
this.hasSpecificEditorConfig = hasSpecificEditorConfig;
this.fileSystem = fileSystem;
}

Expand All @@ -37,11 +40,20 @@ public static async Task<OptionsProvider> Create(
bool limitConfigSearch = false
)
{
var specifiedConfigFile = configPath is not null
? ConfigFileParser.Create(configPath, fileSystem, logger)
var csharpierConfigPath = configPath;
string? editorConfigPath = null;

if (configPath is not null && Path.GetFileName(configPath) == ".editorconfig")
{
csharpierConfigPath = null;
editorConfigPath = configPath;
}

var specifiedConfigFile = csharpierConfigPath is not null
? ConfigFileParser.Create(csharpierConfigPath, fileSystem, logger)
: null;

var csharpierConfigs = configPath is null
var csharpierConfigs = csharpierConfigPath is null
? ConfigFileParser.FindForDirectoryName(
directoryName,
fileSystem,
Expand All @@ -56,12 +68,19 @@ public static async Task<OptionsProvider> Create(

try
{
editorConfigSections = EditorConfigParser.FindForDirectoryName(
directoryName,
fileSystem,
limitConfigSearch,
ignoreFile
);
editorConfigSections = editorConfigPath is null
? EditorConfigParser.FindForDirectoryName(
directoryName,
fileSystem,
limitConfigSearch,
ignoreFile
)
: EditorConfigParser.FindForDirectoryName(
Path.GetDirectoryName(editorConfigPath)!,
fileSystem,
true,
ignoreFile
);
}
catch (Exception ex)
{
Expand All @@ -77,6 +96,7 @@ public static async Task<OptionsProvider> Create(
csharpierConfigs,
ignoreFile,
specifiedConfigFile,
hasSpecificEditorConfig: editorConfigPath is not null,
fileSystem
);
}
Expand All @@ -88,6 +108,11 @@ public static async Task<OptionsProvider> Create(
return this.specifiedConfigFile.ConvertToPrinterOptions(filePath);
}

if (this.hasSpecificEditorConfig)
{
return this.editorConfigs.First().ConvertToPrinterOptions(filePath, true);
}

var directoryName = this.fileSystem.Path.GetDirectoryName(filePath);

ArgumentNullException.ThrowIfNull(directoryName);
Expand All @@ -106,8 +131,7 @@ public static async Task<OptionsProvider> Create(

if (resolvedEditorConfig is not null)
{
DebugLogger.Log("has editorconfig");
return resolvedEditorConfig.ConvertToPrinterOptions(filePath);
return resolvedEditorConfig.ConvertToPrinterOptions(filePath, false);
}

if (filePath.EndsWith(".cs") || filePath.EndsWith(".csx"))
Expand All @@ -129,8 +153,8 @@ public string Serialize()
new
{
specified = this.specifiedConfigFile,
csharpierConfigs = this.csharpierConfigs,
editorConfigs = this.editorConfigs,
this.csharpierConfigs,
this.editorConfigs,
}
);
}
Expand Down
32 changes: 32 additions & 0 deletions Src/CSharpier.Tests/CommandLineFormatterTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,36 @@ public void Empty_Config_Files_Should_Log_Warning(string configFileName)
.Be($"Warning The configuration file at {configPath} was empty.");
}

[Test]
public void Should_Support_Config_Path()
{
var context = new TestContext();
var configPath = context.WhenAFileExists("config/.csharpierrc", "printWidth: 10");
context.WhenAFileExists("file1.cs", "var myVariable = someLongValue;");

this.Format(context, configPath: configPath);

context.GetFileContent("file1.cs").Should().Be("var myVariable =\n someLongValue;\n");
}

[Test]
public void Should_Support_Config_Path_With_Editor_Config()
{
var context = new TestContext();
var configPath = context.WhenAFileExists(
"config/.editorconfig",
"""
[*]
max_line_length = 10
"""
);
var fileName = context.WhenAFileExists("file1.cs", "var myVariable = someLongValue;");

this.Format(context, configPath: configPath);

context.GetFileContent(fileName).Should().Be("var myVariable =\n someLongValue;\n");
}

private FormatResult Format(
TestContext context,
bool skipWrite = false,
Expand All @@ -724,6 +754,7 @@ private FormatResult Format(
bool includeGenerated = false,
bool compilationErrorsAsWarnings = false,
string? standardInFileContents = null,
string? configPath = null,
params string[] directoryOrFilePaths
)
{
Expand All @@ -746,6 +777,7 @@ params string[] directoryOrFilePaths
.Format(
new CommandLineOptions
{
ConfigPath = configPath,
DirectoryOrFilePaths = directoryOrFilePaths,
OriginalDirectoryOrFilePaths = originalDirectoryOrFilePaths,
SkipWrite = skipWrite,
Expand Down
3 changes: 3 additions & 0 deletions docs/CLI.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,4 +153,7 @@ dotnet csharpier . --config-path "./config/.csharpierrc"

# also supports any name for the config file
dotnet csharpier . --config-path "./config/csharpier.yaml"

# as of 0.31.0 supports .editorconfig
dotnet csharpier . --config-path "./config/.editorconfig"
```
Loading