<chore> CodeQuality

This commit is contained in:
nsnail 2022-12-15 10:25:28 +08:00
commit 0e07289747
53 changed files with 1004 additions and 819 deletions

View File

@ -1,12 +1,27 @@
root = true
[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
end_of_line = lf
ij_xml_attribute_wrap = off
ij_xml_text_wrap = off
indent_size = 4
indent_style = space
insert_final_newline = false
trim_trailing_whitespace = true
[*.cs]
dotnet_analyzer_diagnostic.severity = warning
dotnet_diagnostic.CA1707.severity = none
dotnet_diagnostic.CA5350.severity = none
dotnet_diagnostic.CA5351.severity = none
dotnet_diagnostic.IDE0008.severity = none
dotnet_diagnostic.IDE0017.severity = none
dotnet_diagnostic.IDE0048.severity = none
dotnet_diagnostic.IDE0055.severity = none
dotnet_diagnostic.IDE0058.severity = none
dotnet_diagnostic.IDE0160.severity = none
# ReSharper properties
resharper_align_linq_query = true
@ -23,23 +38,27 @@ resharper_align_multline_type_parameter_constrains = true
resharper_align_multline_type_parameter_list = true
resharper_align_tuple_components = true
resharper_allow_comment_after_lbrace = true
resharper_blank_lines_before_single_line_comment = 1
resharper_csharp_empty_block_style = together_same_line
resharper_csharp_outdent_commas = true
resharper_csharp_place_type_constraints_on_same_line = false
resharper_csharp_stick_comment = false
resharper_csharp_wrap_before_comma = true
resharper_indent_nested_foreach_stmt = true
resharper_indent_nested_for_stmt = true
resharper_indent_nested_foreach_stmt = true
resharper_indent_nested_while_stmt = true
resharper_indent_preprocessor_if = usual_indent
resharper_indent_preprocessor_other = usual_indent
resharper_int_align = true
resharper_keep_existing_arrangement = false
resharper_place_linq_into_on_new_line = false
resharper_place_simple_embedded_statement_on_same_line = false
resharper_place_simple_switch_expression_on_single_line = true
resharper_wrap_before_eq = true
resharper_wrap_chained_method_calls = chop_if_long
resharper_wrap_switch_expression = chop_if_long
# Microsoft .NET properties
csharp_indent_braces = false
csharp_new_line_before_open_brace = local_functions, methods, types

17
CodeQuality.props Normal file
View File

@ -0,0 +1,17 @@
<Project>
<PropertyGroup>
<CodeAnalysisRuleSet>../StyleCopAnalyzers.ruleset</CodeAnalysisRuleSet>
<CodeAnalysisTreatWarningsAsErrors>true</CodeAnalysisTreatWarningsAsErrors>
<EnforceCodeStyleInBuild>true</EnforceCodeStyleInBuild>
<MSBuildTreatWarningsAsErrors>true</MSBuildTreatWarningsAsErrors>
<MSBuildWarningsAsErrors>true</MSBuildWarningsAsErrors>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>
<WarningsAsErrors>true</WarningsAsErrors>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@ -1,8 +0,0 @@
<Project>
<ItemGroup>
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.50.0.58025">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
</ItemGroup>
</Project>

View File

@ -1,217 +1,221 @@
<?xml version="1.0"?>
<RuleSet Name="StyleCop.Analyzers rules with default action" Description="StyleCop.Analyzers with default action. Rules with IsEnabledByDefault = false are disabled." ToolsVersion="14.0">
<RuleSet Name="StyleCop.Analyzers rules with default action"
Description="StyleCop.Analyzers with default action. Rules with IsEnabledByDefault = false are disabled."
ToolsVersion="14.0">
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpecialRules">
<Rule Id="SA0001" Action="Warning" /> <!-- XML comment analysis disabled -->
<Rule Id="SA0002" Action="Warning" /> <!-- Invalid settings file -->
<Rule Id="SA0001" Action="Warning"/> <!-- XML comment analysis disabled -->
<Rule Id="SA0002" Action="Warning"/> <!-- Invalid settings file -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpacingRules">
<Rule Id="SA1000" Action="Warning" /> <!-- Keywords should be spaced correctly -->
<Rule Id="SA1001" Action="None" /> <!-- Commas should be spaced correctly -->
<Rule Id="SA1002" Action="Warning" /> <!-- Semicolons should be spaced correctly -->
<Rule Id="SA1003" Action="Warning" /> <!-- Symbols should be spaced correctly -->
<Rule Id="SA1004" Action="Warning" /> <!-- Documentation lines should begin with single space -->
<Rule Id="SA1005" Action="None" /> <!-- Single line comments should begin with single space -->
<Rule Id="SA1006" Action="Warning" /> <!-- Preprocessor keywords should not be preceded by space -->
<Rule Id="SA1007" Action="Warning" /> <!-- Operator keyword should be followed by space -->
<Rule Id="SA1008" Action="Warning" /> <!-- Opening parenthesis should be spaced correctly -->
<Rule Id="SA1009" Action="Warning" /> <!-- Closing parenthesis should be spaced correctly -->
<Rule Id="SA1010" Action="Warning" /> <!-- Opening square brackets should be spaced correctly -->
<Rule Id="SA1011" Action="Warning" /> <!-- Closing square brackets should be spaced correctly -->
<Rule Id="SA1012" Action="Warning" /> <!-- Opening braces should be spaced correctly -->
<Rule Id="SA1013" Action="Warning" /> <!-- Closing braces should be spaced correctly -->
<Rule Id="SA1014" Action="Warning" /> <!-- Opening generic brackets should be spaced correctly -->
<Rule Id="SA1015" Action="Warning" /> <!-- Closing generic brackets should be spaced correctly -->
<Rule Id="SA1016" Action="Warning" /> <!-- Opening attribute brackets should be spaced correctly -->
<Rule Id="SA1017" Action="Warning" /> <!-- Closing attribute brackets should be spaced correctly -->
<Rule Id="SA1018" Action="Warning" /> <!-- Nullable type symbols should be spaced correctly -->
<Rule Id="SA1019" Action="Warning" /> <!-- Member access symbols should be spaced correctly -->
<Rule Id="SA1020" Action="Warning" /> <!-- Increment decrement symbols should be spaced correctly -->
<Rule Id="SA1021" Action="Warning" /> <!-- Negative signs should be spaced correctly -->
<Rule Id="SA1022" Action="Warning" /> <!-- Positive signs should be spaced correctly -->
<Rule Id="SA1023" Action="Warning" /> <!-- Dereference and access of symbols should be spaced correctly -->
<Rule Id="SA1024" Action="Warning" /> <!-- Colons should be spaced correctly -->
<Rule Id="SA1025" Action="None" /> <!-- Code should not contain multiple whitespace in a row -->
<Rule Id="SA1026" Action="Warning" /> <!-- Code should not contain space after new or stackalloc keyword in implicitly typed array allocation -->
<Rule Id="SA1027" Action="Warning" /> <!-- Use tabs correctly -->
<Rule Id="SA1028" Action="Warning" /> <!-- Code should not contain trailing whitespace -->
<Rule Id="SA1000" Action="Warning"/> <!-- Keywords should be spaced correctly -->
<Rule Id="SA1001" Action="None"/> <!-- Commas should be spaced correctly -->
<Rule Id="SA1002" Action="Warning"/> <!-- Semicolons should be spaced correctly -->
<Rule Id="SA1003" Action="Warning"/> <!-- Symbols should be spaced correctly -->
<Rule Id="SA1004" Action="Warning"/> <!-- Documentation lines should begin with single space -->
<Rule Id="SA1005" Action="None"/> <!-- Single line comments should begin with single space -->
<Rule Id="SA1006" Action="Warning"/> <!-- Preprocessor keywords should not be preceded by space -->
<Rule Id="SA1007" Action="Warning"/> <!-- Operator keyword should be followed by space -->
<Rule Id="SA1008" Action="None"/> <!-- Opening parenthesis should be spaced correctly -->
<Rule Id="SA1009" Action="Warning"/> <!-- Closing parenthesis should be spaced correctly -->
<Rule Id="SA1010" Action="Warning"/> <!-- Opening square brackets should be spaced correctly -->
<Rule Id="SA1011" Action="Warning"/> <!-- Closing square brackets should be spaced correctly -->
<Rule Id="SA1012" Action="Warning"/> <!-- Opening braces should be spaced correctly -->
<Rule Id="SA1013" Action="Warning"/> <!-- Closing braces should be spaced correctly -->
<Rule Id="SA1014" Action="Warning"/> <!-- Opening generic brackets should be spaced correctly -->
<Rule Id="SA1015" Action="Warning"/> <!-- Closing generic brackets should be spaced correctly -->
<Rule Id="SA1016" Action="Warning"/> <!-- Opening attribute brackets should be spaced correctly -->
<Rule Id="SA1017" Action="Warning"/> <!-- Closing attribute brackets should be spaced correctly -->
<Rule Id="SA1018" Action="Warning"/> <!-- Nullable type symbols should be spaced correctly -->
<Rule Id="SA1019" Action="Warning"/> <!-- Member access symbols should be spaced correctly -->
<Rule Id="SA1020" Action="Warning"/> <!-- Increment decrement symbols should be spaced correctly -->
<Rule Id="SA1021" Action="Warning"/> <!-- Negative signs should be spaced correctly -->
<Rule Id="SA1022" Action="Warning"/> <!-- Positive signs should be spaced correctly -->
<Rule Id="SA1023" Action="Warning"/> <!-- Dereference and access of symbols should be spaced correctly -->
<Rule Id="SA1024" Action="Warning"/> <!-- Colons should be spaced correctly -->
<Rule Id="SA1025" Action="None"/> <!-- Code should not contain multiple whitespace in a row -->
<Rule Id="SA1026" Action="Warning"/> <!-- Code should not contain space after new or stackalloc keyword in implicitly typed array allocation -->
<Rule Id="SA1027" Action="Warning"/> <!-- Use tabs correctly -->
<Rule Id="SA1028" Action="Warning"/> <!-- Code should not contain trailing whitespace -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.ReadabilityRules">
<Rule Id="SA1100" Action="Warning" /> <!-- Do not prefix calls with base unless local implementation exists -->
<Rule Id="SA1101" Action="None" /> <!-- Prefix local calls with this -->
<Rule Id="SA1102" Action="Warning" /> <!-- Query clause should follow previous clause -->
<Rule Id="SA1103" Action="Warning" /> <!-- Query clauses should be on separate lines or all on one line -->
<Rule Id="SA1104" Action="Warning" /> <!-- Query clause should begin on new line when previous clause spans multiple lines -->
<Rule Id="SA1105" Action="Warning" /> <!-- Query clauses spanning multiple lines should begin on own line -->
<Rule Id="SA1106" Action="Warning" /> <!-- Code should not contain empty statements -->
<Rule Id="SA1107" Action="Warning" /> <!-- Code should not contain multiple statements on one line -->
<Rule Id="SA1108" Action="Warning" /> <!-- Block statements should not contain embedded comments -->
<Rule Id="SA1109" Action="None" /> <!-- Block statements should not contain embedded regions -->
<Rule Id="SA1110" Action="Warning" /> <!-- Opening parenthesis or bracket should be on declaration line -->
<Rule Id="SA1111" Action="Warning" /> <!-- Closing parenthesis should be on line of last parameter -->
<Rule Id="SA1112" Action="Warning" /> <!-- Closing parenthesis should be on line of opening parenthesis -->
<Rule Id="SA1113" Action="Warning" /> <!-- Comma should be on the same line as previous parameter -->
<Rule Id="SA1114" Action="Warning" /> <!-- Parameter list should follow declaration -->
<Rule Id="SA1115" Action="Warning" /> <!-- Parameter should follow comma -->
<Rule Id="SA1116" Action="Warning" /> <!-- Split parameters should start on line after declaration -->
<Rule Id="SA1117" Action="Warning" /> <!-- Parameters should be on same line or separate lines -->
<Rule Id="SA1118" Action="Warning" /> <!-- Parameter should not span multiple lines -->
<Rule Id="SA1120" Action="None" /> <!-- Comments should contain text -->
<Rule Id="SA1121" Action="Warning" /> <!-- Use built-in type alias -->
<Rule Id="SA1122" Action="Warning" /> <!-- Use string.Empty for empty strings -->
<Rule Id="SA1123" Action="Warning" /> <!-- Do not place regions within elements -->
<Rule Id="SA1124" Action="Warning" /> <!-- Do not use regions -->
<Rule Id="SA1125" Action="Warning" /> <!-- Use shorthand for nullable types -->
<Rule Id="SA1126" Action="None" /> <!-- Prefix calls correctly -->
<Rule Id="SA1127" Action="Warning" /> <!-- Generic type constraints should be on their own line -->
<Rule Id="SA1128" Action="Warning" /> <!-- Put constructor initializers on their own line -->
<Rule Id="SA1129" Action="Warning" /> <!-- Do not use default value type constructor -->
<Rule Id="SA1130" Action="Warning" /> <!-- Use lambda syntax -->
<Rule Id="SA1131" Action="Warning" /> <!-- Use readable conditions -->
<Rule Id="SA1132" Action="Warning" /> <!-- Do not combine fields -->
<Rule Id="SA1133" Action="Warning" /> <!-- Do not combine attributes -->
<Rule Id="SA1134" Action="Warning" /> <!-- Attributes should not share line -->
<Rule Id="SA1135" Action="Warning" /> <!-- Using directives should be qualified -->
<Rule Id="SA1136" Action="Warning" /> <!-- Enum values should be on separate lines -->
<Rule Id="SA1137" Action="Warning" /> <!-- Elements should have the same indentation -->
<Rule Id="SA1139" Action="Warning" /> <!-- Use literal suffix notation instead of casting -->
<Rule Id="SX1101" Action="None" /> <!-- Do not prefix local calls with 'this.' -->
<Rule Id="SA1100" Action="Warning"/> <!-- Do not prefix calls with base unless local implementation exists -->
<Rule Id="SA1101" Action="None"/> <!-- Prefix local calls with this -->
<Rule Id="SA1102" Action="Warning"/> <!-- Query clause should follow previous clause -->
<Rule Id="SA1103" Action="Warning"/> <!-- Query clauses should be on separate lines or all on one line -->
<Rule Id="SA1104" Action="Warning"/> <!-- Query clause should begin on new line when previous clause spans multiple lines -->
<Rule Id="SA1105" Action="Warning"/> <!-- Query clauses spanning multiple lines should begin on own line -->
<Rule Id="SA1106" Action="Warning"/> <!-- Code should not contain empty statements -->
<Rule Id="SA1107" Action="Warning"/> <!-- Code should not contain multiple statements on one line -->
<Rule Id="SA1108" Action="Warning"/> <!-- Block statements should not contain embedded comments -->
<Rule Id="SA1109" Action="Warning"/> <!-- Block statements should not contain embedded regions -->
<Rule Id="SA1110" Action="Warning"/> <!-- Opening parenthesis or bracket should be on declaration line -->
<Rule Id="SA1111" Action="Warning"/> <!-- Closing parenthesis should be on line of last parameter -->
<Rule Id="SA1112" Action="Warning"/> <!-- Closing parenthesis should be on line of opening parenthesis -->
<Rule Id="SA1113" Action="None"/> <!-- Comma should be on the same line as previous parameter -->
<Rule Id="SA1114" Action="Warning"/> <!-- Parameter list should follow declaration -->
<Rule Id="SA1115" Action="Warning"/> <!-- Parameter should follow comma -->
<Rule Id="SA1116" Action="Warning"/> <!-- Split parameters should start on line after declaration -->
<Rule Id="SA1117" Action="None"/> <!-- Parameters should be on same line or separate lines -->
<Rule Id="SA1118" Action="Warning"/> <!-- Parameter should not span multiple lines -->
<Rule Id="SA1120" Action="None"/> <!-- Comments should contain text -->
<Rule Id="SA1121" Action="Warning"/> <!-- Use built-in type alias -->
<Rule Id="SA1122" Action="Warning"/> <!-- Use string.Empty for empty strings -->
<Rule Id="SA1123" Action="Warning"/> <!-- Do not place regions within elements -->
<Rule Id="SA1124" Action="Warning"/> <!-- Do not use regions -->
<Rule Id="SA1125" Action="Warning"/> <!-- Use shorthand for nullable types -->
<Rule Id="SA1126" Action="Warning"/> <!-- Prefix calls correctly -->
<Rule Id="SA1127" Action="Warning"/> <!-- Generic type constraints should be on their own line -->
<Rule Id="SA1128" Action="Warning"/> <!-- Put constructor initializers on their own line -->
<Rule Id="SA1129" Action="Warning"/> <!-- Do not use default value type constructor -->
<Rule Id="SA1130" Action="Warning"/> <!-- Use lambda syntax -->
<Rule Id="SA1131" Action="Warning"/> <!-- Use readable conditions -->
<Rule Id="SA1132" Action="Warning"/> <!-- Do not combine fields -->
<Rule Id="SA1133" Action="Warning"/> <!-- Do not combine attributes -->
<Rule Id="SA1134" Action="None"/> <!-- Attributes should not share line -->
<Rule Id="SA1135" Action="Warning"/> <!-- Using directives should be qualified -->
<Rule Id="SA1136" Action="Warning"/> <!-- Enum values should be on separate lines -->
<Rule Id="SA1137" Action="Warning"/> <!-- Elements should have the same indentation -->
<Rule Id="SA1139" Action="Warning"/> <!-- Use literal suffix notation instead of casting -->
<Rule Id="SX1101" Action="Warning"/> <!-- Do not prefix local calls with 'this.' -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.OrderingRules">
<Rule Id="SA1200" Action="Warning" /> <!-- Using directives should be placed correctly -->
<Rule Id="SA1201" Action="Warning" /> <!-- Elements should appear in the correct order -->
<Rule Id="SA1202" Action="Warning" /> <!-- Elements should be ordered by access -->
<Rule Id="SA1203" Action="Warning" /> <!-- Constants should appear before fields -->
<Rule Id="SA1204" Action="Warning" /> <!-- Static elements should appear before instance elements -->
<Rule Id="SA1205" Action="Warning" /> <!-- Partial elements should declare access -->
<Rule Id="SA1206" Action="Warning" /> <!-- Declaration keywords should follow order -->
<Rule Id="SA1207" Action="Warning" /> <!-- Protected should come before internal -->
<Rule Id="SA1208" Action="Warning" /> <!-- System using directives should be placed before other using directives -->
<Rule Id="SA1209" Action="Warning" /> <!-- Using alias directives should be placed after other using directives -->
<Rule Id="SA1210" Action="Warning" /> <!-- Using directives should be ordered alphabetically by namespace -->
<Rule Id="SA1211" Action="Warning" /> <!-- Using alias directives should be ordered alphabetically by alias name -->
<Rule Id="SA1212" Action="Warning" /> <!-- Property accessors should follow order -->
<Rule Id="SA1213" Action="Warning" /> <!-- Event accessors should follow order -->
<Rule Id="SA1214" Action="Warning" /> <!-- Readonly fields should appear before non-readonly fields -->
<Rule Id="SA1216" Action="Warning" /> <!-- Using static directives should be placed at the correct location -->
<Rule Id="SA1217" Action="Warning" /> <!-- Using static directives should be ordered alphabetically -->
<Rule Id="SA1200" Action="None"/> <!-- Using directives should be placed correctly -->
<Rule Id="SA1201" Action="Warning"/> <!-- Elements should appear in the correct order -->
<Rule Id="SA1202" Action="Warning"/> <!-- Elements should be ordered by access -->
<Rule Id="SA1203" Action="Warning"/> <!-- Constants should appear before fields -->
<Rule Id="SA1204" Action="Warning"/> <!-- Static elements should appear before instance elements -->
<Rule Id="SA1205" Action="Warning"/> <!-- Partial elements should declare access -->
<Rule Id="SA1206" Action="Warning"/> <!-- Declaration keywords should follow order -->
<Rule Id="SA1207" Action="Warning"/> <!-- Protected should come before internal -->
<Rule Id="SA1208" Action="Warning"/> <!-- System using directives should be placed before other using directives -->
<Rule Id="SA1209" Action="Warning"/> <!-- Using alias directives should be placed after other using directives -->
<Rule Id="SA1210" Action="Warning"/> <!-- Using directives should be ordered alphabetically by namespace -->
<Rule Id="SA1211" Action="Warning"/> <!-- Using alias directives should be ordered alphabetically by alias name -->
<Rule Id="SA1212" Action="Warning"/> <!-- Property accessors should follow order -->
<Rule Id="SA1213" Action="Warning"/> <!-- Event accessors should follow order -->
<Rule Id="SA1214" Action="Warning"/> <!-- Readonly fields should appear before non-readonly fields -->
<Rule Id="SA1216" Action="Warning"/> <!-- Using static directives should be placed at the correct location -->
<Rule Id="SA1217" Action="Warning"/> <!-- Using static directives should be ordered alphabetically -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.NamingRules">
<Rule Id="SA1300" Action="Warning" /> <!-- Element should begin with upper-case letter -->
<Rule Id="SA1301" Action="None" /> <!-- Element should begin with lower-case letter -->
<Rule Id="SA1302" Action="Warning" /> <!-- Interface names should begin with I -->
<Rule Id="SA1303" Action="Warning" /> <!-- Const field names should begin with upper-case letter -->
<Rule Id="SA1304" Action="Warning" /> <!-- Non-private readonly fields should begin with upper-case letter -->
<Rule Id="SA1305" Action="None" /> <!-- Field names should not use Hungarian notation -->
<Rule Id="SA1306" Action="Warning" /> <!-- Field names should begin with lower-case letter -->
<Rule Id="SA1307" Action="Warning" /> <!-- Accessible fields should begin with upper-case letter -->
<Rule Id="SA1308" Action="Warning" /> <!-- Variable names should not be prefixed -->
<Rule Id="SA1309" Action="Warning" /> <!-- Field names should not begin with underscore -->
<Rule Id="SA1310" Action="None" /> <!-- Field names should not contain underscore -->
<Rule Id="SA1311" Action="Warning" /> <!-- Static readonly fields should begin with upper-case letter -->
<Rule Id="SA1312" Action="Warning" /> <!-- Variable names should begin with lower-case letter -->
<Rule Id="SA1313" Action="Warning" /> <!-- Parameter names should begin with lower-case letter -->
<Rule Id="SA1314" Action="Warning" /> <!-- Type parameter names should begin with T -->
<Rule Id="SX1309" Action="None" /> <!-- Field names should begin with underscore -->
<Rule Id="SX1309S" Action="None" /> <!-- Static field names should begin with underscore -->
<Rule Id="SA1300" Action="Warning"/> <!-- Element should begin with upper-case letter -->
<Rule Id="SA1301" Action="Warning"/> <!-- Element should begin with lower-case letter -->
<Rule Id="SA1302" Action="Warning"/> <!-- Interface names should begin with I -->
<Rule Id="SA1303" Action="Warning"/> <!-- Const field names should begin with upper-case letter -->
<Rule Id="SA1304" Action="Warning"/> <!-- Non-private readonly fields should begin with upper-case letter -->
<Rule Id="SA1305" Action="None"/> <!-- Field names should not use Hungarian notation -->
<Rule Id="SA1306" Action="Warning"/> <!-- Field names should begin with lower-case letter -->
<Rule Id="SA1307" Action="Warning"/> <!-- Accessible fields should begin with upper-case letter -->
<Rule Id="SA1308" Action="Warning"/> <!-- Variable names should not be prefixed -->
<Rule Id="SA1309" Action="None"/> <!-- Field names should not begin with underscore -->
<Rule Id="SA1310" Action="None"/> <!-- Field names should not contain underscore -->
<Rule Id="SA1311" Action="Warning"/> <!-- Static readonly fields should begin with upper-case letter -->
<Rule Id="SA1312" Action="Warning"/> <!-- Variable names should begin with lower-case letter -->
<Rule Id="SA1313" Action="None"/> <!-- Parameter names should begin with lower-case letter -->
<Rule Id="SA1314" Action="Warning"/> <!-- Type parameter names should begin with T -->
<Rule Id="SX1309" Action="Warning"/> <!-- Field names should begin with underscore -->
<Rule Id="SX1309S" Action="Warning"/> <!-- Static field names should begin with underscore -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.MaintainabilityRules">
<Rule Id="SA1119" Action="Warning" /> <!-- Statement should not use unnecessary parenthesis -->
<Rule Id="SA1400" Action="Warning" /> <!-- Access modifier should be declared -->
<Rule Id="SA1401" Action="Warning" /> <!-- Fields should be private -->
<Rule Id="SA1402" Action="Warning" /> <!-- File may only contain a single type -->
<Rule Id="SA1403" Action="Warning" /> <!-- File may only contain a single namespace -->
<Rule Id="SA1404" Action="Warning" /> <!-- Code analysis suppression should have justification -->
<Rule Id="SA1405" Action="Warning" /> <!-- Debug.Assert should provide message text -->
<Rule Id="SA1406" Action="Warning" /> <!-- Debug.Fail should provide message text -->
<Rule Id="SA1407" Action="Warning" /> <!-- Arithmetic expressions should declare precedence -->
<Rule Id="SA1408" Action="Warning" /> <!-- Conditional expressions should declare precedence -->
<Rule Id="SA1409" Action="None" /> <!-- Remove unnecessary code -->
<Rule Id="SA1410" Action="Warning" /> <!-- Remove delegate parenthesis when possible -->
<Rule Id="SA1411" Action="Warning" /> <!-- Attribute constructor should not use unnecessary parenthesis -->
<Rule Id="SA1412" Action="None" /> <!-- Store files as UTF-8 with byte order mark -->
<Rule Id="SA1413" Action="Warning" /> <!-- Use trailing comma in multi-line initializers -->
<Rule Id="SA1119" Action="Warning"/> <!-- Statement should not use unnecessary parenthesis -->
<Rule Id="SA1400" Action="Warning"/> <!-- Access modifier should be declared -->
<Rule Id="SA1401" Action="Warning"/> <!-- Fields should be private -->
<Rule Id="SA1402" Action="Warning"/> <!-- File may only contain a single type -->
<Rule Id="SA1403" Action="Warning"/> <!-- File may only contain a single namespace -->
<Rule Id="SA1404" Action="Warning"/> <!-- Code analysis suppression should have justification -->
<Rule Id="SA1405" Action="Warning"/> <!-- Debug.Assert should provide message text -->
<Rule Id="SA1406" Action="Warning"/> <!-- Debug.Fail should provide message text -->
<Rule Id="SA1407" Action="None"/> <!-- Arithmetic expressions should declare precedence -->
<Rule Id="SA1408" Action="Warning"/> <!-- Conditional expressions should declare precedence -->
<Rule Id="SA1409" Action="Warning"/> <!-- Remove unnecessary code -->
<Rule Id="SA1410" Action="Warning"/> <!-- Remove delegate parenthesis when possible -->
<Rule Id="SA1411" Action="Warning"/> <!-- Attribute constructor should not use unnecessary parenthesis -->
<Rule Id="SA1412" Action="None"/> <!-- Store files as UTF-8 with byte order mark -->
<Rule Id="SA1413" Action="None"/> <!-- Use trailing comma in multi-line initializers -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.LayoutRules">
<Rule Id="SA1500" Action="Warning" /> <!-- Braces for multi-line statements should not share line -->
<Rule Id="SA1501" Action="Warning" /> <!-- Statement should not be on a single line -->
<Rule Id="SA1502" Action="Warning" /> <!-- Element should not be on a single line -->
<Rule Id="SA1503" Action="Warning" /> <!-- Braces should not be omitted -->
<Rule Id="SA1504" Action="Warning" /> <!-- All accessors should be single-line or multi-line -->
<Rule Id="SA1505" Action="Warning" /> <!-- Opening braces should not be followed by blank line -->
<Rule Id="SA1506" Action="Warning" /> <!-- Element documentation headers should not be followed by blank line -->
<Rule Id="SA1507" Action="Warning" /> <!-- Code should not contain multiple blank lines in a row -->
<Rule Id="SA1508" Action="Warning" /> <!-- Closing braces should not be preceded by blank line -->
<Rule Id="SA1509" Action="Warning" /> <!-- Opening braces should not be preceded by blank line -->
<Rule Id="SA1510" Action="Warning" /> <!-- Chained statement blocks should not be preceded by blank line -->
<Rule Id="SA1511" Action="Warning" /> <!-- While-do footer should not be preceded by blank line -->
<Rule Id="SA1512" Action="Warning" /> <!-- Single-line comments should not be followed by blank line -->
<Rule Id="SA1513" Action="Warning" /> <!-- Closing brace should be followed by blank line -->
<Rule Id="SA1514" Action="Warning" /> <!-- Element documentation header should be preceded by blank line -->
<Rule Id="SA1515" Action="Warning" /> <!-- Single-line comment should be preceded by blank line -->
<Rule Id="SA1516" Action="Warning" /> <!-- Elements should be separated by blank line -->
<Rule Id="SA1517" Action="Warning" /> <!-- Code should not contain blank lines at start of file -->
<Rule Id="SA1518" Action="Warning" /> <!-- Use line endings correctly at end of file -->
<Rule Id="SA1519" Action="Warning" /> <!-- Braces should not be omitted from multi-line child statement -->
<Rule Id="SA1520" Action="Warning" /> <!-- Use braces consistently -->
<Rule Id="SA1500" Action="None"/> <!-- Braces for multi-line statements should not share line -->
<Rule Id="SA1501" Action="Warning"/> <!-- Statement should not be on a single line -->
<Rule Id="SA1502" Action="None"/> <!-- Element should not be on a single line -->
<Rule Id="SA1503" Action="None"/> <!-- Braces should not be omitted -->
<Rule Id="SA1504" Action="Warning"/> <!-- All accessors should be single-line or multi-line -->
<Rule Id="SA1505" Action="Warning"/> <!-- Opening braces should not be followed by blank line -->
<Rule Id="SA1506" Action="Warning"/> <!-- Element documentation headers should not be followed by blank line -->
<Rule Id="SA1507" Action="Warning"/> <!-- Code should not contain multiple blank lines in a row -->
<Rule Id="SA1508" Action="Warning"/> <!-- Closing braces should not be preceded by blank line -->
<Rule Id="SA1509" Action="Warning"/> <!-- Opening braces should not be preceded by blank line -->
<Rule Id="SA1510" Action="Warning"/> <!-- Chained statement blocks should not be preceded by blank line -->
<Rule Id="SA1511" Action="Warning"/> <!-- While-do footer should not be preceded by blank line -->
<Rule Id="SA1512" Action="Warning"/> <!-- Single-line comments should not be followed by blank line -->
<Rule Id="SA1513" Action="Warning"/> <!-- Closing brace should be followed by blank line -->
<Rule Id="SA1514" Action="Warning"/> <!-- Element documentation header should be preceded by blank line -->
<Rule Id="SA1515" Action="Warning"/> <!-- Single-line comment should be preceded by blank line -->
<Rule Id="SA1516" Action="Warning"/> <!-- Elements should be separated by blank line -->
<Rule Id="SA1517" Action="Warning"/> <!-- Code should not contain blank lines at start of file -->
<Rule Id="SA1518" Action="Warning"/> <!-- Use line endings correctly at end of file -->
<Rule Id="SA1519" Action="Warning"/> <!-- Braces should not be omitted from multi-line child statement -->
<Rule Id="SA1520" Action="Warning"/> <!-- Use braces consistently -->
</Rules>
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.DocumentationRules">
<Rule Id="SA1600" Action="None" /> <!-- Elements should be documented -->
<Rule Id="SA1601" Action="Warning" /> <!-- Partial elements should be documented -->
<Rule Id="SA1602" Action="Warning" /> <!-- Enumeration items should be documented -->
<Rule Id="SA1603" Action="None" /> <!-- Documentation should contain valid XML -->
<Rule Id="SA1604" Action="Warning" /> <!-- Element documentation should have summary -->
<Rule Id="SA1605" Action="Warning" /> <!-- Partial element documentation should have summary -->
<Rule Id="SA1606" Action="Warning" /> <!-- Element documentation should have summary text -->
<Rule Id="SA1607" Action="Warning" /> <!-- Partial element documentation should have summary text -->
<Rule Id="SA1608" Action="Warning" /> <!-- Element documentation should not have default summary -->
<Rule Id="SA1609" Action="None" /> <!-- Property documentation should have value -->
<Rule Id="SA1610" Action="Warning" /> <!-- Property documentation should have value text -->
<Rule Id="SA1611" Action="Warning" /> <!-- Element parameters should be documented -->
<Rule Id="SA1612" Action="Warning" /> <!-- Element parameter documentation should match element parameters -->
<Rule Id="SA1613" Action="Warning" /> <!-- Element parameter documentation should declare parameter name -->
<Rule Id="SA1614" Action="Warning" /> <!-- Element parameter documentation should have text -->
<Rule Id="SA1615" Action="Warning" /> <!-- Element return value should be documented -->
<Rule Id="SA1616" Action="Warning" /> <!-- Element return value documentation should have text -->
<Rule Id="SA1617" Action="Warning" /> <!-- Void return value should not be documented -->
<Rule Id="SA1618" Action="Warning" /> <!-- Generic type parameters should be documented -->
<Rule Id="SA1619" Action="Warning" /> <!-- Generic type parameters should be documented partial class -->
<Rule Id="SA1620" Action="Warning" /> <!-- Generic type parameter documentation should match type parameters -->
<Rule Id="SA1621" Action="Warning" /> <!-- Generic type parameter documentation should declare parameter name -->
<Rule Id="SA1622" Action="Warning" /> <!-- Generic type parameter documentation should have text -->
<Rule Id="SA1623" Action="Warning" /> <!-- Property summary documentation should match accessors -->
<Rule Id="SA1624" Action="Warning" /> <!-- Property summary documentation should omit accessor with restricted access -->
<Rule Id="SA1625" Action="Warning" /> <!-- Element documentation should not be copied and pasted -->
<Rule Id="SA1626" Action="Warning" /> <!-- Single-line comments should not use documentation style slashes -->
<Rule Id="SA1627" Action="Warning" /> <!-- Documentation text should not be empty -->
<Rule Id="SA1628" Action="None" /> <!-- Documentation text should begin with a capital letter -->
<Rule Id="SA1629" Action="Warning" /> <!-- Documentation text should end with a period -->
<Rule Id="SA1630" Action="None" /> <!-- Documentation text should contain whitespace -->
<Rule Id="SA1631" Action="None" /> <!-- Documentation should meet character percentage -->
<Rule Id="SA1632" Action="None" /> <!-- Documentation text should meet minimum character length -->
<Rule Id="SA1633" Action="None" /> <!-- File should have header -->
<Rule Id="SA1634" Action="Warning" /> <!-- File header should show copyright -->
<Rule Id="SA1635" Action="Warning" /> <!-- File header should have copyright text -->
<Rule Id="SA1636" Action="Warning" /> <!-- File header copyright text should match -->
<Rule Id="SA1637" Action="Warning" /> <!-- File header should contain file name -->
<Rule Id="SA1638" Action="Warning" /> <!-- File header file name documentation should match file name -->
<Rule Id="SA1639" Action="Warning" /> <!-- File header should have summary -->
<Rule Id="SA1640" Action="Warning" /> <!-- File header should have valid company text -->
<Rule Id="SA1641" Action="Warning" /> <!-- File header company name text should match -->
<Rule Id="SA1642" Action="Warning" /> <!-- Constructor summary documentation should begin with standard text -->
<Rule Id="SA1643" Action="Warning" /> <!-- Destructor summary documentation should begin with standard text -->
<Rule Id="SA1644" Action="None" /> <!-- Documentation headers should not contain blank lines -->
<Rule Id="SA1645" Action="None" /> <!-- Included documentation file does not exist -->
<Rule Id="SA1646" Action="None" /> <!-- Included documentation XPath does not exist -->
<Rule Id="SA1647" Action="None" /> <!-- Include node does not contain valid file and path -->
<Rule Id="SA1648" Action="Warning" /> <!-- Inheritdoc should be used with inheriting class -->
<Rule Id="SA1649" Action="Warning" /> <!-- File name should match first type name -->
<Rule Id="SA1650" Action="None" /> <!-- Element documentation should be spelled correctly -->
<Rule Id="SA1651" Action="Warning" /> <!-- Do not use placeholder elements -->
<Rule Id="SA1600" Action="None"/> <!-- Elements should be documented -->
<Rule Id="SA1601" Action="None"/> <!-- Partial elements should be documented -->
<Rule Id="SA1602" Action="None"/> <!-- Enumeration items should be documented -->
<Rule Id="SA1603" Action="Warning"/> <!-- Documentation should contain valid XML -->
<Rule Id="SA1604" Action="Warning"/> <!-- Element documentation should have summary -->
<Rule Id="SA1605" Action="Warning"/> <!-- Partial element documentation should have summary -->
<Rule Id="SA1606" Action="Warning"/> <!-- Element documentation should have summary text -->
<Rule Id="SA1607" Action="Warning"/> <!-- Partial element documentation should have summary text -->
<Rule Id="SA1608" Action="Warning"/> <!-- Element documentation should not have default summary -->
<Rule Id="SA1609" Action="Warning"/> <!-- Property documentation should have value -->
<Rule Id="SA1610" Action="Warning"/> <!-- Property documentation should have value text -->
<Rule Id="SA1611" Action="None"/> <!-- Element parameters should be documented -->
<Rule Id="SA1612" Action="Warning"/> <!-- Element parameter documentation should match element parameters -->
<Rule Id="SA1613" Action="Warning"/> <!-- Element parameter documentation should declare parameter name -->
<Rule Id="SA1614" Action="Warning"/> <!-- Element parameter documentation should have text -->
<Rule Id="SA1615" Action="None"/> <!-- Element return value should be documented -->
<Rule Id="SA1616" Action="Warning"/> <!-- Element return value documentation should have text -->
<Rule Id="SA1617" Action="Warning"/> <!-- Void return value should not be documented -->
<Rule Id="SA1618" Action="None"/> <!-- Generic type parameters should be documented -->
<Rule Id="SA1619" Action="None"/> <!-- Generic type parameters should be documented partial class -->
<Rule Id="SA1620" Action="Warning"/> <!-- Generic type parameter documentation should match type parameters -->
<Rule Id="SA1621" Action="Warning"/> <!-- Generic type parameter documentation should declare parameter name -->
<Rule Id="SA1622" Action="Warning"/> <!-- Generic type parameter documentation should have text -->
<Rule Id="SA1623" Action="Warning"/> <!-- Property summary documentation should match accessors -->
<Rule Id="SA1624" Action="Warning"/> <!-- Property summary documentation should omit accessor with restricted access -->
<Rule Id="SA1625" Action="Warning"/> <!-- Element documentation should not be copied and pasted -->
<Rule Id="SA1626" Action="Warning"/> <!-- Single-line comments should not use documentation style slashes -->
<Rule Id="SA1627" Action="Warning"/> <!-- Documentation text should not be empty -->
<Rule Id="SA1628" Action="Warning"/> <!-- Documentation text should begin with a capital letter -->
<Rule Id="SA1629" Action="Warning"/> <!-- Documentation text should end with a period -->
<Rule Id="SA1630" Action="Warning"/> <!-- Documentation text should contain whitespace -->
<Rule Id="SA1631" Action="Warning"/> <!-- Documentation should meet character percentage -->
<Rule Id="SA1632" Action="Warning"/> <!-- Documentation text should meet minimum character length -->
<Rule Id="SA1633" Action="None"/> <!-- File should have header -->
<Rule Id="SA1634" Action="Warning"/> <!-- File header should show copyright -->
<Rule Id="SA1635" Action="Warning"/> <!-- File header should have copyright text -->
<Rule Id="SA1636" Action="Warning"/> <!-- File header copyright text should match -->
<Rule Id="SA1637" Action="Warning"/> <!-- File header should contain file name -->
<Rule Id="SA1638" Action="Warning"/> <!-- File header file name documentation should match file name -->
<Rule Id="SA1639" Action="Warning"/> <!-- File header should have summary -->
<Rule Id="SA1640" Action="Warning"/> <!-- File header should have valid company text -->
<Rule Id="SA1641" Action="Warning"/> <!-- File header company name text should match -->
<Rule Id="SA1642" Action="Warning"/> <!-- Constructor summary documentation should begin with standard text -->
<Rule Id="SA1643" Action="Warning"/> <!-- Destructor summary documentation should begin with standard text -->
<Rule Id="SA1644" Action="Warning"/> <!-- Documentation headers should not contain blank lines -->
<Rule Id="SA1645" Action="Warning"/> <!-- Included documentation file does not exist -->
<Rule Id="SA1646" Action="Warning"/> <!-- Included documentation XPath does not exist -->
<Rule Id="SA1647" Action="Warning"/> <!-- Include node does not contain valid file and path -->
<Rule Id="SA1648" Action="Warning"/> <!-- Inheritdoc should be used with inheriting class -->
<Rule Id="SA1649" Action="Warning"/> <!-- File name should match first type name -->
<Rule Id="SA1650" Action="Warning"/> <!-- Element documentation should be spelled correctly -->
<Rule Id="SA1651" Action="Warning"/> <!-- Do not use placeholder elements -->
</Rules>
</RuleSet>

View File

@ -15,6 +15,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{AD79881E-7
build.cake = build.cake
code-format.cmd = code-format.cmd
CodeCleanupOnSave.csx = CodeCleanupOnSave.csx
CodeQuality.props = CodeQuality.props
Directory.Build.props = Directory.Build.props
dot.sln.DotSettings = dot.sln.DotSettings
dot.sln.DotSettings.user = dot.sln.DotSettings.user
@ -27,7 +28,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{AD79881E-7
README.md = README.md
README.zh-CN.md = README.zh-CN.md
SafetyDelUnusedResx.ahk = SafetyDelUnusedResx.ahk
SonarqubleAnalyzer.props = SonarqubleAnalyzer.props
stylecop.json = stylecop.json
StyleCopAnalyzers.ruleset = StyleCopAnalyzers.ruleset
switch-nuget.cmd = switch-nuget.cmd
switch-project.cmd = switch-project.cmd
switcher.json = switcher.json

View File

@ -1,6 +1,18 @@
<wpf:ResourceDictionary xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xml:space="preserve">
<s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">False</s:Boolean>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_CODE/@EntryValue">1</s:Int64>
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@EntryValue">1</s:Int64>
<s:String x:Key="/Default/CodeInspection/Highlighting/AnalysisEnabled/@EntryValue">OFF</s:String>
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TooWideLocalVariableScope/@EntryIndexedValue">HINT</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOR/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_FOREACH/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_IFELSE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/BRACES_FOR_WHILE/@EntryValue">Required</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue">&lt;?xml version="1.0" encoding="utf-16"?&gt;
&lt;Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"&gt;
&lt;TypePattern&gt;
@ -8,43 +20,38 @@
&lt;Entry.SortBy&gt;
&lt;Kind&gt;
&lt;Kind.Order&gt;
&lt;DeclarationKind&gt;Interface&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Class&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Record&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Enum&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Struct&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Delegate&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Event&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Constant&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Field&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Property&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Constructor&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Destructor&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Delegate&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Event&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Enum&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Interface&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Property&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Indexer&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Method&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Struct&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Record&lt;/DeclarationKind&gt;
&lt;DeclarationKind&gt;Class&lt;/DeclarationKind&gt;
&lt;/Kind.Order&gt;
&lt;/Kind&gt;
&lt;Access&gt;
&lt;Access.Order&gt;
&lt;AccessModifier&gt;Private&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;PrivateProtected&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;Protected&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;ProtectedInternal&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;Internal&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;Public&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;Internal&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;ProtectedInternal&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;Protected&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;PrivateProtected&lt;/AccessModifier&gt;
&lt;AccessModifier&gt;Private&lt;/AccessModifier&gt;
&lt;/Access.Order&gt;
&lt;/Access&gt;
&lt;Static /&gt;
&lt;Readonly /&gt;
&lt;Name /&gt;
&lt;/Entry.SortBy&gt;
&lt;/Entry&gt;
&lt;/TypePattern&gt;
&lt;/Patterns&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /&gt;</s:String>
<s:String
x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /&gt;</s:String>
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue">&lt;Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /&gt;</s:String>
<s:Boolean x:Key="/Default/ReSpeller/ReSpellerEnabled/@EntryValue">False</s:Boolean>
<s:String
x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=TooWideLocalVariableScope/@EntryIndexedValue">HINT</s:String>
</wpf:ResourceDictionary>

View File

@ -13,9 +13,8 @@ using Dot;
namespace Dot;
public static class AssemblyInfo
internal static class AssemblyInfo
{
private const string _VERSION = "1.1.6";
public const string ASSEMBLY_COMPANY = "nsnail";
public const string ASSEMBLY_COPYRIGHT = $"Copyright (c) 2022 {ASSEMBLY_COMPANY}";
public const string ASSEMBLY_FILE_VERSION = _VERSION;
@ -25,4 +24,5 @@ public static class AssemblyInfo
public const string ASSEMBLY_PRODUCT = "dot";
public const string ASSEMBLY_TITLE = "功能全面的实用工具 - 程序员的瑞士军刀";
public const string ASSEMBLY_VERSION = _VERSION;
private const string _VERSION = "1.1.6";
}

View File

@ -1,12 +1,13 @@
// ReSharper disable ClassNeverInstantiated.Global
#if NET7_0_WINDOWS
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
namespace Dot.Color;
[Description(nameof(Str.ScreenPixelTool))]
[Localization(typeof(Str))]
[SupportedOSPlatform(nameof(OSPlatform.Windows))]
internal sealed class Main : ToolBase<Option>
{
protected override Task Core()
{

View File

@ -8,20 +8,11 @@ namespace Dot.Color;
internal sealed class MouseHook : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
private struct Msllhookstruct
{
[FieldOffset(0)] public readonly int X;
[FieldOffset(4)] public readonly int Y;
}
// ReSharper disable once EventNeverSubscribedTo.Global
public event MouseEventHandler MouseEvent = delegate { };
private const int _WH_MOUSE_LL = 14;
private const int _WM_LBUTTONDOWN = 0x0201;
private const int _WM_MOUSEMOVE = 0x0200;
private bool _disposed;
private readonly nint _hookId;
private bool _disposed;
public MouseHook()
{
@ -33,23 +24,46 @@ internal sealed class MouseHook : IDisposable
Dispose(false);
}
public event MouseEventHandler MouseEvent;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
private static nint SetHook(Func<int, nint, nint, nint> proc)
{
using var curProcess = Process.GetCurrentProcess();
using var curModule = curProcess.MainModule!;
return Win32.SetWindowsHookEx(_WH_MOUSE_LL, proc, Win32.GetModuleHandle(curModule.ModuleName), 0);
}
private void Dispose(bool disposing)
{
if (_disposed) return;
#pragma warning disable S108
if (disposing) { }
#pragma warning restore S108
if (_disposed) {
return;
}
if (disposing) {
//
}
if (_hookId != default) {
Win32.UnhookWindowsHookEx(_hookId);
}
if (_hookId != default) Win32.UnhookWindowsHookEx(_hookId);
_disposed = true;
}
private nint HookCallback(int nCode, nint wParam, nint lParam)
{
if (nCode < 0 || (_WM_MOUSEMOVE != wParam && _WM_LBUTTONDOWN != wParam))
if (nCode < 0 || (wParam != _WM_MOUSEMOVE && wParam != _WM_LBUTTONDOWN)) {
return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam);
}
var hookStruct = (Msllhookstruct)Marshal.PtrToStructure(lParam, typeof(Msllhookstruct))!;
MouseEvent(null, new MouseEventArgs( //
MouseEvent?.Invoke(null, new MouseEventArgs( //
wParam == _WM_MOUSEMOVE ? MouseButtons.None : MouseButtons.Left //
, 0 //
, hookStruct.X //
@ -58,17 +72,11 @@ internal sealed class MouseHook : IDisposable
return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam);
}
private static nint SetHook(Win32.LowLevelMouseProc proc)
[StructLayout(LayoutKind.Explicit)]
private readonly struct Msllhookstruct
{
using var curProcess = Process.GetCurrentProcess();
using var curModule = curProcess.MainModule!;
return Win32.SetWindowsHookEx(_WH_MOUSE_LL, proc, Win32.GetModuleHandle(curModule.ModuleName), 0);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
[FieldOffset(0)] public readonly int X;
[FieldOffset(4)] public readonly int Y;
}
}
#endif

View File

@ -2,4 +2,4 @@
namespace Dot.Color;
internal class Option : OptionBase { }
internal sealed class Option : OptionBase { }

View File

@ -1,16 +1,19 @@
#if NET7_0_WINDOWS
using System.Drawing.Drawing2D;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using Size = System.Drawing.Size;
namespace Dot.Color;
internal class WinInfo : Form
[SupportedOSPlatform(nameof(OSPlatform.Windows))]
internal sealed class WinInfo : Form
{
private const int _WINDOW_SIZE = 480; //窗口大小
private const int _ZOOM_RATE = 16; //缩放倍率
private bool _disposed;
private readonly Graphics _graphics;
private readonly PictureBox _pbox;
private bool _disposed;
public WinInfo()
{
@ -38,25 +41,6 @@ internal class WinInfo : Form
Dispose(false);
}
private void PboxOnMouseEnter(object sender, EventArgs e)
{
// 信息窗口避开鼠标指针指向区域
Location = new Point(Location.X, Location.Y == 0 ? Screen.PrimaryScreen!.Bounds.Height - _WINDOW_SIZE : 0);
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (_disposed) return;
if (disposing) {
_graphics?.Dispose();
_pbox?.Dispose();
}
_disposed = true;
}
public void UpdateImage(Bitmap img, int x, int y)
{
// 计算复制小图的区域
@ -72,13 +56,38 @@ internal class WinInfo : Form
// 取鼠标位置颜色
var posColor = img.GetPixel(x, y);
// 绘制底部文字信息
_graphics.FillRectangle(Brushes.Black, 0, _WINDOW_SIZE - 30, _WINDOW_SIZE, 30);
_graphics.DrawString($"{Str.ClickCopyColor} X: {x} Y: {y} RGB({posColor.R},{posColor.G},{posColor.B})"
_graphics.DrawString( //
$"{Str.ClickCopyColor} X: {x} Y: {y} RGB({posColor.R},{posColor.G},{posColor.B})"
, new Font(FontFamily.GenericSerif, 10) //
, Brushes.White, 0, _WINDOW_SIZE - 20);
// 触发重绘
_pbox.Refresh();
}
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (_disposed) {
return;
}
if (disposing) {
_graphics?.Dispose();
_pbox?.Dispose();
}
_disposed = true;
}
private void PboxOnMouseEnter(object sender, EventArgs e)
{
// 信息窗口避开鼠标指针指向区域
Location = new Point(Location.X, Location.Y == 0 ? Screen.PrimaryScreen!.Bounds.Height - _WINDOW_SIZE : 0);
}
}
#endif

View File

@ -1,14 +1,18 @@
#if NET7_0_WINDOWS
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using TextCopy;
namespace Dot.Color;
internal class WinMain : Form
[SupportedOSPlatform(nameof(OSPlatform.Windows))]
internal sealed class WinMain : Form
{
private readonly Bitmap _bmp;
private bool _disposed;
private readonly WinInfo _winInfo = new(); //小图窗口
private bool _disposed;
public WinMain()
{
// 隐藏控制台窗口,避免捕获到截屏
@ -32,7 +36,10 @@ internal class WinMain : Form
protected override void Dispose(bool disposing)
{
base.Dispose(disposing);
if (_disposed) return;
if (_disposed) {
return;
}
if (disposing) {
_bmp?.Dispose();
_winInfo?.Dispose();
@ -43,7 +50,9 @@ internal class WinMain : Form
protected override void OnKeyUp(KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape) Application.Exit();
if (e.KeyCode == Keys.Escape) {
Application.Exit();
}
}
protected override void OnLoad(EventArgs e)

View File

@ -3,12 +3,13 @@ using System.Diagnostics;
namespace Dot;
// ReSharper disable once UnusedType.Global
internal class CsxEditor
// ReSharper disable once UnusedMember.Global
internal sealed class CsxEditor
{
// ReSharper disable once UnusedMember.Local
#pragma warning disable CA1822
private void Run()
#pragma warning restore CA1822
#pragma warning disable IDE0051
private static void Run()
#pragma warning restore IDE0051
{
/*
for %%i in (*.png) do pngquant %%i --force --output %%i --skip-if-larger
@ -24,14 +25,14 @@ internal class CsxEditor
})
.ToArray();
Parallel.ForEach(files, file => {
_ = Parallel.ForEach(files, file => {
var startInfo = new ProcessStartInfo {
FileName = "pngquant"
, Arguments
= $"\"{file}\" --force --output \"{file}\" --skip-if-larger"
};
using var p = Process.Start(startInfo);
p.WaitForExit();
p!.WaitForExit();
Console.WriteLine(p.ExitCode);
});
@ -45,13 +46,13 @@ internal class CsxEditor
}))
.ToArray();
Parallel.ForEach(files, file => {
_ = Parallel.ForEach(files, file => {
var startInfo = new ProcessStartInfo {
FileName = "jpegtran"
, Arguments = $"-copy none -optimize -perfect \"{file}\" \"{file}\""
};
using var p = Process.Start(startInfo);
p.WaitForExit();
p!.WaitForExit();
Console.WriteLine(p.ExitCode);
});
}

View File

@ -1,87 +1,24 @@
using System.Collections.Concurrent;
using System.Globalization;
using System.Text.RegularExpressions;
// ReSharper disable once RedundantUsingDirective
using Panel = Spectre.Console.Panel;
namespace Dot;
internal abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : DirOption
internal abstract class FilesTool<TOption> : ToolBase<TOption>
where TOption : DirOption
{
// ReSharper disable once StaticMemberInGenericType
private static readonly object _lock = new(); //线程锁
private readonly ConcurrentDictionary<string, int> _writeStats = new(); //写入统计:后缀,数量
private int _breakCnt; //跳过文件数
private ProgressTask _childTask; //子任务进度
private int _excludeCnt; //排除文件数
// ReSharper disable once StaticMemberInGenericType
#pragma warning disable S2743
private static readonly object _lock = new(); //线程锁
private int _readCnt; //读取文件数
private int _totalCnt; //总文件数
private int _writeCnt; //写入文件数
private readonly ConcurrentDictionary<string, int> _writeStats = new(); //写入统计:后缀,数量
private async Task CoreInternal()
{
if (!Opt.WriteMode) AnsiConsole.MarkupLine("[gray]{0}[/]", Str.ExerciseMode);
IEnumerable<string> fileList;
await AnsiConsole.Progress()
.Columns(new ProgressBarColumn() //
, new ElapsedTimeColumn() //
, new PercentageColumn() //
, new SpinnerColumn() //
, new TaskDescriptionColumn { Alignment = Justify.Left } //
)
.StartAsync(async ctx => {
var taskSearchfile = ctx.AddTask(Str.SearchingFile).IsIndeterminate();
_childTask = ctx.AddTask("-/-", false);
fileList = EnumerateFiles(Opt.Path, Opt.Filter, out _excludeCnt);
_totalCnt = fileList.Count();
taskSearchfile.StopTask();
_childTask.MaxValue = _totalCnt;
_childTask.StartTask();
await Parallel.ForEachAsync(fileList, FileHandle);
});
var grid = new Grid().AddColumn(new GridColumn().NoWrap().PadRight(16))
.AddColumn(new GridColumn().Alignment(Justify.Right));
foreach (var kv in _writeStats.OrderByDescending(x => x.Value).ThenBy(x => x.Key))
grid.AddRow(kv.Key, kv.Value.ToString());
AnsiConsole.Write(new Panel(grid).Header(Str.WriteFileStats));
}
// ReSharper disable once ReturnTypeCanBeEnumerable.Local
private string[] EnumerateFiles(string path, string searchPattern, out int excludeCnt)
{
var exCnt = 0;
if (Opt.ExcludeRegexes?.FirstOrDefault() is null) //默认排除.git 、 node_modules 目录
Opt.ExcludeRegexes = new[] { @"\.git", "node_modules" };
var excludeRegexes = Opt.ExcludeRegexes.Select(x => new Regex(x));
var fileList = Directory.EnumerateFiles(path, searchPattern
, new EnumerationOptions {
RecurseSubdirectories = true
, AttributesToSkip
= FileAttributes.ReparsePoint
, IgnoreInaccessible = true
, MaxRecursionDepth = Opt.MaxRecursionDepth
})
.Where(x => {
if (!excludeRegexes.Any(y => y.IsMatch(x))) return true;
++exCnt;
return false;
})
.ToArray();
excludeCnt = exCnt;
return fileList;
}
protected override Task Core()
{
if (!Directory.Exists(Opt.Path))
throw new ArgumentException(nameof(Opt.Path), string.Format(Str.PathNotFound, Opt.Path));
return CoreInternal();
}
protected static FileStream CreateTempFile(out string file)
{
@ -89,8 +26,6 @@ internal abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : D
return OpenFileStream(file, FileMode.OpenOrCreate, FileAccess.Write);
}
protected abstract ValueTask FileHandle(string file, CancellationToken cancelToken);
protected static FileStream OpenFileStream(string file, FileMode mode, FileAccess access
, FileShare share = FileShare.Read)
{
@ -114,13 +49,26 @@ internal abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : D
return fsr;
}
protected override Task Core()
{
return !Directory.Exists(Opt.Path)
? throw new ArgumentException( //
nameof(Opt.Path), string.Format(CultureInfo.InvariantCulture, Str.PathNotFound, Opt.Path))
: CoreInternal();
}
protected abstract ValueTask FileHandle(string file, CancellationToken cancelToken);
protected void ShowMessage(int readCnt, int writeCnt, int breakCnt)
{
lock (_lock) {
_readCnt += readCnt;
_writeCnt += writeCnt;
_breakCnt += breakCnt;
if (readCnt > 0) _childTask.Increment(1);
if (readCnt > 0) {
_childTask.Increment(1);
}
_childTask.Description
= $"{Str.Read}: [green]{_readCnt}[/]/{_totalCnt}, {Str.Write}: [red]{_writeCnt}[/], {Str.Break}: [gray]{_breakCnt}[/], {Str.Exclude}: [yellow]{_excludeCnt}[/]";
}
@ -128,6 +76,74 @@ internal abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : D
protected void UpdateStats(string key)
{
_writeStats.AddOrUpdate(key, 1, (_, oldValue) => oldValue + 1);
_ = _writeStats.AddOrUpdate(key, 1, (_, oldValue) => oldValue + 1);
}
private async Task CoreInternal()
{
if (!Opt.WriteMode) {
AnsiConsole.MarkupLine(CultureInfo.InvariantCulture, "[gray]{0}[/]", Str.ExerciseMode);
}
IEnumerable<string> fileList;
await AnsiConsole.Progress()
.Columns( //
new ProgressBarColumn() //
, new ElapsedTimeColumn() //
, new PercentageColumn() //
, new SpinnerColumn() //
, new TaskDescriptionColumn { Alignment = Justify.Left }) //
.StartAsync(async ctx => {
var taskSearchfile = ctx.AddTask(Str.SearchingFile).IsIndeterminate();
_childTask = ctx.AddTask("-/-", false);
fileList = EnumerateFiles(Opt.Path, Opt.Filter, out _excludeCnt);
_totalCnt = fileList.Count();
taskSearchfile.StopTask();
_childTask.MaxValue = _totalCnt;
_childTask.StartTask();
await Parallel.ForEachAsync(fileList, FileHandle);
});
var grid = new Grid().AddColumn(new GridColumn().NoWrap().PadRight(16))
.AddColumn(new GridColumn().Alignment(Justify.Right));
foreach (var kv in _writeStats.OrderByDescending(x => x.Value).ThenBy(x => x.Key)) {
_ = grid.AddRow(kv.Key, kv.Value.ToString(CultureInfo.InvariantCulture));
}
AnsiConsole.Write(new Panel(grid).Header(Str.WriteFileStats));
}
// ReSharper disable once ReturnTypeCanBeEnumerable.Local
private string[] EnumerateFiles(string path, string searchPattern, out int excludeCnt)
{
var exCnt = 0;
//默认排除.git 、 node_modules 目录
if (Opt.ExcludeRegexes?.FirstOrDefault() is null) {
Opt.ExcludeRegexes = new[] { @"\.git", "node_modules" };
}
var excludeRegexes = Opt.ExcludeRegexes.Select(x => new Regex(x));
var fileList = Directory.EnumerateFiles(path, searchPattern
, new EnumerationOptions {
RecurseSubdirectories = true
, AttributesToSkip
= FileAttributes.ReparsePoint
, IgnoreInaccessible = true
, MaxRecursionDepth = Opt.MaxRecursionDepth
})
.Where(x => {
if (!excludeRegexes.Any(y => y.IsMatch(x))) {
return true;
}
++exCnt;
return false;
})
.ToArray();
excludeCnt = exCnt;
return fileList;
}
}

View File

@ -8,21 +8,110 @@ namespace Dot.Get;
[Description(nameof(Str.DownloadTool))]
[Localization(typeof(Str))]
internal partial class Main : ToolBase<Option>
internal sealed partial class Main : ToolBase<Option>
{
private const string _PART = "part";
protected override async Task Core()
{
using var http = new HttpClient();
string attachment = default;
long contentLength = default;
var table = new Table().AddColumn(Str.DataIdentification).AddColumn(Str.DataContent).AddRow("Url", Opt.Url);
await AnsiConsole.Status()
.AutoRefresh(true)
.Spinner(Spinner.Known.Default)
.StartAsync($"{Str.RequestMetaData}: {Opt.Url}", async _ => {
using var headRsp = await http.SendAsync(new HttpRequestMessage(HttpMethod.Head, Opt.Url));
using var content = headRsp.Content;
contentLength = content.Headers.ContentLength ?? 0;
attachment = content.Headers.ContentDisposition?.FileName ??
Opt.Url[(Opt.Url.LastIndexOf('/') + 1)..];
foreach (var kv in content.Headers) {
table.AddRow(kv.Key, string.Join(Environment.NewLine, kv.Value));
}
});
AnsiConsole.Write(table);
var timer = DateTime.Now;
var mainFilePath = BuildFilePath(Opt.Output, attachment);
await AnsiConsole.Progress()
.Columns( //
new ProgressBarColumn() //
, new SpinnerColumn() //
, new DownloadedColumn() //
, new TransferSpeedColumn() //
, new PercentageColumn() //
, new TaskDescriptionColumn() //
, new RemainingTimeColumn()) //
.StartAsync(async ctx => {
var tParent = ctx.AddTask($"{Str.TotalProgress} {Str.RemainingTime}:").IsIndeterminate();
//未知文件长度,单线程下载;
if (contentLength == 0) {
await using var nets = await http.GetStreamAsync(Opt.Url);
await using var fs
= new FileStream(mainFilePath, FileMode.CreateNew, FileAccess.Write
, FileShare.None);
tParent.MaxValue = Opt.BufferSize + 1; //由于文件长度未知, 进度条终点永远至为当前长度+1
StreamCopy(nets, fs, x => {
tParent.MaxValue += x;
tParent.Increment(x);
});
tParent.MaxValue = tParent.Value; // 写完了
tParent.IsIndeterminate(false);
tParent.StopTask();
}
//已知文件长度,多线程下载:
else {
tParent.IsIndeterminate(false);
tParent.MaxValue = contentLength;
var chunkSize = contentLength / Opt.ChunkNumbers;
Parallel.For(0, Opt.ChunkNumbers
, new ParallelOptions { MaxDegreeOfParallelism = Opt.MaxParallel } //
, i => {
var tChild = ctx.AddTask(
$"{Str.Thread}{i} {Str.RemainingTime}:", maxValue: chunkSize);
using var getReq = new HttpRequestMessage(HttpMethod.Get, Opt.Url);
var startPos = i * chunkSize;
var endPos = startPos + chunkSize - 1;
if (i == Opt.ChunkNumbers - 1) {
endPos += contentLength % chunkSize;
}
getReq.Headers.Range = new RangeHeaderValue(startPos, endPos);
// ReSharper disable once AccessToDisposedClosure
using var getRsp
= http.Send(getReq, HttpCompletionOption.ResponseHeadersRead);
WritePart(getRsp, mainFilePath, i, startPos, endPos, x => {
tChild.Increment(x);
tParent.Increment(x);
});
});
MergeParts(mainFilePath);
}
});
AnsiConsole.MarkupLine(
$"{Str.DownloadCompleted}, {Str.ElapsedTime}: {DateTime.Now - timer}, {Str.FileSaveLocation}: {mainFilePath}");
}
/// <summary>
/// 给定一个路径(存在的目录,或者存在的目录+存在或不存在的文件)
/// 给定一个路径(存在的目录,或者存在的目录+存在或不存在的文件).
/// </summary>
/// <param name="path">存在的目录,或者存在的目录+存在或不存在的文件</param>
/// <param name="file">要写入的文件名</param>
/// <returns>返回一个可写的文件完整路径</returns>
/// <param name="path">存在的目录,或者存在的目录+存在或不存在的文件.</param>
/// <param name="file">要写入的文件名.</param>
/// <returns>返回一个可写的文件完整路径.</returns>
private static string BuildFilePath(string path, string file)
{
if (GetUseablePath(ref path))
// path 是一个存在的文件,已追加尾标
if (GetUseablePath(ref path)) {
return path;
}
// ReSharper disable once InvertIf
if (Directory.Exists(path)) { //path 是一个存在的目录。
@ -41,7 +130,9 @@ internal partial class Main : ToolBase<Option>
var name = Path.GetFileNameWithoutExtension(path);
var ext = Path.GetExtension(path);
var ret = false;
#pragma warning disable SA1002
for (var i = 1;; ++i) {
#pragma warning restore SA1002
if (File.Exists(path)) {
path = Path.Combine(dir!, $"{name}({i}){ext}");
ret = true;
@ -56,7 +147,8 @@ internal partial class Main : ToolBase<Option>
private static void MergeParts(string mainFilePath)
{
var files = Directory.GetFiles(Path.GetDirectoryName(mainFilePath)! //
var files = Directory.GetFiles( //
Path.GetDirectoryName(mainFilePath)! //
, $"{Path.GetFileName(mainFilePath)}.*.{_PART}", SearchOption.TopDirectoryOnly)
.OrderBy(x => x)
.ToArray();
@ -97,85 +189,4 @@ internal partial class Main : ToolBase<Option>
rateHandle(read);
}
}
protected override async Task Core()
{
using var http = new HttpClient();
string attachment = default;
long contentLength = default;
var table = new Table().AddColumn(Str.DataIdentification).AddColumn(Str.DataContent).AddRow("Url", Opt.Url);
await AnsiConsole.Status()
.AutoRefresh(true)
.Spinner(Spinner.Known.Default)
.StartAsync($"{Str.RequestMetaData}: {Opt.Url}", async _ => {
using var headRsp = await http.SendAsync(new HttpRequestMessage(HttpMethod.Head, Opt.Url));
using var content = headRsp.Content;
contentLength = content.Headers.ContentLength ?? 0;
attachment = content.Headers.ContentDisposition?.FileName ??
Opt.Url[(Opt.Url.LastIndexOf('/') + 1)..];
foreach (var kv in content.Headers)
table.AddRow(kv.Key, string.Join(Environment.NewLine, kv.Value));
});
AnsiConsole.Write(table);
var timer = DateTime.Now;
var mainFilePath = BuildFilePath(Opt.Output, attachment);
await AnsiConsole.Progress()
.Columns(new ProgressBarColumn() //
, new SpinnerColumn() //
, new DownloadedColumn() //
, new TransferSpeedColumn() //
, new PercentageColumn() //
, new TaskDescriptionColumn() //
, new RemainingTimeColumn() //
)
.StartAsync(async ctx => {
var tParent = ctx.AddTask($"{Str.TotalProgress} {Str.RemainingTime}:").IsIndeterminate();
if (contentLength == 0) //未知文件长度,单线程下载;
{
await using var nets = await http.GetStreamAsync(Opt.Url);
await using var fs
= new FileStream(mainFilePath, FileMode.CreateNew, FileAccess.Write
, FileShare.None);
tParent.MaxValue = Opt.BufferSize + 1; //由于文件长度未知, 进度条终点永远至为当前长度+1
StreamCopy(nets, fs, x => {
tParent.MaxValue += x;
tParent.Increment(x);
});
tParent.MaxValue = tParent.Value; // 写完了
tParent.IsIndeterminate(false);
tParent.StopTask();
}
else //已知文件长度,多线程下载:
{
tParent.IsIndeterminate(false);
tParent.MaxValue = contentLength;
var chunkSize = contentLength / Opt.ChunkNumbers;
Parallel.For(0, Opt.ChunkNumbers
, new ParallelOptions { MaxDegreeOfParallelism = Opt.MaxParallel } //
, i => {
var tChild = ctx.AddTask(
$"{Str.Thread}{i} {Str.RemainingTime}:", maxValue: chunkSize);
using var getReq = new HttpRequestMessage(HttpMethod.Get, Opt.Url);
var startPos = i * chunkSize;
var endPos = startPos + chunkSize - 1;
if (i == Opt.ChunkNumbers - 1) endPos += contentLength % chunkSize;
getReq.Headers.Range = new RangeHeaderValue(startPos, endPos);
// ReSharper disable once AccessToDisposedClosure
using var getRsp
= http.Send(getReq, HttpCompletionOption.ResponseHeadersRead);
WritePart(getRsp, mainFilePath, i, startPos, endPos, x => {
tChild.Increment(x);
tParent.Increment(x);
});
});
MergeParts(mainFilePath);
}
});
AnsiConsole.MarkupLine(
$"{Str.DownloadCompleted}, {Str.ElapsedTime}: {DateTime.Now - timer}, {Str.FileSaveLocation}: {mainFilePath}");
}
}

View File

@ -3,7 +3,7 @@
namespace Dot.Get;
internal class Option : OptionBase
internal sealed class Option : OptionBase
{
[CommandOption("-b|--buffer-size")]
[Description(nameof(Str.BufferSize))]

View File

@ -2,6 +2,7 @@
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Globalization;
using System.Text;
using NSExt.Extensions;
@ -9,33 +10,44 @@ namespace Dot.Git;
[Description(nameof(Str.GitTool))]
[Localization(typeof(Str))]
internal class Main : ToolBase<Option>
internal sealed class Main : ToolBase<Option>
{
private Encoding _gitOutputEnc; //git command rsp 编码
private ConcurrentDictionary<string, StringBuilder> _repoRsp; //仓库信息容器
private ConcurrentDictionary<string, TaskStatusColumn.Statues> _repoStatus;
protected override Task Core()
{
return !Directory.Exists(Opt.Path)
? throw new ArgumentException( //
nameof(Opt.Path) //
, string.Format(CultureInfo.InvariantCulture, Str.PathNotFound, Opt.Path))
: CoreInternal();
}
private async Task CoreInternal()
{
_gitOutputEnc = Encoding.GetEncoding(Opt.GitOutputEncoding);
var progressBar = new ProgressBarColumn { Width = 10 };
await AnsiConsole.Progress()
.Columns(progressBar //
.Columns( //
progressBar //
, new ElapsedTimeColumn() //
, new SpinnerColumn() //
, new TaskStatusColumn() //
, new TaskDescriptionColumn { Alignment = Justify.Left } //
)
, new TaskDescriptionColumn { Alignment = Justify.Left }) //
.StartAsync(async ctx => {
var taskFinder = ctx.AddTask(string.Format(Str.FindGitReps, Opt.Path)).IsIndeterminate();
var taskFinder = ctx
.AddTask(string.Format(CultureInfo.InvariantCulture, Str.FindGitReps
, Opt.Path))
.IsIndeterminate();
var paths = Directory.GetDirectories(Opt.Path, ".git" //
, new EnumerationOptions //
{
MaxRecursionDepth = Opt.MaxRecursionDepth
, RecurseSubdirectories = true
, IgnoreInaccessible = true
, AttributesToSkip
= FileAttributes.ReparsePoint
, AttributesToSkip = FileAttributes.ReparsePoint
})
.Select(x => Directory.GetParent(x)!.FullName);
@ -43,8 +55,8 @@ internal class Main : ToolBase<Option>
_repoStatus = new ConcurrentDictionary<string, TaskStatusColumn.Statues>();
var tasks = new Dictionary<string, ProgressTask>();
foreach (var path in paths) {
_repoRsp.TryAdd(path, new StringBuilder());
_repoStatus.TryAdd(path, default);
_ = _repoRsp.TryAdd(path, new StringBuilder());
_ = _repoStatus.TryAdd(path, default);
var task = ctx.AddTask(new DirectoryInfo(path).Name, false).IsIndeterminate();
tasks.Add(path, task);
}
@ -79,13 +91,15 @@ internal class Main : ToolBase<Option>
// 打印 git command rsp
void ExecRspReceived(object sender, DataReceivedEventArgs e)
{
if (e.Data is null) return;
if (e.Data is null) {
return;
}
var msg = Encoding.UTF8.GetString(_gitOutputEnc.GetBytes(e.Data));
_repoRsp[payload.Key].Append(msg.EscapeMarkup());
}
// 启动git进程
var startInfo = new ProcessStartInfo {
CreateNoWindow = true
, WorkingDirectory = payload.Key
@ -116,12 +130,4 @@ internal class Main : ToolBase<Option>
payload.Value.StopTask();
}
protected override Task Core()
{
if (!Directory.Exists(Opt.Path))
throw new ArgumentException(nameof(Opt.Path) //
, string.Format(Str.PathNotFound, Opt.Path));
return CoreInternal();
}
}

View File

@ -3,7 +3,7 @@
namespace Dot.Git;
internal class Option : OptionBase
internal sealed class Option : OptionBase
{
[CommandOption("-a|--args")]
[Description(nameof(Str.GitArgs))]

View File

@ -4,6 +4,6 @@ internal static class ProgressTaskStateExtensions
{
public static void Status(this ProgressTaskState me, TaskStatusColumn.Statues value)
{
me.Update<TaskStatusColumn.Statues>(nameof(TaskStatusColumn), _ => value);
_ = me.Update<TaskStatusColumn.Statues>(nameof(TaskStatusColumn), _ => value);
}
}

View File

@ -6,11 +6,12 @@ using Spectre.Console.Rendering;
namespace Dot.Git;
internal class TaskStatusColumn : ProgressColumn
internal sealed class TaskStatusColumn : ProgressColumn
{
public enum Statues : byte
{
[Description($"[gray]{nameof(Ready)}[/]")]
// ReSharper disable once UnusedMember.Global
Ready
@ -27,6 +28,9 @@ internal class TaskStatusColumn : ProgressColumn
/// <summary>
/// Gets or sets the alignment of the task description.
/// </summary>
/// <value>
/// The alignment of the task description.
/// </value>
public Justify Alignment { get; set; } = Justify.Right;
/// <inheritdoc />

View File

@ -1,4 +1,4 @@
global using System.ComponentModel;
global using Dot.Lang;
global using Spectre.Console;
global using Spectre.Console.Cli;
global using Dot.Lang;

View File

@ -1,5 +1,6 @@
// ReSharper disable ClassNeverInstantiated.Global
using System.Globalization;
#if NET7_0_WINDOWS
using TextCopy;
#endif
@ -13,7 +14,10 @@ internal sealed class Main : ToolBase<Option>
protected override Task Core()
{
var guid = System.Guid.NewGuid().ToString();
if (Opt.Upper) guid = guid.ToUpper();
if (Opt.Upper) {
guid = guid.ToUpper(CultureInfo.InvariantCulture);
}
Console.WriteLine(Str.Copied, guid);
#if NET7_0_WINDOWS
ClipboardService.SetText(guid);

View File

@ -3,7 +3,7 @@
namespace Dot.Guid;
internal class Option : OptionBase
internal sealed class Option : OptionBase
{
[CommandOption("-u|--upper")]
[Description(nameof(Str.UseUppercase))]

View File

@ -1,3 +1,3 @@
namespace Dot;
public interface IOption { }
internal interface IOption { }

View File

@ -8,18 +8,19 @@ namespace Dot.IP;
[Description(nameof(Str.Ip))]
[Localization(typeof(Str))]
internal sealed class Main : ToolBase<Option>
{
protected override async Task Core()
{
foreach (var item in NetworkInterface.GetAllNetworkInterfaces()) {
if (item.NetworkInterfaceType != NetworkInterfaceType.Ethernet ||
item.OperationalStatus != OperationalStatus.Up)
item.OperationalStatus != OperationalStatus.Up) {
continue;
var output = string.Join(Environment.NewLine
}
var output = string.Join( //
Environment.NewLine
, item.GetIPProperties()
.UnicastAddresses
.Where(x => x.Address.AddressFamily == AddressFamily.InterNetwork)
.UnicastAddresses.Where(x => x.Address.AddressFamily == AddressFamily.InterNetwork)
.Select(x => @$"{item.Name}: {x.Address}"));
Console.WriteLine(output);
}

View File

@ -2,4 +2,4 @@
namespace Dot.IP;
internal class Option : OptionBase { }
internal sealed class Option : OptionBase { }

View File

@ -10,58 +10,22 @@ namespace Dot.Json;
[Description(nameof(Str.Json))]
[Localization(typeof(Str))]
internal class Main : ToolBase<Option>
internal sealed class Main : ToolBase<Option>
{
private object _inputObj;
private async Task<string> ConvertToString()
{
var ret = await JsonCompress();
ret = ret.Replace("\"", "\\\"");
return ret;
}
private async Task CoreInternal()
{
string result = null;
if (Opt.Compress)
result = await JsonCompress();
else if (Opt.ConvertToString)
result = await ConvertToString();
else if (Opt.Format) result = await JsonFormat();
if (!result.NullOrWhiteSpace()) {
#if NET7_0_WINDOWS
await ClipboardService.SetTextAsync(result!);
#endif
}
}
private Task<string> JsonCompress()
{
var ret = _inputObj.Json();
return Task.FromResult(ret);
}
private Task<string> JsonFormat()
{
var ret = _inputObj.Json(true);
return Task.FromResult(ret);
}
private static string UnescapeString(string text)
{
return text.Replace("\\\"", "\"");
}
protected override Task Core()
{
var inputText = Opt.InputText;
#if NET7_0_WINDOWS
if (inputText.NullOrWhiteSpace()) inputText = ClipboardService.GetText();
if (inputText.NullOrWhiteSpace()) {
inputText = ClipboardService.GetText();
}
#endif
if (inputText.NullOrWhiteSpace()) throw new ArgumentException(Str.InputTextIsEmpty);
if (inputText.NullOrWhiteSpace()) {
throw new ArgumentException(Str.InputTextIsEmpty);
}
try {
_inputObj = inputText.Object<object>();
@ -81,4 +45,48 @@ internal class Main : ToolBase<Option>
return CoreInternal();
}
private static string UnescapeString(string text)
{
return text.Replace("\\\"", "\"");
}
private async Task<string> ConvertToString()
{
var ret = await JsonCompress();
ret = ret.Replace("\"", "\\\"");
return ret;
}
private async Task CoreInternal()
{
string result = null;
if (Opt.Compress) {
result = await JsonCompress();
}
else if (Opt.ConvertToString) {
result = await ConvertToString();
}
else if (Opt.Format) {
result = await JsonFormat();
}
if (!result.NullOrWhiteSpace()) {
#if NET7_0_WINDOWS
await ClipboardService.SetTextAsync(result!);
#endif
}
}
private Task<string> JsonCompress()
{
var ret = _inputObj.Json();
return Task.FromResult(ret);
}
private Task<string> JsonFormat()
{
var ret = _inputObj.Json(true);
return Task.FromResult(ret);
}
}

View File

@ -3,7 +3,7 @@
namespace Dot.Json;
internal class Option : OptionBase
internal sealed class Option : OptionBase
{
[CommandOption("-c|--compress")]
[Description(nameof(Str.CompressJson))]

View File

@ -135,7 +135,6 @@
<value>密码长度</value>
</data>
<data name="PwdGenerateTypes" xml:space="preserve">
<value>BitSet 1[0-9]2[a-z]4[A-Z]8[ascii.0x21-0x2F]</value>
</data>

View File

@ -27,7 +27,7 @@ namespace Dot.Lang {
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
internal class Str {
internal sealed class Str {
private static global::System.Resources.ResourceManager resourceMan;
@ -68,7 +68,8 @@ namespace Dot.Lang {
<#
var xml = new XmlDocument();
xml.Load("Str.resx");
foreach (XmlNode data in xml.SelectNodes("//root/data")!) {
foreach (XmlNode data in xml.SelectNodes("//root/data")!)
{
#>
/// <summary>
/// <#= data.SelectSingleNode("value")?.InnerText #>

View File

@ -1,30 +1,43 @@
using System.Globalization;
using System.Text;
using Dot;
using Dot.Git;
#if NET7_0_WINDOWS
using System.Runtime.InteropServices;
#endif
var app = new CommandApp();
namespace Dot;
app.Configure(config => {
internal sealed class Program
{
public static int Main(string[] args)
{
var app = new CommandApp();
app.Configure(config => {
config.SetApplicationName(AssemblyInfo.ASSEMBLY_PRODUCT);
config.SetApplicationVersion(AssemblyInfo.ASSEMBLY_VERSION);
config.AddCommand<Main>(nameof(Dot.Git).ToLower());
config.AddCommand<Main>(nameof(Git).ToLower(CultureInfo.InvariantCulture));
#if NET7_0_WINDOWS
config.AddCommand<Dot.Color.Main>(nameof(Dot.Color).ToLower());
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
config.AddCommand<Color.Main>(nameof(Color).ToLower(CultureInfo.InvariantCulture));
}
#endif
config.AddCommand<Dot.Guid.Main>(nameof(Dot.Guid).ToLower());
config.AddCommand<Dot.IP.Main>(nameof(Dot.IP).ToLower());
config.AddCommand<Dot.Json.Main>(nameof(Dot.Json).ToLower());
config.AddCommand<Dot.Pwd.Main>(nameof(Dot.Pwd).ToLower());
config.AddCommand<Dot.Rbom.Main>(nameof(Dot.Rbom).ToLower());
config.AddCommand<Dot.Trim.Main>(nameof(Dot.Trim).ToLower());
config.AddCommand<Dot.Text.Main>(nameof(Dot.Text).ToLower());
config.AddCommand<Dot.Time.Main>(nameof(Dot.Time).ToLower());
config.AddCommand<Dot.ToLf.Main>(nameof(Dot.ToLf).ToLower());
config.AddCommand<Dot.Get.Main>(nameof(Dot.Get).ToLower());
config.AddCommand<Guid.Main>(nameof(Guid).ToLower(CultureInfo.InvariantCulture));
config.AddCommand<IP.Main>(nameof(IP).ToLower(CultureInfo.InvariantCulture));
config.AddCommand<Json.Main>(nameof(Json).ToLower(CultureInfo.InvariantCulture));
config.AddCommand<Pwd.Main>(nameof(Pwd).ToLower(CultureInfo.InvariantCulture));
config.AddCommand<Rbom.Main>(nameof(Rbom).ToLower(CultureInfo.InvariantCulture));
config.AddCommand<Trim.Main>(nameof(Trim).ToLower(CultureInfo.InvariantCulture));
config.AddCommand<Text.Main>(nameof(Text).ToLower(CultureInfo.InvariantCulture));
config.AddCommand<Time.Main>(nameof(Time).ToLower(CultureInfo.InvariantCulture));
config.AddCommand<ToLf.Main>(nameof(ToLf).ToLower(CultureInfo.InvariantCulture));
config.AddCommand<Get.Main>(nameof(Get).ToLower(CultureInfo.InvariantCulture));
config.ValidateExamples();
});
});
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
return app.Run(args);
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
return app.Run(args);
}
}

View File

@ -25,25 +25,34 @@ internal sealed class Main : ToolBase<Option>
var pDest = stackalloc char[Opt.Length];
var sourceLen = 0;
if (Opt.Type.HasFlag(Option.GenerateTypes.Number))
foreach (var c in _charTable[0])
if (Opt.Type.HasFlag(Option.GenerateTypes.Number)) {
foreach (var c in _charTable[0]) {
*(pSource + sourceLen++) = c;
}
}
if (Opt.Type.HasFlag(Option.GenerateTypes.LowerCaseLetter))
foreach (var c in _charTable[1])
if (Opt.Type.HasFlag(Option.GenerateTypes.LowerCaseLetter)) {
foreach (var c in _charTable[1]) {
*(pSource + sourceLen++) = c;
}
}
if (Opt.Type.HasFlag(Option.GenerateTypes.UpperCaseLetter))
foreach (var c in _charTable[2])
if (Opt.Type.HasFlag(Option.GenerateTypes.UpperCaseLetter)) {
foreach (var c in _charTable[2]) {
*(pSource + sourceLen++) = c;
}
}
if (Opt.Type.HasFlag(Option.GenerateTypes.SpecialCharacter))
foreach (var c in _charTable[3])
if (Opt.Type.HasFlag(Option.GenerateTypes.SpecialCharacter)) {
foreach (var c in _charTable[3]) {
*(pSource + sourceLen++) = c;
}
}
var randScope = new[] { 0, sourceLen };
for (var i = 0; i != Opt.Length; ++i) //
for (var i = 0; i != Opt.Length; ++i) {
*(pDest + i) = *(pSource + randScope.Rand());
}
var result = new string(pDest, 0, Opt.Length);
Console.WriteLine(Str.Copied, result);

View File

@ -3,7 +3,7 @@
namespace Dot.Pwd;
internal class Option : OptionBase
internal sealed class Option : OptionBase
{
[Flags]
public enum GenerateTypes

View File

@ -8,18 +8,6 @@ internal sealed class Main : FilesTool<Option>
{
private readonly byte[] _utf8Bom = { 0xef, 0xbb, 0xbf };
private bool CloneFileWithoutBom(Stream fsr, ref string tempFile)
{
Span<byte> buffer = stackalloc byte[_utf8Bom.Length];
var readLen = fsr.Read(buffer);
if (readLen != _utf8Bom.Length || !buffer.SequenceEqual(_utf8Bom)) return false;
using var fsw = CreateTempFile(out tempFile);
int data;
while ((data = fsr.ReadByte()) != -1) fsw.WriteByte((byte)data);
return true;
}
protected override async ValueTask FileHandle(string file, CancellationToken cancelToken)
{
ShowMessage(1, 0, 0);
@ -32,7 +20,10 @@ internal sealed class Main : FilesTool<Option>
}
if (CloneFileWithoutBom(fsr, ref tmpFile)) {
if (Opt.WriteMode) File.Copy(tmpFile, file, true);
if (Opt.WriteMode) {
File.Copy(tmpFile, file, true);
}
ShowMessage(0, 1, 0);
UpdateStats(Path.GetExtension(file));
}
@ -41,6 +32,26 @@ internal sealed class Main : FilesTool<Option>
}
}
if (tmpFile != default) File.Delete(tmpFile);
if (tmpFile != default) {
File.Delete(tmpFile);
}
}
private bool CloneFileWithoutBom(Stream fsr, ref string tempFile)
{
Span<byte> buffer = stackalloc byte[_utf8Bom.Length];
var readLen = fsr.Read(buffer);
if (readLen != _utf8Bom.Length || !buffer.SequenceEqual(_utf8Bom)) {
return false;
}
using var fsw = CreateTempFile(out tempFile);
int data;
while ((data = fsr.ReadByte()) != -1) {
fsw.WriteByte((byte)data);
}
return true;
}
}

View File

@ -2,4 +2,4 @@
namespace Dot.Rbom;
internal class Option : DirOption { }
internal sealed class Option : DirOption { }

22
src/Text/Main.Output.cs Normal file
View File

@ -0,0 +1,22 @@
namespace Dot.Text;
internal sealed partial class Main
{
private ref struct Output
{
public ReadOnlySpan<char> Base64;
public ReadOnlySpan<char> Base64DeCode;
public ReadOnlySpan<char> Base64DeCodeHex;
public ReadOnlySpan<char> EncodingName;
public ReadOnlySpan<char> Hex;
public ReadOnlySpan<char> HtmlDecode;
public ReadOnlySpan<char> HtmlEncode;
public ReadOnlySpan<char> Md5;
public ReadOnlySpan<char> OriginText;
public ReadOnlySpan<char> Sha1;
public ReadOnlySpan<char> Sha256;
public ReadOnlySpan<char> Sha512;
public ReadOnlySpan<char> UrlDecode;
public ReadOnlySpan<char> UrlEncode;
}
}

View File

@ -4,32 +4,35 @@ using System.Security.Cryptography;
using System.Text;
using NSExt.Extensions;
#if NET7_0_WINDOWS
using TextCopy;
using System.Diagnostics;
using TextCopy;
#endif
namespace Dot.Text;
[Description(nameof(Str.TextTool))]
[Localization(typeof(Str))]
internal sealed class Main : ToolBase<Option>
internal sealed partial class Main : ToolBase<Option>
{
private ref struct Output
#if NET7_0_WINDOWS
protected override async Task Core()
#else
protected override Task Core()
#endif
{
public ReadOnlySpan<char> Base64;
public ReadOnlySpan<char> Base64DeCode;
public ReadOnlySpan<char> Base64DeCodeHex;
public ReadOnlySpan<char> EncodingName;
public ReadOnlySpan<char> Hex;
public ReadOnlySpan<char> HtmlDecode;
public ReadOnlySpan<char> HtmlEncode;
public ReadOnlySpan<char> Md5;
public ReadOnlySpan<char> OriginText;
public ReadOnlySpan<char> Sha1;
public ReadOnlySpan<char> Sha256;
public ReadOnlySpan<char> Sha512;
public ReadOnlySpan<char> UrlDecode;
public ReadOnlySpan<char> UrlEncode;
#if NET7_0_WINDOWS
if (Opt.Text.NullOrEmpty()) {
Opt.Text = await ClipboardService.GetTextAsync();
}
#endif
if (Opt.Text.NullOrEmpty()) {
throw new ArgumentException(Str.InputTextIsEmpty);
}
ParseAndShow(Opt.Text);
#if !NET7_0_WINDOWS
return Task.CompletedTask;
#endif
}
private static Output BuildOutput(string text, Encoding enc)
@ -51,7 +54,10 @@ internal sealed class Main : ToolBase<Option>
ret.HtmlDecode = text.HtmlDe();
ret.HtmlEncode = text.Html();
if (!text.IsBase64String()) return ret;
if (!text.IsBase64String()) {
return ret;
}
byte[] base64DeHex = null;
try {
base64DeHex = text.Base64De();
@ -60,7 +66,10 @@ internal sealed class Main : ToolBase<Option>
// ignored
}
if (base64DeHex == null) return ret;
if (base64DeHex == null) {
return ret;
}
ret.Base64DeCodeHex = base64DeHex.String();
ret.Base64DeCode = enc.GetString(base64DeHex);
@ -105,21 +114,4 @@ html-decode: {o.HtmlDecode}
Process.Start("explorer", file);
#endif
}
#if NET7_0_WINDOWS
protected override async Task Core()
#else
protected override Task Core()
#endif
{
#if NET7_0_WINDOWS
if (Opt.Text.NullOrEmpty()) Opt.Text = await ClipboardService.GetTextAsync();
#endif
if (Opt.Text.NullOrEmpty()) throw new ArgumentException(Str.InputTextIsEmpty);
ParseAndShow(Opt.Text);
#if !NET7_0_WINDOWS
return Task.CompletedTask;
#endif
}
}

View File

@ -2,7 +2,7 @@
namespace Dot.Text;
internal class Option : OptionBase
internal sealed class Option : OptionBase
{
[CommandArgument(0, "[input text]")]
[Description(nameof(Str.TextTobeProcessed))]

View File

@ -1,5 +1,6 @@
// ReSharper disable ClassNeverInstantiated.Global
using System.Globalization;
using System.Net.Sockets;
namespace Dot.Time;
@ -33,6 +34,81 @@ internal sealed class Main : ToolBase<Option>
private int _successCnt;
protected override async Task Core()
{
await AnsiConsole.Progress()
.Columns( //
new TaskDescriptionColumn() //
, new ProgressBarColumn() //
, new ElapsedTimeColumn() //
, new SpinnerColumn() //
, new TaskStatusColumn() //
, new TaskResultColumn())
.StartAsync(async ctx => {
var tasks = _ntpServers.ToDictionary( //
server => server, server => ctx.AddTask(server, false).IsIndeterminate());
await Parallel.ForEachAsync(
tasks, new ParallelOptions { MaxDegreeOfParallelism = _MAX_DEGREE_OF_PARALLELISM }
, ServerHandle);
_offsetAvg = tasks.Where(x => x.Value.State.Status() == TaskStatusColumn.Statues.Succeed)
.Average(x => x.Value.State.Result().TotalMilliseconds);
});
AnsiConsole.MarkupLine(CultureInfo.InvariantCulture, Str.NtpReceiveDone, $"[green]{_successCnt}[/]"
, _ntpServers.Length, $"[yellow]{_offsetAvg:f2}[/]");
if (Opt.Sync) {
SetSysteTime(DateTime.Now.AddMilliseconds(-_offsetAvg));
AnsiConsole.MarkupLine($"[green]{Str.LocalTimeSyncDone}[/]");
}
}
protected override async Task Run()
{
await Core();
if (Opt.KeepSession) {
var table = new Table().HideHeaders()
.AddColumn(new TableColumn(string.Empty))
.AddColumn(new TableColumn(string.Empty))
.Caption(Str.PressAnyKey)
.AddRow(Str.NtpClock, DateTime.Now.AddMilliseconds(-_offsetAvg).ToString("O"))
.AddRow(Str.LocalClock, DateTime.Now.ToString("O"));
var cts = new CancellationTokenSource();
var task = AnsiConsole.Live(table)
.StartAsync(async ctx => {
while (!cts.IsCancellationRequested) {
ctx.UpdateTarget(
table.UpdateCell(
0, 1, DateTime.Now.AddMilliseconds(-_offsetAvg).ToString("O"))
.UpdateCell(1, 1, DateTime.Now.ToString("O")));
await Task.Delay(100, CancellationToken.None);
}
});
_ = await AnsiConsole.Console.Input.ReadKeyAsync(true, cts.Token);
cts.Cancel();
await task;
}
}
private static void SetSysteTime(DateTime time)
{
var timeToSet = new Win32.Systemtime {
wDay = (ushort)time.Day
, wDayOfWeek = (ushort)time.DayOfWeek
, wHour = (ushort)time.Hour
, wMilliseconds = (ushort)time.Millisecond
, wMinute = (ushort)time.Minute
, wMonth = (ushort)time.Month
, wSecond = (ushort)time.Second
, wYear = (ushort)time.Year
};
Win32.SetLocalTime(timeToSet);
}
private TimeSpan GetNtpOffset(string server)
{
Span<byte> ntpData = stackalloc byte[48];
@ -44,9 +120,9 @@ internal sealed class Main : ToolBase<Option>
try {
socket.Connect(server, _NTP_PORT);
socket.Send(ntpData);
_ = socket.Send(ntpData);
var timeBefore = DateTime.Now;
socket.Receive(ntpData);
_ = socket.Receive(ntpData);
var transferTime = DateTime.Now - timeBefore;
var intPart = ((ulong)ntpData[40] << 24) //
@ -86,79 +162,4 @@ internal sealed class Main : ToolBase<Option>
payload.Value.StopTask();
return ValueTask.CompletedTask;
}
private static void SetSysteTime(DateTime time)
{
var timeToSet = new Win32.Systemtime {
wDay = (ushort)time.Day
, wDayOfWeek = (ushort)time.DayOfWeek
, wHour = (ushort)time.Hour
, wMilliseconds = (ushort)time.Millisecond
, wMinute = (ushort)time.Minute
, wMonth = (ushort)time.Month
, wSecond = (ushort)time.Second
, wYear = (ushort)time.Year
};
Win32.SetLocalTime(timeToSet);
}
protected override async Task Core()
{
await AnsiConsole.Progress()
.Columns(new TaskDescriptionColumn() //
, new ProgressBarColumn() //
, new ElapsedTimeColumn() //
, new SpinnerColumn() //
, new TaskStatusColumn() //
, new TaskResultColumn())
.StartAsync(async ctx => {
var tasks = _ntpServers.ToDictionary(server => server
, server => ctx.AddTask(server, false)
.IsIndeterminate());
await Parallel.ForEachAsync(
tasks, new ParallelOptions { MaxDegreeOfParallelism = _MAX_DEGREE_OF_PARALLELISM }
, ServerHandle);
_offsetAvg = tasks.Where(x => x.Value.State.Status() == TaskStatusColumn.Statues.Succeed)
.Average(x => x.Value.State.Result().TotalMilliseconds);
});
AnsiConsole.MarkupLine(Str.NtpReceiveDone, $"[green]{_successCnt}[/]", _ntpServers.Length
, $"[yellow]{_offsetAvg:f2}[/]");
if (Opt.Sync) {
SetSysteTime(DateTime.Now.AddMilliseconds(-_offsetAvg));
AnsiConsole.MarkupLine($"[green]{Str.LocalTimeSyncDone}[/]");
}
}
protected override async Task Run()
{
await Core();
if (Opt.KeepSession) {
var table = new Table().HideHeaders()
.AddColumn(new TableColumn(string.Empty))
.AddColumn(new TableColumn(string.Empty))
.Caption(Str.PressAnyKey)
.AddRow(Str.NtpClock, DateTime.Now.AddMilliseconds(-_offsetAvg).ToString("O"))
.AddRow(Str.LocalClock, DateTime.Now.ToString("O"));
var cts = new CancellationTokenSource();
var task = AnsiConsole.Live(table)
.StartAsync(async ctx => {
while (!cts.IsCancellationRequested) {
ctx.UpdateTarget(
table.UpdateCell(
0, 1, DateTime.Now.AddMilliseconds(-_offsetAvg).ToString("O"))
.UpdateCell(1, 1, DateTime.Now.ToString("O")));
await Task.Delay(100);
}
});
await AnsiConsole.Console.Input.ReadKeyAsync(true, cts.Token);
cts.Cancel();
await task;
}
}
}

View File

@ -3,7 +3,7 @@
namespace Dot.Time;
internal class Option : OptionBase
internal sealed class Option : OptionBase
{
[CommandOption("-s|--sync")]
[Description(nameof(Str.SyncToLocalTime))]

View File

@ -9,7 +9,7 @@ internal static class ProgressTaskStateExtensions
public static void Result(this ProgressTaskState me, TimeSpan value)
{
me.Update<TimeSpan>(nameof(TaskResultColumn), _ => value);
_ = me.Update<TimeSpan>(nameof(TaskResultColumn), _ => value);
}
public static TaskStatusColumn.Statues Status(this ProgressTaskState me)
@ -19,6 +19,6 @@ internal static class ProgressTaskStateExtensions
public static void Status(this ProgressTaskState me, TaskStatusColumn.Statues value)
{
me.Update<TaskStatusColumn.Statues>(nameof(TaskStatusColumn), _ => value);
_ = me.Update<TaskStatusColumn.Statues>(nameof(TaskStatusColumn), _ => value);
}
}

View File

@ -5,11 +5,14 @@ using Spectre.Console.Rendering;
namespace Dot.Time;
internal class TaskResultColumn : ProgressColumn
internal sealed class TaskResultColumn : ProgressColumn
{
/// <summary>
/// Gets or sets the alignment of the task description.
/// </summary>
/// <value>
/// The alignment of the task description.
/// </value>
public Justify Alignment { get; set; } = Justify.Right;
/// <inheritdoc />

View File

@ -6,12 +6,12 @@ using Spectre.Console.Rendering;
namespace Dot.Time;
internal class TaskStatusColumn : ProgressColumn
internal sealed class TaskStatusColumn : ProgressColumn
{
public enum Statues : byte
{
[Description($"[gray]{nameof(Ready)}[/]")]
// ReSharper disable once UnusedMember.Global
[Description($"[gray]{nameof(Ready)}[/]")]
Ready
, [Description($"[yellow]{nameof(Connecting)}[/]")]
@ -27,6 +27,9 @@ internal class TaskStatusColumn : ProgressColumn
/// <summary>
/// Gets or sets the alignment of the task description.
/// </summary>
/// <value>
/// The alignment of the task description.
/// </value>
public Justify Alignment { get; set; } = Justify.Right;
/// <inheritdoc />

View File

@ -13,6 +13,7 @@ internal sealed class Main : FilesTool<Option>
var hasWrote = false;
var isBin = false;
string tmpFile;
// ReSharper disable once TooWideLocalVariableScope
int data;
@ -32,7 +33,7 @@ internal sealed class Main : FilesTool<Option>
continue;
case 0x0d: //cr macos
fsw.WriteByte(0x0a);
fsr.Seek(-1, SeekOrigin.Current);
_ = fsr.Seek(-1, SeekOrigin.Current);
hasWrote = true;
continue;
case 0x00 or 0xff: //非文本文件
@ -47,10 +48,11 @@ internal sealed class Main : FilesTool<Option>
}
}
#pragma warning disable S2583
if (hasWrote && !isBin) {
#pragma warning restore S2583
if (Opt.WriteMode) File.Copy(tmpFile, file, true);
if (Opt.WriteMode) {
File.Copy(tmpFile, file, true);
}
ShowMessage(0, 1, 0);
UpdateStats(Path.GetExtension(file));
}

View File

@ -2,4 +2,4 @@
namespace Dot.ToLf;
internal class Option : DirOption { }
internal sealed class Option : DirOption { }

View File

@ -1,18 +1,9 @@
namespace Dot;
internal abstract class ToolBase<TOption> : Command<TOption> where TOption : OptionBase
internal abstract class ToolBase<TOption> : Command<TOption>
where TOption : OptionBase
{
protected TOption Opt { get; private set; }
protected abstract Task Core();
protected virtual async Task Run()
{
await Core();
if (Opt.KeepSession) {
AnsiConsole.MarkupLine(Str.PressAnyKey);
AnsiConsole.Console.Input.ReadKey(true);
}
}
public override int Execute(CommandContext context, TOption settings)
{
@ -20,4 +11,15 @@ internal abstract class ToolBase<TOption> : Command<TOption> where TOption : Opt
Run().Wait();
return 0;
}
protected abstract Task Core();
protected virtual async Task Run()
{
await Core();
if (Opt.KeepSession) {
AnsiConsole.MarkupLine(Str.PressAnyKey);
_ = AnsiConsole.Console.Input.ReadKey(true);
}
}
}

View File

@ -8,24 +8,6 @@ namespace Dot.Trim;
[Localization(typeof(Str))]
internal sealed class Main : FilesTool<Option>
{
private static int GetSpacesCnt(Stream fsr)
{
var trimLen = 0;
fsr.Seek(-1, SeekOrigin.End);
int data;
while ((data = fsr.ReadByte()) != -1)
if (new[] { 0x20, 0x0d, 0x0a }.Contains(data)) {
++trimLen;
if (fsr.Position - 2 < 0) break;
fsr.Seek(-2, SeekOrigin.Current);
}
else {
break;
}
return trimLen;
}
protected override async ValueTask FileHandle(string file, CancellationToken cancelToken)
{
ShowMessage(1, 0, 0);
@ -38,14 +20,39 @@ internal sealed class Main : FilesTool<Option>
return;
}
fsrw.Seek(0, SeekOrigin.Begin);
_ = fsrw.Seek(0, SeekOrigin.Begin);
if (!fsrw.IsTextStream()) {
ShowMessage(0, 0, 1);
return;
}
if (Opt.WriteMode) fsrw.SetLength(fsrw.Length - spacesCnt);
if (Opt.WriteMode) {
fsrw.SetLength(fsrw.Length - spacesCnt);
}
ShowMessage(0, 1, 0);
UpdateStats(Path.GetExtension(file));
}
private static int GetSpacesCnt(Stream fsr)
{
var trimLen = 0;
_ = fsr.Seek(-1, SeekOrigin.End);
int data;
while ((data = fsr.ReadByte()) != -1) {
if (new[] { 0x20, 0x0d, 0x0a }.Contains(data)) {
++trimLen;
if (fsr.Position - 2 < 0) {
break;
}
_ = fsr.Seek(-2, SeekOrigin.Current);
}
else {
break;
}
}
return trimLen;
}
}

View File

@ -2,4 +2,4 @@
namespace Dot.Trim;
internal class Option : DirOption { }
internal sealed class Option : DirOption { }

View File

@ -5,27 +5,13 @@ using System.Runtime.InteropServices;
namespace Dot;
public static partial class Win32
internal static partial class Win32
{
[StructLayout(LayoutKind.Explicit)]
internal ref struct Systemtime
{
[FieldOffset(6)] public ushort wDay;
[FieldOffset(4)] public ushort wDayOfWeek;
[FieldOffset(8)] public ushort wHour;
[FieldOffset(14)] public ushort wMilliseconds;
[FieldOffset(10)] public ushort wMinute;
[FieldOffset(2)] public ushort wMonth;
[FieldOffset(12)] public ushort wSecond;
[FieldOffset(0)] public ushort wYear;
}
public delegate nint LowLevelMouseProc(int nCode, nint wParam, nint lParam);
public const int SW_HIDE = 0;
private const string _GDI32_DLL = "gdi32.dll";
private const string _KERNEL32_DLL = "kernel32.dll";
private const string _USER32_DLL = "user32.dll";
public const int SW_HIDE = 0;
[LibraryImport(_USER32_DLL)]
internal static partial nint CallNextHookEx(nint hhk, int nCode, nint wParam, nint lParam);
@ -52,7 +38,8 @@ public static partial class Win32
internal static partial void SetLocalTime(Systemtime st);
[LibraryImport(_USER32_DLL)]
internal static partial nint SetWindowsHookEx(int idHook, LowLevelMouseProc lpfn, nint hMod, uint dwThreadId);
internal static partial nint SetWindowsHookEx(int idHook, Func<int, nint, nint, nint> lpfn, nint hMod
, uint dwThreadId);
[LibraryImport(_USER32_DLL)]
[return: MarshalAs(UnmanagedType.Bool)]
@ -61,4 +48,19 @@ public static partial class Win32
[LibraryImport(_USER32_DLL)]
[return: MarshalAs(UnmanagedType.Bool)]
internal static partial bool UnhookWindowsHookEx(nint hhk);
[StructLayout(LayoutKind.Explicit)]
internal ref struct Systemtime
{
#pragma warning disable SA1307
[FieldOffset(6)] public ushort wDay;
[FieldOffset(4)] public ushort wDayOfWeek;
[FieldOffset(8)] public ushort wHour;
[FieldOffset(14)] public ushort wMilliseconds;
[FieldOffset(10)] public ushort wMinute;
[FieldOffset(2)] public ushort wMonth;
[FieldOffset(12)] public ushort wSecond;
[FieldOffset(0)] public ushort wYear;
#pragma warning restore SA1307
}
}

View File

@ -1,13 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<GenerateDocumentationFile>true</GenerateDocumentationFile>
<OutputType>Exe</OutputType>
<RootNamespace>Dot</RootNamespace>
<TargetFrameworks>net7.0-windows;net7.0</TargetFrameworks>
<UseWindowsForms Condition="'$(TargetFramework)' == 'net7.0-windows'">true</UseWindowsForms>
<RootNamespace>Dot</RootNamespace>
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<NoWarn>CA1416;S1075</NoWarn>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<CodeAnalysisRuleSet>../StyleCopAnalyzers.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<PropertyGroup Condition="'$(TargetFramework)' == 'net7.0-windows'">
<DefineConstants>$(DefineConstants);NET7_0_WINDOWS</DefineConstants>
@ -16,10 +15,6 @@
<PackageReference Include="NSExt" Version="1.0.9-alpha.0.1"/>
<PackageReference Include="Spectre.Console.Cli.NS" Version="0.45.1-preview.0.48"/>
<PackageReference Include="Spectre.Console.NS" Version="0.45.1-preview.0.48"/>
<PackageReference Include="StyleCop.Analyzers" Version="1.2.0-beta.435">
<PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference>
<PackageReference Condition="'$(TargetFramework)' == 'net7.0-windows'" Include="TextCopy" Version="6.2.0"/>
</ItemGroup>
<ItemGroup>
@ -28,11 +23,6 @@
<LastGenOutput>Str.Designer.cs</LastGenOutput>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Reference Include="Spectre.Console">
<HintPath>..\..\..\..\..\ForkedGitReps\spectre.console\src\Spectre.Console\bin\Debug\net6.0\Spectre.Console.dll</HintPath>
</Reference>
</ItemGroup>
<Import Project="../SonarqubleAnalyzer.props"/>
<Import Project="../CodeQuality.props"/>
<Import Project="../GenerateResx.targets"/>
</Project>

9
stylecop.json Normal file
View File

@ -0,0 +1,9 @@
{
"$schema": "https://raw.githubusercontent.com/DotNetAnalyzers/StyleCopAnalyzers/master/StyleCop.Analyzers/StyleCop.Analyzers/Settings/stylecop.schema.json",
"settings": {
"indentation": {
"useTabs": false,
"indentationSize": 4
}
}
}

View File

@ -5,12 +5,6 @@ namespace Dot.Tests;
public class TestGet
{
private static string GetFileSha1(string file)
{
using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return BitConverter.ToString(SHA1.HashData(fs));
}
[Test]
public void DownloadFile()
{
@ -35,4 +29,10 @@ public class TestGet
[SetUp]
public void Setup() { }
private static string GetFileSha1(string file)
{
using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite);
return BitConverter.ToString(SHA1.HashData(fs));
}
}