NewYour coding agent can read the release notes before it upgrades.Set up the MCP server →
NuGet · #1817 most downloaded on NuGet
CSharpier is an opinionated code formatter for c#.
Last release 4 months ago
07 Jun 2026
Release timing varies
gaps range from 8 days to 4 months
Some releases are documented
notes for 20 of the last 60 stable releases
5 versions withdrawn
withdrawn after publishing
127 years old
102 releases · first in 1900
Change xml formatting to return error when it runs into syntax error so it is consistent with c# #1854
Previously CSharpier treated an invalid xml file as a warning instead of an error. This was inconsistent with how it treated c# files.
Invalid c# or xml files are not treated as errors.
The --compilation-errors-as-warnings argument has been renamed to --syntax-errors-as-warnings and can be used to return warnings instead of errors when encountering invalid files.
CSharpier now supports two types of xml whitespace formatting strict or ignore.
By default all xml except xaml or axaml is treated as strict whitespace. See details
With strict xml whitespace handling, csharpier now keeps the closing bracket for an element on the same line instead of breaking it to a new line.
<!-- input & expected output -->
<ElementWithAttribute Attribute="AttributeValue__________________"
>TextValue</ElementWithAttribute>
<!-- 1.2.6 -->
<ElementWithAttribute Attribute="AttributeValue__________________"
>TextValue</ElementWithAttribute
>CSharpier now supports csharpier-ignore in xml files. See details
CSharpier.MSBuild can now work as a transitive dependency.
The csharpier check command now supports a --use-cache option.
Previously CSharpier required that Microsoft.AspNetCore.App be installed. CSharpier has been modified to use an HttpListener when it is run using server to remove the need for this dependency.
CSharpier was removing blank lines before csharpier-ignore comments in some cases
// input and expected output
var x = 1;
// csharpier-ignore
var y=1;
/// 1.2.6
var x = 1;
// csharpier-ignore
var y=1;CSharpier was not consistently indenting raw string literals when they were inside of simple lambdas.
// input & expected output
CallMethod(() =>
{
var someString = """
SomeRawString
""";
});
// 1.2.6
CallMethod(() =>
{
var someString = """
SomeRawString
""";
});CSharpier was incorrectly reporting a syntax validation failure when it was reordering modifiers. This is now resolved.
// when this code is modified and the modifiers are reorderd it should not report a syntax validation failure.
public class ClassName
{
// SomeComment
override public int GetHashCode() => 0;
}CSharpier was breaking the end element in some cases when it should not be.
<!-- input & expected output -->
<HtmlTypeElement
>Some long text to make things break <a href="http://url.com"
>url.com</a> more text.</HtmlTypeElement>
<!-- 1.2.6 -->
<HtmlTypeElement
>Some long text to make things break <a href="http://url.com"
>url.com</a
> more text.</HtmlTypeElement
>
CSharpier now supports csharpier-ignore comments within case statements.
switch (1)
{
case 2:
// csharpier-ignore
var unformatted = true;
break;
}CSharpier was indenting code for a simple lambda with a leading comment.
// input & expected output
this.Where___________________(
// Comment
x =>
{
return x;
}
);
// 1.2.6
this.Where___________________(
// Comment
x =>
{
return x;
});Fixed a couple more edgecases with CSharpier not handling negative ignore patterns the same way that git does
CSharpier was throwing a DirectoryNotFoundException if it were passed a path via --stdin-path with a directory that did not exist.
When CSharpier walks up the target directory looking for .gitignore files it stops when encountering a .git directory. However in a git worktree there is no directory, .git is a file. This change ensures CSharpier stops when encountering a .git file so that CSharpier behaves the same in a worktree.
IgnoreWithBasePath #1758FullSpan and source code #1737SyntaxNodeComparer #1730List in MembersForcedLine #1709Stack.Peek to reduce Pop and Push churn #1708Doc.Null check to Argument avoids Concat creation #1706Any( SyntaxTriviaList to prevent allocations #1703Full Changelog: 1.2.6...1.3.0
One column per quarter.
[Bug]: XML with DOCTYPE results in "invalid xml" warning #1809
CSharpier was not formatting xml that included a doctype and instead reporting that it was invalid xml.
<?xml version="1.0"?>
<!DOCTYPE staff SYSTEM "staff.dtd"[
<!ENTITY ent1 "es">
]>
<staff></staff>stackalloc leads to different formatting compared to new #1808When initializing a spacn using stackalloc, it was not being formatting consistently with other code
// input & expected output
Span<int> metatable = new int[]
{
00000000000000000000000001,
00000000000000000000000002,
00000000000000000000000003,
};
Span<int> metatable = stackalloc int[]
{
00000000000000000000000001,
00000000000000000000000002,
00000000000000000000000003,
};
// 1.2.5
Span<int> metatable = new int[]
{
00000000000000000000000001,
00000000000000000000000002,
00000000000000000000000003,
};
Span<int> metatable =
stackalloc int[] {
00000000000000000000000001,
00000000000000000000000002,
00000000000000000000000003,
};CSharpier was removing comments if they were the only content of an object pattern.
// input & expected output
var match = obj is {
//Property: 123
};
// 1.2.5
var match = obj is { };Full Changelog: 1.2.5...1.2.6
Performance issue when running CLI in project with pnpm on Windows #1781
1.2.4 did not properly address this
The code to determine if there is a version of CSharpier.MsBuild referenced that does not match the version of CSharpier being run has been optimized to not look in node_modules or .git. This significantly speeds things up in some setups.
Full Changelog: 1.2.4...1.2.5
Weird enter in closing when formatting XAML TextBlock #1785
CSharpier was breaking an end element to a new line when it did not need to.
<!-- input & expected output -->
<root>
<TextBlock Foreground="DarkGray">
I saw the sign. When I opened up my eyes, I saw the sign.
</TextBlock>
<TextBlock>
I saw the sign. When I opened up my eyes, I saw the sign.
</TextBlock>
</root>
<!-- 1.2.3 -->
<root>
<TextBlock Foreground="DarkGray">
I saw the sign. When I opened up my eyes, I saw the sign.
</TextBlock
>
<TextBlock>
I saw the sign. When I opened up my eyes, I saw the sign.
</TextBlock>
</root>When incorrectly ordered modifiers were preceded by a comment they were not being reordered. Thanks go to @TimothyMakkison for the contribution
// input & 1.2.3
// Comment
required public int Prop1 { get; set; }
// expected output
// Comment
public required int Prop1 { get; set; }The code to determine if there is a version of CSharpier.MsBuild referenced that does not match the version of CSharpier being run has been optimized to not look in node_modules or .git. This significantly speeds things up in some setups.
Full Changelog: 1.2.3...1.2.4
Large directories ignored in .gitignore significantly impact performance. #1776
CSharpier was enumerating all files within all subdirectories and then determining if they should be formatted or not. That logic was optimized to only enumerate files in directories that are not ignored.
Full Changelog: 1.2.2...1.2.3
The null coalescing operator is grouped in an unexpected place #1769
Null coalescing is now consistently broken thanks to a contribution from @ogaken-1
// input & expected output
var x =
someValue.SomeCall().SomeProperty.SomeProperty
?? someValue.SomeCall().SomeProperty.SomeProperty;
var x =
someValue.SomeCall().SomeProperty?.SomeCall().SomeProperty
?? someValue.SomeCall().SomeProperty?.SomeCall().SomeProperty;
var x =
someValue.SomeCall().A_______.B_______.C_______
?? someValue.SomeCall().A_______.B_______.C_______;
// 1.2.1
var x =
someValue.SomeCall().SomeProperty.SomeProperty ?? someValue
.SomeCall()
.SomeProperty.SomeProperty;
var x =
someValue.SomeCall().SomeProperty?.SomeCall().SomeProperty ?? someValue
.SomeCall()
.SomeProperty?.SomeCall()
.SomeProperty;
var x =
someValue.SomeCall().A_______.B_______.C_______ ?? someValue
.SomeCall()
.A_______.B_______.C_______;When formatting an xml file with a declaration and extra blank line was being added.
<!-- input & expected output -->
<?xml version="1.0" encoding="utf-8"?>
<Element />
<!-- 1.2.1 -->
<?xml version="1.0" encoding="utf-8"?>
<Element />The handling of ignore patterns did not properly match how git handles them. The logic has been reworked and now has tests that compare it directly to git.
If a plugin launched csharpier server without a console it would crash. This has been resolved thanks to @rcdailey
Full Changelog: 1.2.1...1.2.2
Multiline comments are now formatted in a single line in XML format #1747
The 1.2.0 release was combining xml comments into a single line.
<!-- input & expected output -->
<Root>
<!-- This is the first line comment-->
<!-- This is the second line of my comment-->
</Root>
<!-- 1.2.0 -->
<Root>
<!-- This is the first line comment--><!-- This is the second line of my comment-->
</Root>Full Changelog: 1.2.0...1.2.1
CSharpier now has a custom xml parser. XmlDocument and XDocument do not provide the original white space or the original attribute values from the fil
CSharpier now has a custom xml parser. XmlDocument and XDocument do not provide the original white space or the original attribute values from the file that was parsed which blocked the ability to implement supporting keeping empty new lines and not automatically encoding attributes.
CSharpier now supports keeping a single empty line between elements in xml files. It will remove any initial or trailing empty lines.
<!-- input -->
<Root>
<Element />
<Element />
</Root>
<!-- expected output -->
<Root>
<Element />
<Element />
</Root>
<!-- 1.1.2 -->
<Root>
<Element />
<Element />
</Root>CSharpier will no longer encode attribute values. It will leave them encoded if they are supplied that way.
<!-- input & expected output -->
<Target Name="Transform" BeforeTargets="Build">
<Message Importance="high" Text="@(MyItems->'MyItems has %(Identity)', ', ')" />
</Target>
<!-- 1.1.2 -->
<Target Name="Transform" BeforeTargets="Build">
<Message Importance="high" Text="@(MyItems->'MyItems has %(Identity)', ', ')" />
</Target>When a using contained a newline before the namespace it was not being sorted properly.
// input
using System.Net;
using
SomeProject.Bar;
using Microsoft.Extensions.Logging;
// expected output
using System.Net;
using Microsoft.Extensions.Logging;
using SomeProject.Bar;
// 1.1.2
using System.Net;
using SomeProject.Bar;
using Microsoft.Extensions.Logging;CSharpier was inserting an extra blank line in some situations with a lambda and a collection expression
// input & expected output
CallMethod(
(parameter1, parameter2) =>
[
LongValue________________________________________________,
LongValue________________________________________________,
]
);
// 1.1.2
CallMethod(
(parameter1, parameter2) =>
[
LongValue________________________________________________,
LongValue________________________________________________,
]
);CSharpier now treats .ThenInclude as a special case to improve formatting of EF queries
// input & expected output
websiteQueryable = websiteQueryable
.Include(o => o.Categories)
.Include(o => o.Categories)
.ThenInclude(c => c.Products)
.Include(o => o.Categories)
.ThenInclude(c => c.RuleManager)
.ThenInclude(rm => rm.RuleClauses)
.Include(o => o.Categories)
.ThenInclude(c => c.RuleManager)
.ThenInclude(rm => rm.RuleClauses)
.ThenInclude(rc => rc.RuleTypeOption);
// 1.1.2
websiteQueryable = websiteQueryable
.Include(o => o.Categories)
.Include(o => o.Categories)
.ThenInclude(c => c.Products)
.Include(o => o.Categories)
.ThenInclude(c => c.RuleManager)
.ThenInclude(rm => rm.RuleClauses)
.Include(o => o.Categories)
.ThenInclude(c => c.RuleManager)
.ThenInclude(rm => rm.RuleClauses)
.ThenInclude(rc => rc.RuleTypeOption);is and other operators #1601Pattern operators were being indented inconsistently with other operators. The formatting is now more consistent
// input & expected output
var b2 = (
System.Environment.SpecialFolder.AdminTools
is System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
);
var b2 =
System.Environment.SpecialFolder.AdminTools
is System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools;
var b2 =
someLongValue____________________________________________
== someOtherLongValue______________________________
+ someOtherLongValue______________________________;
var b2 = (
someLongValue____________________________________________
== someOtherLongValue______________________________
+ someOtherLongValue______________________________
);
// 1.1.2
var b2 = (
System.Environment.SpecialFolder.AdminTools
is System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
);
var b2 =
System.Environment.SpecialFolder.AdminTools
is System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools;
var b2 =
someLongValue____________________________________________
== someOtherLongValue______________________________
+ someOtherLongValue______________________________;
var b2 = (
someLongValue____________________________________________
== someOtherLongValue______________________________
+ someOtherLongValue______________________________
);Previously csharpier would attempt to format code when indent size was set to 0. This was not intentional and had a number of bugs. CSharpier now error out when encountering an indent size of 0
In some situations CSharpier.Msbuild was running into a build failure.
Full Changelog: 1.1.2...1.2.0
On longer method chains, depending on the exact chain a null coalescing expression wouldn't always be preceded by a new line.
On longer method chains, depending on the exact chain a null coalescing expression wouldn't always be preceded by a new line.
// input & expected output
var x =
someValue
.Property.CallLongMethod_____________________________________()
.CallMethod__________()
?? throw new Exception();
var x =
someValue
.Property.CallLongMethod_____________________________________()
.CallLongMethod___________________________________________________()
?? throw new Exception();
// 1.1.1
var x =
someValue
.Property.CallLongMethod_____________________________________()
.CallMethod__________() ?? throw new Exception();
var x =
someValue
.Property.CallLongMethod_____________________________________()
.CallLongMethod___________________________________________________()
?? throw new Exception();
Full Changelog: https://github.com/belav/csharpier/compare/1.1.1...1.1.2
CSharpier was throwing an exception when formating a directory contained a file without an extension.
CSharpier was throwing an exception when formating a directory contained a file without an extension.
Full Changelog: https://github.com/belav/csharpier/compare/1.1.1...1.1.1
CSharpier will no longer consider .gitignore files located above the root of the current git repository.
CSharpier will no longer consider .gitignore files located above the root of the current git repository.
There is a new option --stdin-filepath that is used to specify the filepath CSharpier should use for resolving options and ignore files.
When no path is specified via stdin-path
< in which case it is assumed to be xml.Changes were required to support the following
It is now possible to specify the path to an ignore file
dotnet csharpier format . --ignore-path .config/.csharpierignore
CSharpier now formats xaml and slnx by default without the need for configuration changes.
When formatting the following XML, CSharpier would always use the system system default for ending lines within the comment instead of the respecting the configured EOL setting.
<Element>
<!--
Comment with EOL
-->
</Element>
In the case that CSharpier had access to a sub directory but not the parent of that sub directory, it was failing with an exception. That has been resolved.
Previously the format and check commands both used the same output message. The check command now correctly reports that it checked files and did not format them.
# 1.0.3
dotnet csharpier check .
Formatted 13226 files in 21986ms.
# 1.1.0
dotnet csharpier check .
Checked 13226 files in 21986ms.
CSharpier now formats collection expressions consistently when they are in a property
// input & expected output
public class ClassName
{
public SomeObject LongValue = new
{
One = "One",
Two = "Two",
ThreeThreeThree = "ThreeThreeThree",
};
public SomeObject LongValue { get; } = new
{
One = "One",
Two = "Two",
ThreeThreeThree = "ThreeThreeThree",
};
}
// 1.0.3
public class ClassName
{
public SomeObject LongValue = new
{
One = "One",
Two = "Two",
ThreeThreeThree = "ThreeThreeThree",
};
public SomeObject LongValue { get; } =
new
{
One = "One",
Two = "Two",
ThreeThreeThree = "ThreeThreeThree",
};
}
Previously if an .editorconfig was in the .gitignore it would not be considered when determining the configuration options for formatting a given file. That behavior has been changed so it will be considered.
Full Changelog: https://github.com/belav/csharpier/compare/1.0.3...1.1.0
Switch blocks were breaking on conditions within patterns. ```c# // input and expected output switch ("") { case "" or "": break; }
Switch blocks were breaking on conditions within patterns.
// input and expected output
switch ("")
{
case "" or "":
break;
}
// 1.0.2
switch ("")
{
case ""
or "":
break;
}
CSharpier was breaking after a discard with a when, resulting in extra new lines
// input and expected output
_ = someValue switch
{
_ when KeepWhenWithDiscard() => "",
_ when KeepWhenWithDiscard_________________(
SomeObject_______________________________________________
) => "",
_ when KeepWhenWithDiscard_________________(
SomeObject_______________________________________________
) => "LongString_____________________________________________________________________",
};
// 1.0.2
_ = someValue switch
{
_ when KeepWhenWithDiscard() => "",
_
when KeepWhenWithDiscard_________________(
SomeObject_______________________________________________
) => "",
_
when KeepWhenWithDiscard_________________(
SomeObject_______________________________________________
) => "LongString_____________________________________________________________________",
};
If a query syntax linq expression contained a raw string, it could result in method invocations not breaking.
// input and expected output
(
from x in SomeMethod()
select """
someString
"""
)
.CallMethod_____________________________________________()
.CallMethod_____________________________________________();
// 1.0.2
(
from x in SomeMethod()
select """
someString
"""
).CallMethod_____________________________________________().CallMethod_____________________________________________();
Full Changelog: https://github.com/belav/csharpier/compare/1.0.2...1.0.3
CSharpier was using a naive algorithm for parsing and evaluating gitignore rules that caused significant perfomance issues. @kevinboss reworked the im
CSharpier was using a naive algorithm for parsing and evaluating gitignore rules that caused significant perfomance issues. @kevinboss reworked the implementation to drastically increate performance.
bin/ and obj/ directory content from xml formatting #1600CSharpier now excludes all files in bin/ and obj/ by default.
is #1612The following c# is valid and compiles with 9.0.300+. CSharpier was updated to properly parse it.
var x = y is y ? [] : z ?? [];
CSharpier has some issues with formatting text that contained xml comments. That has been improved.
Input & expected output
<NoWarn>
CA1031; <!-- Since this is not a library project, catching general exceptions is OK -->
IDE0005; <!-- Allow unused usings -->
</NoWarn>
1.0.1
<NoWarn
>
CA1031;
<!-- Since this is not a library project, catching general exceptions is OK -->
IDE0005;
<!-- Allow unused usings -->
</NoWarn>
CSharpier 1.0.0 introduced a regression that caused the following formatting. This is now working as expected.
// input & expected output
CallMethod(() => CallAnotherMethod______________________________________________________());
CallMethod(() =>
CallAnotherMethod______________________________________________________1()
);
CallMethod(() =>
CallAnotherMethod______________________________________________________12()
);
CallMethod(() =>
CallAnotherMethod______________________________________________________123()
);
// 1.0.0
CallMethod(() => CallAnotherMethod______________________________________________________());
CallMethod(() => CallAnotherMethod______________________________________________________1()
);
CallMethod(() => CallAnotherMethod______________________________________________________12()
);
CallMethod(() =>
CallAnotherMethod______________________________________________________123()
);
Full Changelog: https://github.com/belav/csharpier/compare/1.0.1...1.0.2
The support for .gitignore has some major performance problems when there are a large number of .gitignore files and/or ignore rules. The feature has
The support for .gitignore has some major performance problems when there are a large number of .gitignore files and/or ignore rules. The feature has been disabled for now until it can be fixed.
CSharpier.MsBuild was not properly logging errors when performing a formatting check. This would result in the build passing when files were not formatted.
Setting CSharpier_LogLevel was passing an invalid parameter of --loglevel to CSharpier, resulting in a build failure
Full Changelog: https://github.com/belav/csharpier/compare/1.0.0...1.0.1
CSharpier now formats xml files by default. It will try to format ".csproj", ".props", ".targets", ".xml", ".config" as if they were xml. \ If a file
CSharpier now formats xml files by default. It will try to format ".csproj", ".props", ".targets", ".xml", ".config" as if they were xml.
If a file is not valid xml it will be treated as a warning.
The default indent size is 2 instead of 4
@TimothyMakkison put a lot of effort into improving the performance of CSharpier. These benchmark numbers show drastic improvement for both speed and memory usage.
Baseline
| Method | Mean | Error | StdDev | Median | Gen0 | Gen1 | Gen2 | Allocated |
|------------------------------ |---------:|--------:|--------:|---------:|-----------:|----------:|----------:|----------:|
| Default_CodeFormatter_Tests | 233.3 ms | 4.63 ms | 8.23 ms | 229.7 ms | 11000.0000 | 4000.0000 | 1000.0000 | 101.41 MB |
| Default_CodeFormatter_Complex | 433.7 ms | 8.53 ms | 7.56 ms | 433.4 ms | 20000.0000 | 5000.0000 | 1000.0000 | 182.44 MB |
After Improvements
| Method | Mean | Error | StdDev | Gen0 | Gen1 | Allocated |
|------------------------------ |----------:|---------:|---------:|----------:|----------:|----------:|
| Default_CodeFormatter_Tests | 64.72 ms | 0.548 ms | 0.512 ms | 1666.6667 | 1000.0000 | 18.33 MB |
| Default_CodeFormatter_Complex | 137.83 ms | 2.730 ms | 4.708 ms | 3000.0000 | 1000.0000 | 30.78 MB |
In order to get consistency between an .editorconfig and .csharpierconfig the option TabWidth has been renamed to IndentSize. This is also a more accurate name considering by default indentation is done with spaces and not tabs.
The CLI has been reworked to use commands. This helps make it clear which arguments apply to which commands. The two common commands are below, see https://csharpier.com/docs/CLI for more details.
dotnet csharpier format .
dotnet csharpier check .
Prior to 1.0.0 the tool command was dotnet-csharpier and assembly/exe were named dotnet_csharpier.
The tool command name was changed to just csharpier
dotnet csharpier --versioncsharpier --versionThe assembly/exe names have changed to just CSharpier
CSharpier now works as follows when determining if a file should be ignored.
CSharpier now supports a --log-format argument. By default it will log with a console format.
With --log-format MsBuild CSharpier will produce logs in a format that allow jumping to files in the VisualStudio error list.
Thanks go to @moormaster for the contribution
.editorconfig file path into --config-path #1456CSharpier now supports passing a path to an .editorconfig file when using the --config-path argument.
CSharpier will now ignore any files that are in a .git folder. Previously if the .git folder happened to contain an invalid c# file CSharpier would attempt to format it and report an error.
When CSharpier server was started, it would create file watches for all of the files within the directory the tool existed in. This can lead to some systems running out of the ability to monitor more files.
CSharpier server now uses a temporary empty content root to avoid creating all file watches.
Thanks go to @chklauser for the contribution
Previously CSharpier was eagerly loading all .editorconfig files within a directory that it was asked to format. It now lazy loads them in a way that is performant and avoids loading and parsing editorconfigs that aren't needed.
// input & expected output
int x = 1;
{
int x = 2;
}
// 0.30.6
int x = 1;
{
int x = 2;
}
A statement being surrounded by parentheses affected the indentation in an inconsistent way.
// input & expected output
var b2 =
System.Environment.SpecialFolder.AdminTools
is System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools;
var b2 = (
System.Environment.SpecialFolder.AdminTools
is System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
);
// 0.30.6
var b2 =
System.Environment.SpecialFolder.AdminTools
is System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools;
var b2 = (
System.Environment.SpecialFolder.AdminTools
is System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
or System.Environment.SpecialFolder.AdminTools
);
The logic around when to break properties with attributes has been adjusted. See the example for more details
public class ClassName
{
[Obsolete]
public string Property { [Obsolete] get; [Obsolete] set; }
public int ShortProperty { get; [SomeAttribute] init; } = 20;
public int CommandTimeout
{
get;
[SomeAttribute]
[SomeOtherAttribute]
set;
}
public int CommandTimeout
{
[SomeAttribute(someValue)]
get;
}
}
When a single method in a fluent chain was commented out, csharpier would try to collapse the chain to a single line.
// input & expected output
builder
.CallMethod()
.CallMethod()
.CallMethod()
//.CallMethod()
;
// 0.30.6
builder.CallMethod().CallMethod().CallMethod()
//.CallMethod()
;
In some cases CSharpier was breaking an invocation chain when it should not.
// input & expected output
// CommentOnGenericDoesNotBreakChain
SomeObject<SomeThing>.SomeProperty.SomeOtherProperty = 1;
// CommentOnGenericDoesNotBreakChain
SomeObject<SomeThing>.SomeProperty.CallMethod();
// 0.30.6
// CommentOnGenericDoesNotBreakChain
SomeObject<SomeThing>
.SomeProperty
.SomeOtherProperty = 1;
// CommentOnGenericDoesNotBreakChain
SomeObject<SomeThing>.SomeProperty.CallMethod();
CSharpier was breaking and indenting a parameter when it had a comment
// input & expected output
public void SomeMethod(
// Some Comment does not indent parameter
[SomeAttribute] string someParameter
) { }
// 0.30.6
public void SomeMethod(
// Some Comment does not indent parameter
[SomeAttribute]
string someParameter
) { }
CSharpier was keeping a method chain on a single line if it was invoked on a switch expression within parentheses.
// input & expected output
(
someValue switch
{
someValue => 1,
_ => 2,
}
)
.SomeLongMethodCall______________________________()
.SomeLongMethodCall______________________________()
.SomeLongMethodCall______________________________();
// 0.30.6
(
someValue switch
{
someValue => 1,
_ => 2,
}
).SomeLongMethodCall______________________________().SomeLongMethodCall______________________________().SomeLongMethodCall______________________________();
CSharpier was not formatting all lambda expressions consistently when they were the single argument to a method call.
// input & expected output
CallMethod(() =>
CallOtherMethod___________________________________________________________()
);
CallMethod(() =>
CallLongMethod_________________________________()
.ThenAnotherMethod_____________________________________()
);
// 0.30.6
CallMethod(() =>
CallOtherMethod___________________________________________________________()
);
CallMethod(
() =>
CallLongMethod_________________________________()
.ThenAnotherMethod_____________________________________()
);
When a member has documentation comments, any empty lines after those comments and before the member are now removed.
// input
/// <summary>Remove the lines after the summary</summary>
public bool SomeField1;
// output
/// <summary>Remove the lines after the summary</summary>
public bool SomeField1;
CSharpier was indenting the final non-content line within a raw string. It now leaves them dedented to keep it consistent with other non-content lines.
MakeSureBothNonContentLinesHereStayTrimmed(
$"""
"""
);
Full Changelog: https://github.com/belav/csharpier/compare/0.30.6...1.0.0
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
```c# // input enum MyEnum { First, Second // the second value }
// input
enum MyEnum
{
First,
Second // the second value
}
// 0.30.5
enum MyEnum
{
First,
Second // the second value
,
}
// 0.30.6
enum MyEnum
{
First,
Second, // the second value
}
Full Changelog: https://github.com/belav/csharpier/compare/0.30.5...0.30.6
When a file ended in a comment and that comment had multiple blank lines before it, a new blank line was being added each time it was formatted. // in
When a file ended in a comment and that comment had multiple blank lines before it, a new blank line was being added each time it was formatted. // input
// input
namespace MyCompany.MyNamespace;
// Comment block
// 0.30.4
namespace MyCompany.MyNamespace;
// Comment block
// 0.30.5
namespace MyCompany.MyNamespace;
// Comment block
**Full Changelog**: https://github.com/belav/csharpier/compare/0.30.4...0.30.5
# 0.30.4
## What's Changed
### Formatting deletes `unsafe` modifier [#1416](https://github.com/belav/csharpier/issues/1416)
Formatting a using directive with an unsafe modifier resulted in the lose of the unsafe keyword
```c#
// input & expected output
using unsafe NvapiQueryInterface = delegate* unmanaged[Cdecl]<uint, nint>;
// 0.30.3
using NvapiQueryInterface = delegate* unmanaged[Cdecl]<uint, nint>;
In some cases if a file ended with a comment, CSharpier would add a new extra blank line above the comment each time it formatted the file
// input & expected outpet
using System;
namespace MyCompany.MyNamespace;
// Comment block
// 0.30.3
using System;
namespace MyCompany.MyNamespace;
// Comment block
Full Changelog: https://github.com/belav/csharpier/compare/0.30.3...0.30.4
The changes for 1311 caused CSharpier.MsBuild to not report unformatted files as errors on linux.
Thanks go to @PetSerAl for the fix
Full Changelog: https://github.com/belav/csharpier/compare/0.30.2...0.30.3
Use current dotnet binary from DOTNET_HOST_PATH instead of just dotnet.
// input & expected output
Dictionary<string, string[]> dictionary = new()
{
{
"Key",
[
"SomeValue__________________________________________",
"SomeValue__________________________________________",
]
},
};
// 0.30.1
Dictionary<string, string[]> dictionary = new()
{
{
"Key",
[
"SomeValue__________________________________________",
"SomeValue__________________________________________",
]
},
};
With the following code, CSharpier will add a trailing comma before the trailing comment.
CSharpier's syntax tree validation was incorrectly reporting this as a failure.
// input
var someObject = new SomeObject()
{
Property1 = 1,
Property2 = 2 // Trailing Comment
};
// output
var someObject = new SomeObject()
{
Property1 = 1,
Property2 = 2, // Trailing Comment
};
Full Changelog: https://github.com/belav/csharpier/compare/0.30.1...0.30.2
Revert tool command back to dotnet-csharpier, it was supposed to be changed to csharpier for 1.0.0
The CSharpier dotnet tool no longer supports net6 & net7.
CSharpier now supports dotnet 9 along with formatting all C# 13 language features.
Implicit and explicit object initialization with constructors was not formatted consistently
// input & expected output
SomeObject someObject = new(
someLongParameter___________________,
someLongParameter___________________
)
{
Property = longValue_______________________________________________________________________,
};
SomeObject someObject = new SomeObject(
someLongParameter___________________,
someLongParameter___________________
)
{
Property = longValue_______________________________________________________________________,
};
// 0.29.2
SomeObject someObject =
new(someLongParameter___________________, someLongParameter___________________)
{
Property = longValue_______________________________________________________________________,
};
SomeObject someObject = new SomeObject(
someLongParameter___________________,
someLongParameter___________________
)
{
Property = longValue_______________________________________________________________________,
};
When an interpolated verbatim string contained line breaks, the code within the interpolations would contain extra spaces.
// input & expected output
var someStringWithLineBreakAndLongValue =
$@"
{someValue.GetValue().Name} someLongText________________________________________________________________";
// 0.29.2
var someStringWithLineBreakAndLongValue =
$@"
{someValue .GetValue() .Name} someLongText________________________________________________________________";
CSharpier would insert a trailing comma after a trailing comment and format the end result poorly.
// input
var someObject = new SomeObject()
{
Property1 = 1,
Property2 = 2 // Trailing Comment
};
// 0.29.2
var someObject = new SomeObject()
{
Property1 = 1,
Property2 =
2 // Trailing Comment
,
};
// 0.30.0
var someObject = new SomeObject()
{
Property1 = 1,
Property2 = 2, // Trailing Comment
};
CSharpier was inserting an extra line break on a long field name followed by a collection expression to initialize it.
// input & expected output
class ClassName
{
public SomeType[] LongName____________________________________________________________________________ =
[
someLongValue___________________________________________________,
someLongValue___________________________________________________,
];
}
// 0.29.2
class ClassName
{
public SomeType[] LongName____________________________________________________________________________ =
[
someLongValue___________________________________________________,
someLongValue___________________________________________________,
];
}
Full Changelog: https://github.com/belav/csharpier/compare/0.29.2...0.30.0
Prior to 0.29.2 CSharpier was converting any tabs within the block of a multiline comment to spaces.
public void SomeFunction()
{
/*
The following line is an example with an indent:
This line is indented by one tab. (prior to 0.29.2 this would end up as a tab followed by 4 spaces)
*/
/*
The following line is an example with an indent:
This line is indented by 4 spaces but will be converted to 1 tab (prior to 0.29.2 this would end up as a tab followed by 4 spaces)
*/
/*
The following line is an example with an indent:
This line is indented by 3 spaces but will be left as 3 spaces
*/
}
csharpier-ignore-start now supported in object initializers #1342// input & expected output
return new SomeClass
{
// csharpier-ignore-start
SomeProperty = someValue,
SomeProperty2 = someValue
// csharpier-ignore-end
};
// 0.29.1
return new SomeClass
{
// csharpier-ignore-start
SomeProperty = someValue,
SomeProperty2 = someValue
// csharpier-ignore-end
};
// input & expected output
CallMethod(
(string[])
[
longerValue_____________________________________________,
longerValue_____________________________________________,
]
);
// 0.29.1
CallMethod(
(string[])
[
longerValue_____________________________________________,
longerValue_____________________________________________,
]
);
As of 0.29.0 CSharpier could format non-standard file extensions, but only if configured in the csharpierrc file. This is now supported with an .editorconfig
[*.cst]
csharpier_formatter = csharp
indent_style = space
indent_size = 2
max_line_length = 80
Full Changelog: https://github.com/belav/csharpier/compare/0.29.1...0.29.2
CSharpier now sorts _ to the bottom of usings.
using SomeCompany.MWord;
using SomeCompany.ZWord;
using SomeCompany._Word;
CSharpier Server now uses a log file name based on the port that it is starting on to avoid concurrency issues trying to access the same log file
Full Changelog: https://github.com/belav/csharpier/compare/0.29.0...0.29.1
Prior to 0.29.0 if csharpier encountered a file that could not be compiled it would treat it as a warning and exit with a code of 0.
As of 0.29.0 a file that cannot be compiled is now treated as an error and csharpier will exit with code 1
CSharpier will now add trailing commas automatically where appropriate. It will collapse to a single line and remove the trailing comma in cases where everything fits on one line.
// input
public enum SomeEnum
{
Value1,
Value2
}
string[] someArray = new string[]
{
someLongValue_____________________________________________,
someLongValue_____________________________________________
};
string[] someArray = new string[]
{
someValue,
someValue,
};
// 0.29.0
public enum SomeEnum
{
Value1,
Value2,
}
string[] someArray = new string[]
{
someLongValue_____________________________________________,
someLongValue_____________________________________________,
}
string[] someArray = new string[] { someValue, someValue };
Many thanks go to @dawust for the contribution.
Prior to 0.29.0 csharpier would only format files with an extension of .cs or .csx. It is now possible to configure csharpier to format other files extensions, and to specify configuration options per file extension. See https://csharpier.com/docs/Configuration#configuration-overrides for more details.
// input & expected output
CallMethod(_ =>
[
LongValue________________________________________________,
LongValue________________________________________________,
]
);
// 0.28.2
CallMethod(_ =>
[
LongValue________________________________________________,
LongValue________________________________________________,
]
);
Prior to 0.29.0 csharpier would break before the => in switch expression arms. It now breaks after them to be consistent with other lambda expressions.
// 0.28.2
return someEnum switch
{
Value1 => someOtherValue,
Value2
or Value3
=> someValue________________________________________________________________________,
Value4
=> someValue_____________________________________________________________________________,
};
// 0.29.0
return someEnum switch
{
Value1 => someOtherValue,
Value2 or Value3 =>
someValue________________________________________________________________________,
Value4 =>
someValue_____________________________________________________________________________,
};
Empty collection expression initializers formatting was including a break plus indentation resulting in poor formatting.
// 0.28.2
var someObject = new List<(
int Field1__________________________________,
int Field2__________________________________
)>
{
};
// 0.29.0
var someObject = new List<(
int Field1__________________________________,
int Field2__________________________________
)>
{ };
Thanks go to @Rudomitori for the contribution
Improved formatting for short expression arms that have a leading comment.
// 0.28.2
return someValue switch
{
// comment
Some.One
=> 1,
Some.Two => 2,
};
return someValue switch
{
Some.One => 1,
// comment
Some.Two
=> 2,
};
// 0.29.0
return someValue switch
{
// comment
Some.One => 1,
Some.Two => 2,
};
return someValue switch
{
Some.One => 1,
// comment
Some.Two => 2,
};
Fixed bug with comments on a ternary expression that resulted in invalid code.
// input & expected output
public string TrailingComment = someCondition
? $"empty" // trailing comment
: someString;
// 0.28.2
public string TrailingComment = someCondition ? $"empty" // trailing comment : someString;
Improved formatting of indexed properties that contained attributes.
// input & expected output
public class ClassName
{
public string this[
[SomeAttribute] int a________________________________,
[SomeAttribute] int b________________________________
] => someValue;
}
// 0.28.2
public class ClassName
{
public string this[[SomeAttribute] int a________________________________, [SomeAttribute]
int b________________________________] => someValue;
}
CSharpier_Check when already set. #1314Fixed a bug with csharpier.msbuild where it would overwrite the CSharpier_Check value in some cases.
Thanks go to @PetSerAl for the contribution
The help text for the cli has been improved to better indicate when directoryOrFile is required.
Thanks go to @marcinjahn for the contribution
CSharpier now considers full width unicode characters such as 가 to be 2 spaces wide when determining how to format code.
Full Changelog: https://github.com/belav/csharpier/compare/0.28.2...0.29.0
dotnet csharpier fails when subdirectory is inaccessible #1240When running the following CSharpier would look for config files in subdirectories of the pwd. This could lead to exceptions if some of those directories were inaccessible.
echo "namespace Foo { public class Bar { public string Baz {get;set;}}}" | dotnet csharpier
Thanks go to @jamesfoster for reporting the issue.
Full Changelog: https://github.com/belav/csharpier/compare/0.28.1...0.28.2
When CSharpier encountered an invalid .editorconfig file, it would throw an exception and not format files. These files could appear in 3rd party code (for example within node_modules). CSharpier now ignores invalid lines in .editorconfigs
Thanks go to @K0Te for reporting the issue
Full Changelog: https://github.com/belav/csharpier/compare/0.28.0...0.28.1
In some cases of method chains, the first invocation would end up dedented.
// 0.27.3
o.Property.CallMethod(
someParameter_____________________________,
someParameter_____________________________
)
.CallMethod()
.CallMethod();
// 0.28.0
o.Property.CallMethod(
someParameter_____________________________,
someParameter_____________________________
)
.CallMethod()
.CallMethod();
If a case statement started with a block it would get an extra new line
// 0.27.3
switch (someValue)
{
case 0:
{
// dedented because the only statement is a block
break;
}
case 1:
{
// indented because there are two statements, a block then a break
}
break;
}
// 0.28.0
// 0.27.3
switch (someValue)
{
case 0:
{
// dedented because the only statement is a block
break;
}
case 1:
{
// indented because there are two statements, a block then a break
}
break;
}
Thanks go to @emberTrev for reporting the bug.
The editorconfig parsing was not handling glob patterns that contained braces.
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
[*.cs] indent_size = 4 tab_width = 4
[*.cs] indent_size = 4 tab_width = 4
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Nothing published for this version
Your coding agent can read these notes before it upgrades. Set up the MCP server →