mirror of
https://github.com/nsnail/dot.git
synced 2025-06-17 21:13:21 +08:00
<chore> CodeQuality
This commit is contained in:
commit
0e07289747
@ -1,12 +1,27 @@
|
|||||||
root = true
|
root = true
|
||||||
|
|
||||||
[*]
|
[*]
|
||||||
indent_style = space
|
|
||||||
indent_size = 4
|
|
||||||
end_of_line = lf
|
|
||||||
charset = utf-8
|
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
|
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 properties
|
||||||
resharper_align_linq_query = true
|
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_multline_type_parameter_list = true
|
||||||
resharper_align_tuple_components = true
|
resharper_align_tuple_components = true
|
||||||
resharper_allow_comment_after_lbrace = 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_empty_block_style = together_same_line
|
||||||
resharper_csharp_outdent_commas = true
|
resharper_csharp_outdent_commas = true
|
||||||
|
resharper_csharp_place_type_constraints_on_same_line = false
|
||||||
resharper_csharp_stick_comment = false
|
resharper_csharp_stick_comment = false
|
||||||
resharper_csharp_wrap_before_comma = true
|
resharper_csharp_wrap_before_comma = true
|
||||||
resharper_indent_nested_foreach_stmt = true
|
|
||||||
resharper_indent_nested_for_stmt = true
|
resharper_indent_nested_for_stmt = true
|
||||||
|
resharper_indent_nested_foreach_stmt = true
|
||||||
resharper_indent_nested_while_stmt = true
|
resharper_indent_nested_while_stmt = true
|
||||||
resharper_indent_preprocessor_if = usual_indent
|
resharper_indent_preprocessor_if = usual_indent
|
||||||
resharper_indent_preprocessor_other = usual_indent
|
resharper_indent_preprocessor_other = usual_indent
|
||||||
resharper_int_align = true
|
resharper_int_align = true
|
||||||
resharper_keep_existing_arrangement = false
|
resharper_keep_existing_arrangement = false
|
||||||
resharper_place_linq_into_on_new_line = 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_place_simple_switch_expression_on_single_line = true
|
||||||
resharper_wrap_before_eq = true
|
resharper_wrap_before_eq = true
|
||||||
resharper_wrap_chained_method_calls = chop_if_long
|
resharper_wrap_chained_method_calls = chop_if_long
|
||||||
resharper_wrap_switch_expression = chop_if_long
|
resharper_wrap_switch_expression = chop_if_long
|
||||||
|
|
||||||
|
|
||||||
# Microsoft .NET properties
|
# Microsoft .NET properties
|
||||||
csharp_indent_braces = false
|
csharp_indent_braces = false
|
||||||
csharp_new_line_before_open_brace = local_functions, methods, types
|
csharp_new_line_before_open_brace = local_functions, methods, types
|
17
CodeQuality.props
Normal file
17
CodeQuality.props
Normal 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>
|
@ -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>
|
|
@ -1,9 +1,12 @@
|
|||||||
<?xml version="1.0"?>
|
<?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">
|
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpecialRules">
|
||||||
<Rule Id="SA0001" Action="Warning"/> <!-- XML comment analysis disabled -->
|
<Rule Id="SA0001" Action="Warning"/> <!-- XML comment analysis disabled -->
|
||||||
<Rule Id="SA0002" Action="Warning"/> <!-- Invalid settings file -->
|
<Rule Id="SA0002" Action="Warning"/> <!-- Invalid settings file -->
|
||||||
</Rules>
|
</Rules>
|
||||||
|
|
||||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpacingRules">
|
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.SpacingRules">
|
||||||
<Rule Id="SA1000" Action="Warning"/> <!-- Keywords should be spaced correctly -->
|
<Rule Id="SA1000" Action="Warning"/> <!-- Keywords should be spaced correctly -->
|
||||||
<Rule Id="SA1001" Action="None"/> <!-- Commas should be spaced correctly -->
|
<Rule Id="SA1001" Action="None"/> <!-- Commas should be spaced correctly -->
|
||||||
@ -13,7 +16,7 @@
|
|||||||
<Rule Id="SA1005" Action="None"/> <!-- Single line comments 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="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="SA1007" Action="Warning"/> <!-- Operator keyword should be followed by space -->
|
||||||
<Rule Id="SA1008" Action="Warning" /> <!-- Opening parenthesis should be spaced correctly -->
|
<Rule Id="SA1008" Action="None"/> <!-- Opening parenthesis should be spaced correctly -->
|
||||||
<Rule Id="SA1009" Action="Warning"/> <!-- Closing 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="SA1010" Action="Warning"/> <!-- Opening square brackets should be spaced correctly -->
|
||||||
<Rule Id="SA1011" Action="Warning"/> <!-- Closing square brackets should be spaced correctly -->
|
<Rule Id="SA1011" Action="Warning"/> <!-- Closing square brackets should be spaced correctly -->
|
||||||
@ -46,15 +49,15 @@
|
|||||||
<Rule Id="SA1106" Action="Warning"/> <!-- Code should not contain empty statements -->
|
<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="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="SA1108" Action="Warning"/> <!-- Block statements should not contain embedded comments -->
|
||||||
<Rule Id="SA1109" Action="None" /> <!-- Block statements should not contain embedded regions -->
|
<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="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="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="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="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="SA1114" Action="Warning"/> <!-- Parameter list should follow declaration -->
|
||||||
<Rule Id="SA1115" Action="Warning"/> <!-- Parameter should follow comma -->
|
<Rule Id="SA1115" Action="Warning"/> <!-- Parameter should follow comma -->
|
||||||
<Rule Id="SA1116" Action="Warning"/> <!-- Split parameters should start on line after declaration -->
|
<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="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="SA1118" Action="Warning"/> <!-- Parameter should not span multiple lines -->
|
||||||
<Rule Id="SA1120" Action="None"/> <!-- Comments should contain text -->
|
<Rule Id="SA1120" Action="None"/> <!-- Comments should contain text -->
|
||||||
<Rule Id="SA1121" Action="Warning"/> <!-- Use built-in type alias -->
|
<Rule Id="SA1121" Action="Warning"/> <!-- Use built-in type alias -->
|
||||||
@ -62,7 +65,7 @@
|
|||||||
<Rule Id="SA1123" Action="Warning"/> <!-- Do not place regions within elements -->
|
<Rule Id="SA1123" Action="Warning"/> <!-- Do not place regions within elements -->
|
||||||
<Rule Id="SA1124" Action="Warning"/> <!-- Do not use regions -->
|
<Rule Id="SA1124" Action="Warning"/> <!-- Do not use regions -->
|
||||||
<Rule Id="SA1125" Action="Warning"/> <!-- Use shorthand for nullable types -->
|
<Rule Id="SA1125" Action="Warning"/> <!-- Use shorthand for nullable types -->
|
||||||
<Rule Id="SA1126" Action="None" /> <!-- Prefix calls correctly -->
|
<Rule Id="SA1126" Action="Warning"/> <!-- Prefix calls correctly -->
|
||||||
<Rule Id="SA1127" Action="Warning"/> <!-- Generic type constraints should be on their own line -->
|
<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="SA1128" Action="Warning"/> <!-- Put constructor initializers on their own line -->
|
||||||
<Rule Id="SA1129" Action="Warning"/> <!-- Do not use default value type constructor -->
|
<Rule Id="SA1129" Action="Warning"/> <!-- Do not use default value type constructor -->
|
||||||
@ -70,16 +73,16 @@
|
|||||||
<Rule Id="SA1131" Action="Warning"/> <!-- Use readable conditions -->
|
<Rule Id="SA1131" Action="Warning"/> <!-- Use readable conditions -->
|
||||||
<Rule Id="SA1132" Action="Warning"/> <!-- Do not combine fields -->
|
<Rule Id="SA1132" Action="Warning"/> <!-- Do not combine fields -->
|
||||||
<Rule Id="SA1133" Action="Warning"/> <!-- Do not combine attributes -->
|
<Rule Id="SA1133" Action="Warning"/> <!-- Do not combine attributes -->
|
||||||
<Rule Id="SA1134" Action="Warning" /> <!-- Attributes should not share line -->
|
<Rule Id="SA1134" Action="None"/> <!-- Attributes should not share line -->
|
||||||
<Rule Id="SA1135" Action="Warning"/> <!-- Using directives should be qualified -->
|
<Rule Id="SA1135" Action="Warning"/> <!-- Using directives should be qualified -->
|
||||||
<Rule Id="SA1136" Action="Warning"/> <!-- Enum values should be on separate lines -->
|
<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="SA1137" Action="Warning"/> <!-- Elements should have the same indentation -->
|
||||||
<Rule Id="SA1139" Action="Warning"/> <!-- Use literal suffix notation instead of casting -->
|
<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="SX1101" Action="Warning"/> <!-- Do not prefix local calls with 'this.' -->
|
||||||
</Rules>
|
</Rules>
|
||||||
|
|
||||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.OrderingRules">
|
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.OrderingRules">
|
||||||
<Rule Id="SA1200" Action="Warning" /> <!-- Using directives should be placed correctly -->
|
<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="SA1201" Action="Warning"/> <!-- Elements should appear in the correct order -->
|
||||||
<Rule Id="SA1202" Action="Warning"/> <!-- Elements should be ordered by access -->
|
<Rule Id="SA1202" Action="Warning"/> <!-- Elements should be ordered by access -->
|
||||||
<Rule Id="SA1203" Action="Warning"/> <!-- Constants should appear before fields -->
|
<Rule Id="SA1203" Action="Warning"/> <!-- Constants should appear before fields -->
|
||||||
@ -100,7 +103,7 @@
|
|||||||
|
|
||||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.NamingRules">
|
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.NamingRules">
|
||||||
<Rule Id="SA1300" Action="Warning"/> <!-- Element should begin with upper-case letter -->
|
<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="SA1301" Action="Warning"/> <!-- Element should begin with lower-case letter -->
|
||||||
<Rule Id="SA1302" Action="Warning"/> <!-- Interface names should begin with I -->
|
<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="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="SA1304" Action="Warning"/> <!-- Non-private readonly fields should begin with upper-case letter -->
|
||||||
@ -108,14 +111,14 @@
|
|||||||
<Rule Id="SA1306" Action="Warning"/> <!-- Field names should begin with lower-case letter -->
|
<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="SA1307" Action="Warning"/> <!-- Accessible fields should begin with upper-case letter -->
|
||||||
<Rule Id="SA1308" Action="Warning"/> <!-- Variable names should not be prefixed -->
|
<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="SA1309" Action="None"/> <!-- Field names should not begin with underscore -->
|
||||||
<Rule Id="SA1310" Action="None"/> <!-- Field names should not contain 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="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="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="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="SA1314" Action="Warning"/> <!-- Type parameter names should begin with T -->
|
||||||
<Rule Id="SX1309" Action="None" /> <!-- Field names should begin with underscore -->
|
<Rule Id="SX1309" Action="Warning"/> <!-- Field names should begin with underscore -->
|
||||||
<Rule Id="SX1309S" Action="None" /> <!-- Static field names should begin with underscore -->
|
<Rule Id="SX1309S" Action="Warning"/> <!-- Static field names should begin with underscore -->
|
||||||
</Rules>
|
</Rules>
|
||||||
|
|
||||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.MaintainabilityRules">
|
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.MaintainabilityRules">
|
||||||
@ -127,20 +130,20 @@
|
|||||||
<Rule Id="SA1404" Action="Warning"/> <!-- Code analysis suppression should have justification -->
|
<Rule Id="SA1404" Action="Warning"/> <!-- Code analysis suppression should have justification -->
|
||||||
<Rule Id="SA1405" Action="Warning"/> <!-- Debug.Assert should provide message text -->
|
<Rule Id="SA1405" Action="Warning"/> <!-- Debug.Assert should provide message text -->
|
||||||
<Rule Id="SA1406" Action="Warning"/> <!-- Debug.Fail 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="SA1407" Action="None"/> <!-- Arithmetic expressions should declare precedence -->
|
||||||
<Rule Id="SA1408" Action="Warning"/> <!-- Conditional expressions should declare precedence -->
|
<Rule Id="SA1408" Action="Warning"/> <!-- Conditional expressions should declare precedence -->
|
||||||
<Rule Id="SA1409" Action="None" /> <!-- Remove unnecessary code -->
|
<Rule Id="SA1409" Action="Warning"/> <!-- Remove unnecessary code -->
|
||||||
<Rule Id="SA1410" Action="Warning"/> <!-- Remove delegate parenthesis when possible -->
|
<Rule Id="SA1410" Action="Warning"/> <!-- Remove delegate parenthesis when possible -->
|
||||||
<Rule Id="SA1411" Action="Warning"/> <!-- Attribute constructor should not use unnecessary parenthesis -->
|
<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="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="SA1413" Action="None"/> <!-- Use trailing comma in multi-line initializers -->
|
||||||
</Rules>
|
</Rules>
|
||||||
|
|
||||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.LayoutRules">
|
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.LayoutRules">
|
||||||
<Rule Id="SA1500" Action="Warning" /> <!-- Braces for multi-line statements should not share line -->
|
<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="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="SA1502" Action="None"/> <!-- Element should not be on a single line -->
|
||||||
<Rule Id="SA1503" Action="Warning" /> <!-- Braces should not be omitted -->
|
<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="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="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="SA1506" Action="Warning"/> <!-- Element documentation headers should not be followed by blank line -->
|
||||||
@ -162,25 +165,25 @@
|
|||||||
|
|
||||||
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.DocumentationRules">
|
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers.DocumentationRules">
|
||||||
<Rule Id="SA1600" Action="None"/> <!-- Elements should be documented -->
|
<Rule Id="SA1600" Action="None"/> <!-- Elements should be documented -->
|
||||||
<Rule Id="SA1601" Action="Warning" /> <!-- Partial elements should be documented -->
|
<Rule Id="SA1601" Action="None"/> <!-- Partial elements should be documented -->
|
||||||
<Rule Id="SA1602" Action="Warning" /> <!-- Enumeration items should be documented -->
|
<Rule Id="SA1602" Action="None"/> <!-- Enumeration items should be documented -->
|
||||||
<Rule Id="SA1603" Action="None" /> <!-- Documentation should contain valid XML -->
|
<Rule Id="SA1603" Action="Warning"/> <!-- Documentation should contain valid XML -->
|
||||||
<Rule Id="SA1604" Action="Warning"/> <!-- Element documentation should have summary -->
|
<Rule Id="SA1604" Action="Warning"/> <!-- Element documentation should have summary -->
|
||||||
<Rule Id="SA1605" Action="Warning"/> <!-- Partial 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="SA1606" Action="Warning"/> <!-- Element documentation should have summary text -->
|
||||||
<Rule Id="SA1607" Action="Warning"/> <!-- Partial 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="SA1608" Action="Warning"/> <!-- Element documentation should not have default summary -->
|
||||||
<Rule Id="SA1609" Action="None" /> <!-- Property documentation should have value -->
|
<Rule Id="SA1609" Action="Warning"/> <!-- Property documentation should have value -->
|
||||||
<Rule Id="SA1610" Action="Warning"/> <!-- Property documentation should have value text -->
|
<Rule Id="SA1610" Action="Warning"/> <!-- Property documentation should have value text -->
|
||||||
<Rule Id="SA1611" Action="Warning" /> <!-- Element parameters should be documented -->
|
<Rule Id="SA1611" Action="None"/> <!-- Element parameters should be documented -->
|
||||||
<Rule Id="SA1612" Action="Warning"/> <!-- Element parameter documentation should match element parameters -->
|
<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="SA1613" Action="Warning"/> <!-- Element parameter documentation should declare parameter name -->
|
||||||
<Rule Id="SA1614" Action="Warning"/> <!-- Element parameter documentation should have text -->
|
<Rule Id="SA1614" Action="Warning"/> <!-- Element parameter documentation should have text -->
|
||||||
<Rule Id="SA1615" Action="Warning" /> <!-- Element return value should be documented -->
|
<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="SA1616" Action="Warning"/> <!-- Element return value documentation should have text -->
|
||||||
<Rule Id="SA1617" Action="Warning"/> <!-- Void return value should not be documented -->
|
<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="SA1618" Action="None"/> <!-- Generic type parameters should be documented -->
|
||||||
<Rule Id="SA1619" Action="Warning" /> <!-- Generic type parameters should be documented partial class -->
|
<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="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="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="SA1622" Action="Warning"/> <!-- Generic type parameter documentation should have text -->
|
||||||
@ -189,11 +192,11 @@
|
|||||||
<Rule Id="SA1625" Action="Warning"/> <!-- Element documentation should not be copied and pasted -->
|
<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="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="SA1627" Action="Warning"/> <!-- Documentation text should not be empty -->
|
||||||
<Rule Id="SA1628" Action="None" /> <!-- Documentation text should begin with a capital letter -->
|
<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="SA1629" Action="Warning"/> <!-- Documentation text should end with a period -->
|
||||||
<Rule Id="SA1630" Action="None" /> <!-- Documentation text should contain whitespace -->
|
<Rule Id="SA1630" Action="Warning"/> <!-- Documentation text should contain whitespace -->
|
||||||
<Rule Id="SA1631" Action="None" /> <!-- Documentation should meet character percentage -->
|
<Rule Id="SA1631" Action="Warning"/> <!-- Documentation should meet character percentage -->
|
||||||
<Rule Id="SA1632" Action="None" /> <!-- Documentation text should meet minimum character length -->
|
<Rule Id="SA1632" Action="Warning"/> <!-- Documentation text should meet minimum character length -->
|
||||||
<Rule Id="SA1633" Action="None"/> <!-- File should have header -->
|
<Rule Id="SA1633" Action="None"/> <!-- File should have header -->
|
||||||
<Rule Id="SA1634" Action="Warning"/> <!-- File header should show copyright -->
|
<Rule Id="SA1634" Action="Warning"/> <!-- File header should show copyright -->
|
||||||
<Rule Id="SA1635" Action="Warning"/> <!-- File header should have copyright text -->
|
<Rule Id="SA1635" Action="Warning"/> <!-- File header should have copyright text -->
|
||||||
@ -205,13 +208,14 @@
|
|||||||
<Rule Id="SA1641" Action="Warning"/> <!-- File header company name text should match -->
|
<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="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="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="SA1644" Action="Warning"/> <!-- Documentation headers should not contain blank lines -->
|
||||||
<Rule Id="SA1645" Action="None" /> <!-- Included documentation file does not exist -->
|
<Rule Id="SA1645" Action="Warning"/> <!-- Included documentation file does not exist -->
|
||||||
<Rule Id="SA1646" Action="None" /> <!-- Included documentation XPath does not exist -->
|
<Rule Id="SA1646" Action="Warning"/> <!-- Included documentation XPath does not exist -->
|
||||||
<Rule Id="SA1647" Action="None" /> <!-- Include node does not contain valid file and path -->
|
<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="SA1648" Action="Warning"/> <!-- Inheritdoc should be used with inheriting class -->
|
||||||
<Rule Id="SA1649" Action="Warning"/> <!-- File name should match first type name -->
|
<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="SA1650" Action="Warning"/> <!-- Element documentation should be spelled correctly -->
|
||||||
<Rule Id="SA1651" Action="Warning"/> <!-- Do not use placeholder elements -->
|
<Rule Id="SA1651" Action="Warning"/> <!-- Do not use placeholder elements -->
|
||||||
|
|
||||||
</Rules>
|
</Rules>
|
||||||
</RuleSet>
|
</RuleSet>
|
4
dot.sln
4
dot.sln
@ -15,6 +15,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{AD79881E-7
|
|||||||
build.cake = build.cake
|
build.cake = build.cake
|
||||||
code-format.cmd = code-format.cmd
|
code-format.cmd = code-format.cmd
|
||||||
CodeCleanupOnSave.csx = CodeCleanupOnSave.csx
|
CodeCleanupOnSave.csx = CodeCleanupOnSave.csx
|
||||||
|
CodeQuality.props = CodeQuality.props
|
||||||
Directory.Build.props = Directory.Build.props
|
Directory.Build.props = Directory.Build.props
|
||||||
dot.sln.DotSettings = dot.sln.DotSettings
|
dot.sln.DotSettings = dot.sln.DotSettings
|
||||||
dot.sln.DotSettings.user = dot.sln.DotSettings.user
|
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.md = README.md
|
||||||
README.zh-CN.md = README.zh-CN.md
|
README.zh-CN.md = README.zh-CN.md
|
||||||
SafetyDelUnusedResx.ahk = SafetyDelUnusedResx.ahk
|
SafetyDelUnusedResx.ahk = SafetyDelUnusedResx.ahk
|
||||||
SonarqubleAnalyzer.props = SonarqubleAnalyzer.props
|
stylecop.json = stylecop.json
|
||||||
|
StyleCopAnalyzers.ruleset = StyleCopAnalyzers.ruleset
|
||||||
switch-nuget.cmd = switch-nuget.cmd
|
switch-nuget.cmd = switch-nuget.cmd
|
||||||
switch-project.cmd = switch-project.cmd
|
switch-project.cmd = switch-project.cmd
|
||||||
switcher.json = switcher.json
|
switcher.json = switcher.json
|
||||||
|
@ -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">
|
<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_CODE/@EntryValue">1</s:Int64>
|
||||||
<s:Int64 x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/KEEP_BLANK_LINES_IN_DECLARATIONS/@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"><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /></s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></s:String>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></s:String>
|
||||||
|
|
||||||
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue"><?xml version="1.0" encoding="utf-16"?>
|
<s:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue"><?xml version="1.0" encoding="utf-16"?>
|
||||||
<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
|
<Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns">
|
||||||
<TypePattern>
|
<TypePattern>
|
||||||
@ -8,43 +20,38 @@
|
|||||||
<Entry.SortBy>
|
<Entry.SortBy>
|
||||||
<Kind>
|
<Kind>
|
||||||
<Kind.Order>
|
<Kind.Order>
|
||||||
<DeclarationKind>Interface</DeclarationKind>
|
|
||||||
<DeclarationKind>Class</DeclarationKind>
|
|
||||||
<DeclarationKind>Record</DeclarationKind>
|
|
||||||
<DeclarationKind>Enum</DeclarationKind>
|
|
||||||
<DeclarationKind>Struct</DeclarationKind>
|
|
||||||
<DeclarationKind>Delegate</DeclarationKind>
|
|
||||||
<DeclarationKind>Event</DeclarationKind>
|
|
||||||
<DeclarationKind>Constant</DeclarationKind>
|
<DeclarationKind>Constant</DeclarationKind>
|
||||||
<DeclarationKind>Field</DeclarationKind>
|
<DeclarationKind>Field</DeclarationKind>
|
||||||
<DeclarationKind>Property</DeclarationKind>
|
|
||||||
<DeclarationKind>Constructor</DeclarationKind>
|
<DeclarationKind>Constructor</DeclarationKind>
|
||||||
<DeclarationKind>Destructor</DeclarationKind>
|
<DeclarationKind>Destructor</DeclarationKind>
|
||||||
|
<DeclarationKind>Delegate</DeclarationKind>
|
||||||
|
<DeclarationKind>Event</DeclarationKind>
|
||||||
|
<DeclarationKind>Enum</DeclarationKind>
|
||||||
|
<DeclarationKind>Interface</DeclarationKind>
|
||||||
|
<DeclarationKind>Property</DeclarationKind>
|
||||||
<DeclarationKind>Indexer</DeclarationKind>
|
<DeclarationKind>Indexer</DeclarationKind>
|
||||||
<DeclarationKind>Method</DeclarationKind>
|
<DeclarationKind>Method</DeclarationKind>
|
||||||
|
<DeclarationKind>Struct</DeclarationKind>
|
||||||
|
<DeclarationKind>Record</DeclarationKind>
|
||||||
|
<DeclarationKind>Class</DeclarationKind>
|
||||||
</Kind.Order>
|
</Kind.Order>
|
||||||
</Kind>
|
</Kind>
|
||||||
<Access>
|
<Access>
|
||||||
<Access.Order>
|
<Access.Order>
|
||||||
<AccessModifier>Private</AccessModifier>
|
|
||||||
<AccessModifier>PrivateProtected</AccessModifier>
|
|
||||||
<AccessModifier>Protected</AccessModifier>
|
|
||||||
<AccessModifier>ProtectedInternal</AccessModifier>
|
|
||||||
<AccessModifier>Internal</AccessModifier>
|
|
||||||
<AccessModifier>Public</AccessModifier>
|
<AccessModifier>Public</AccessModifier>
|
||||||
|
<AccessModifier>Internal</AccessModifier>
|
||||||
|
<AccessModifier>ProtectedInternal</AccessModifier>
|
||||||
|
<AccessModifier>Protected</AccessModifier>
|
||||||
|
<AccessModifier>PrivateProtected</AccessModifier>
|
||||||
|
<AccessModifier>Private</AccessModifier>
|
||||||
</Access.Order>
|
</Access.Order>
|
||||||
</Access>
|
</Access>
|
||||||
|
<Static />
|
||||||
|
<Readonly />
|
||||||
<Name />
|
<Name />
|
||||||
</Entry.SortBy>
|
</Entry.SortBy>
|
||||||
</Entry>
|
</Entry>
|
||||||
</TypePattern>
|
</TypePattern>
|
||||||
</Patterns></s:String>
|
</Patterns></s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=Constants/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AA_BB" /></s:String>
|
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateConstants/@EntryIndexedValue"><Policy Inspect="True" Prefix="_" Suffix="" Style="AA_BB" /></s:String>
|
|
||||||
<s:String
|
|
||||||
x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=PrivateStaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="_" Suffix="" Style="aaBb" /></s:String>
|
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/PredefinedNamingRules/=StaticReadonly/@EntryIndexedValue"><Policy Inspect="True" Prefix="" Suffix="" Style="AaBb" /></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>
|
</wpf:ResourceDictionary>
|
@ -13,9 +13,8 @@ using Dot;
|
|||||||
|
|
||||||
namespace 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_COMPANY = "nsnail";
|
||||||
public const string ASSEMBLY_COPYRIGHT = $"Copyright (c) 2022 {ASSEMBLY_COMPANY}";
|
public const string ASSEMBLY_COPYRIGHT = $"Copyright (c) 2022 {ASSEMBLY_COMPANY}";
|
||||||
public const string ASSEMBLY_FILE_VERSION = _VERSION;
|
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_PRODUCT = "dot";
|
||||||
public const string ASSEMBLY_TITLE = "功能全面的实用工具 - 程序员的瑞士军刀";
|
public const string ASSEMBLY_TITLE = "功能全面的实用工具 - 程序员的瑞士军刀";
|
||||||
public const string ASSEMBLY_VERSION = _VERSION;
|
public const string ASSEMBLY_VERSION = _VERSION;
|
||||||
|
private const string _VERSION = "1.1.6";
|
||||||
}
|
}
|
@ -1,12 +1,13 @@
|
|||||||
// ReSharper disable ClassNeverInstantiated.Global
|
|
||||||
|
|
||||||
#if NET7_0_WINDOWS
|
#if NET7_0_WINDOWS
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
|
|
||||||
namespace Dot.Color;
|
namespace Dot.Color;
|
||||||
|
|
||||||
[Description(nameof(Str.ScreenPixelTool))]
|
[Description(nameof(Str.ScreenPixelTool))]
|
||||||
[Localization(typeof(Str))]
|
[Localization(typeof(Str))]
|
||||||
|
[SupportedOSPlatform(nameof(OSPlatform.Windows))]
|
||||||
internal sealed class Main : ToolBase<Option>
|
internal sealed class Main : ToolBase<Option>
|
||||||
|
|
||||||
{
|
{
|
||||||
protected override Task Core()
|
protected override Task Core()
|
||||||
{
|
{
|
||||||
|
@ -8,20 +8,11 @@ namespace Dot.Color;
|
|||||||
|
|
||||||
internal sealed class MouseHook : IDisposable
|
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 _WH_MOUSE_LL = 14;
|
||||||
private const int _WM_LBUTTONDOWN = 0x0201;
|
private const int _WM_LBUTTONDOWN = 0x0201;
|
||||||
private const int _WM_MOUSEMOVE = 0x0200;
|
private const int _WM_MOUSEMOVE = 0x0200;
|
||||||
private bool _disposed;
|
|
||||||
private readonly nint _hookId;
|
private readonly nint _hookId;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public MouseHook()
|
public MouseHook()
|
||||||
{
|
{
|
||||||
@ -33,23 +24,46 @@ internal sealed class MouseHook : IDisposable
|
|||||||
Dispose(false);
|
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)
|
private void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (_disposed) return;
|
if (_disposed) {
|
||||||
#pragma warning disable S108
|
return;
|
||||||
if (disposing) { }
|
}
|
||||||
#pragma warning restore S108
|
|
||||||
|
if (disposing) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_hookId != default) {
|
||||||
|
Win32.UnhookWindowsHookEx(_hookId);
|
||||||
|
}
|
||||||
|
|
||||||
if (_hookId != default) Win32.UnhookWindowsHookEx(_hookId);
|
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private nint HookCallback(int nCode, nint wParam, nint lParam)
|
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);
|
return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam);
|
||||||
|
}
|
||||||
|
|
||||||
var hookStruct = (Msllhookstruct)Marshal.PtrToStructure(lParam, typeof(Msllhookstruct))!;
|
var hookStruct = (Msllhookstruct)Marshal.PtrToStructure(lParam, typeof(Msllhookstruct))!;
|
||||||
MouseEvent(null, new MouseEventArgs( //
|
MouseEvent?.Invoke(null, new MouseEventArgs( //
|
||||||
wParam == _WM_MOUSEMOVE ? MouseButtons.None : MouseButtons.Left //
|
wParam == _WM_MOUSEMOVE ? MouseButtons.None : MouseButtons.Left //
|
||||||
, 0 //
|
, 0 //
|
||||||
, hookStruct.X //
|
, hookStruct.X //
|
||||||
@ -58,17 +72,11 @@ internal sealed class MouseHook : IDisposable
|
|||||||
return Win32.CallNextHookEx(_hookId, nCode, wParam, lParam);
|
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();
|
[FieldOffset(0)] public readonly int X;
|
||||||
using var curModule = curProcess.MainModule!;
|
[FieldOffset(4)] public readonly int Y;
|
||||||
return Win32.SetWindowsHookEx(_WH_MOUSE_LL, proc, Win32.GetModuleHandle(curModule.ModuleName), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Dispose(true);
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
namespace Dot.Color;
|
namespace Dot.Color;
|
||||||
|
|
||||||
internal class Option : OptionBase { }
|
internal sealed class Option : OptionBase { }
|
@ -1,16 +1,19 @@
|
|||||||
#if NET7_0_WINDOWS
|
#if NET7_0_WINDOWS
|
||||||
using System.Drawing.Drawing2D;
|
using System.Drawing.Drawing2D;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
using Size = System.Drawing.Size;
|
using Size = System.Drawing.Size;
|
||||||
|
|
||||||
namespace Dot.Color;
|
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 _WINDOW_SIZE = 480; //窗口大小
|
||||||
private const int _ZOOM_RATE = 16; //缩放倍率
|
private const int _ZOOM_RATE = 16; //缩放倍率
|
||||||
private bool _disposed;
|
|
||||||
private readonly Graphics _graphics;
|
private readonly Graphics _graphics;
|
||||||
private readonly PictureBox _pbox;
|
private readonly PictureBox _pbox;
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public WinInfo()
|
public WinInfo()
|
||||||
{
|
{
|
||||||
@ -38,25 +41,6 @@ internal class WinInfo : Form
|
|||||||
Dispose(false);
|
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)
|
public void UpdateImage(Bitmap img, int x, int y)
|
||||||
{
|
{
|
||||||
// 计算复制小图的区域
|
// 计算复制小图的区域
|
||||||
@ -72,13 +56,38 @@ internal class WinInfo : Form
|
|||||||
|
|
||||||
// 取鼠标位置颜色
|
// 取鼠标位置颜色
|
||||||
var posColor = img.GetPixel(x, y);
|
var posColor = img.GetPixel(x, y);
|
||||||
|
|
||||||
// 绘制底部文字信息
|
// 绘制底部文字信息
|
||||||
_graphics.FillRectangle(Brushes.Black, 0, _WINDOW_SIZE - 30, _WINDOW_SIZE, 30);
|
_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) //
|
, new Font(FontFamily.GenericSerif, 10) //
|
||||||
, Brushes.White, 0, _WINDOW_SIZE - 20);
|
, Brushes.White, 0, _WINDOW_SIZE - 20);
|
||||||
|
|
||||||
// 触发重绘
|
// 触发重绘
|
||||||
_pbox.Refresh();
|
_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
|
#endif
|
@ -1,14 +1,18 @@
|
|||||||
#if NET7_0_WINDOWS
|
#if NET7_0_WINDOWS
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Runtime.Versioning;
|
||||||
using TextCopy;
|
using TextCopy;
|
||||||
|
|
||||||
namespace Dot.Color;
|
namespace Dot.Color;
|
||||||
|
|
||||||
internal class WinMain : Form
|
[SupportedOSPlatform(nameof(OSPlatform.Windows))]
|
||||||
|
internal sealed class WinMain : Form
|
||||||
{
|
{
|
||||||
private readonly Bitmap _bmp;
|
private readonly Bitmap _bmp;
|
||||||
private bool _disposed;
|
|
||||||
private readonly WinInfo _winInfo = new(); //小图窗口
|
private readonly WinInfo _winInfo = new(); //小图窗口
|
||||||
|
|
||||||
|
private bool _disposed;
|
||||||
|
|
||||||
public WinMain()
|
public WinMain()
|
||||||
{
|
{
|
||||||
// 隐藏控制台窗口,避免捕获到截屏
|
// 隐藏控制台窗口,避免捕获到截屏
|
||||||
@ -32,7 +36,10 @@ internal class WinMain : Form
|
|||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
base.Dispose(disposing);
|
base.Dispose(disposing);
|
||||||
if (_disposed) return;
|
if (_disposed) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (disposing) {
|
if (disposing) {
|
||||||
_bmp?.Dispose();
|
_bmp?.Dispose();
|
||||||
_winInfo?.Dispose();
|
_winInfo?.Dispose();
|
||||||
@ -43,7 +50,9 @@ internal class WinMain : Form
|
|||||||
|
|
||||||
protected override void OnKeyUp(KeyEventArgs e)
|
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)
|
protected override void OnLoad(EventArgs e)
|
||||||
|
@ -3,12 +3,13 @@ using System.Diagnostics;
|
|||||||
namespace Dot;
|
namespace Dot;
|
||||||
|
|
||||||
// ReSharper disable once UnusedType.Global
|
// ReSharper disable once UnusedType.Global
|
||||||
internal class CsxEditor
|
// ReSharper disable once UnusedMember.Global
|
||||||
|
internal sealed class CsxEditor
|
||||||
{
|
{
|
||||||
// ReSharper disable once UnusedMember.Local
|
// ReSharper disable once UnusedMember.Local
|
||||||
#pragma warning disable CA1822
|
#pragma warning disable IDE0051
|
||||||
private void Run()
|
private static void Run()
|
||||||
#pragma warning restore CA1822
|
#pragma warning restore IDE0051
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
for %%i in (*.png) do pngquant %%i --force --output %%i --skip-if-larger
|
for %%i in (*.png) do pngquant %%i --force --output %%i --skip-if-larger
|
||||||
@ -24,14 +25,14 @@ internal class CsxEditor
|
|||||||
})
|
})
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
Parallel.ForEach(files, file => {
|
_ = Parallel.ForEach(files, file => {
|
||||||
var startInfo = new ProcessStartInfo {
|
var startInfo = new ProcessStartInfo {
|
||||||
FileName = "pngquant"
|
FileName = "pngquant"
|
||||||
, Arguments
|
, Arguments
|
||||||
= $"\"{file}\" --force --output \"{file}\" --skip-if-larger"
|
= $"\"{file}\" --force --output \"{file}\" --skip-if-larger"
|
||||||
};
|
};
|
||||||
using var p = Process.Start(startInfo);
|
using var p = Process.Start(startInfo);
|
||||||
p.WaitForExit();
|
p!.WaitForExit();
|
||||||
Console.WriteLine(p.ExitCode);
|
Console.WriteLine(p.ExitCode);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -45,13 +46,13 @@ internal class CsxEditor
|
|||||||
}))
|
}))
|
||||||
.ToArray();
|
.ToArray();
|
||||||
|
|
||||||
Parallel.ForEach(files, file => {
|
_ = Parallel.ForEach(files, file => {
|
||||||
var startInfo = new ProcessStartInfo {
|
var startInfo = new ProcessStartInfo {
|
||||||
FileName = "jpegtran"
|
FileName = "jpegtran"
|
||||||
, Arguments = $"-copy none -optimize -perfect \"{file}\" \"{file}\""
|
, Arguments = $"-copy none -optimize -perfect \"{file}\" \"{file}\""
|
||||||
};
|
};
|
||||||
using var p = Process.Start(startInfo);
|
using var p = Process.Start(startInfo);
|
||||||
p.WaitForExit();
|
p!.WaitForExit();
|
||||||
Console.WriteLine(p.ExitCode);
|
Console.WriteLine(p.ExitCode);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
164
src/FilesTool.cs
164
src/FilesTool.cs
@ -1,87 +1,24 @@
|
|||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
|
using System.Globalization;
|
||||||
using System.Text.RegularExpressions;
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
// ReSharper disable once RedundantUsingDirective
|
// ReSharper disable once RedundantUsingDirective
|
||||||
using Panel = Spectre.Console.Panel;
|
using Panel = Spectre.Console.Panel;
|
||||||
|
|
||||||
namespace Dot;
|
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 int _breakCnt; //跳过文件数
|
||||||
private ProgressTask _childTask; //子任务进度
|
private ProgressTask _childTask; //子任务进度
|
||||||
private int _excludeCnt; //排除文件数
|
private int _excludeCnt; //排除文件数
|
||||||
|
|
||||||
// ReSharper disable once StaticMemberInGenericType
|
|
||||||
#pragma warning disable S2743
|
|
||||||
private static readonly object _lock = new(); //线程锁
|
|
||||||
private int _readCnt; //读取文件数
|
private int _readCnt; //读取文件数
|
||||||
private int _totalCnt; //总文件数
|
private int _totalCnt; //总文件数
|
||||||
private int _writeCnt; //写入文件数
|
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)
|
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);
|
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
|
protected static FileStream OpenFileStream(string file, FileMode mode, FileAccess access
|
||||||
, FileShare share = FileShare.Read)
|
, FileShare share = FileShare.Read)
|
||||||
{
|
{
|
||||||
@ -114,13 +49,26 @@ internal abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : D
|
|||||||
return fsr;
|
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)
|
protected void ShowMessage(int readCnt, int writeCnt, int breakCnt)
|
||||||
{
|
{
|
||||||
lock (_lock) {
|
lock (_lock) {
|
||||||
_readCnt += readCnt;
|
_readCnt += readCnt;
|
||||||
_writeCnt += writeCnt;
|
_writeCnt += writeCnt;
|
||||||
_breakCnt += breakCnt;
|
_breakCnt += breakCnt;
|
||||||
if (readCnt > 0) _childTask.Increment(1);
|
if (readCnt > 0) {
|
||||||
|
_childTask.Increment(1);
|
||||||
|
}
|
||||||
|
|
||||||
_childTask.Description
|
_childTask.Description
|
||||||
= $"{Str.Read}: [green]{_readCnt}[/]/{_totalCnt}, {Str.Write}: [red]{_writeCnt}[/], {Str.Break}: [gray]{_breakCnt}[/], {Str.Exclude}: [yellow]{_excludeCnt}[/]";
|
= $"{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)
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
187
src/Get/Main.cs
187
src/Get/Main.cs
@ -8,21 +8,110 @@ namespace Dot.Get;
|
|||||||
|
|
||||||
[Description(nameof(Str.DownloadTool))]
|
[Description(nameof(Str.DownloadTool))]
|
||||||
[Localization(typeof(Str))]
|
[Localization(typeof(Str))]
|
||||||
internal partial class Main : ToolBase<Option>
|
internal sealed partial class Main : ToolBase<Option>
|
||||||
{
|
{
|
||||||
private const string _PART = "part";
|
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>
|
||||||
/// 给定一个路径(存在的目录,或者存在的目录+存在或不存在的文件)
|
/// 给定一个路径(存在的目录,或者存在的目录+存在或不存在的文件).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="path">存在的目录,或者存在的目录+存在或不存在的文件</param>
|
/// <param name="path">存在的目录,或者存在的目录+存在或不存在的文件.</param>
|
||||||
/// <param name="file">要写入的文件名</param>
|
/// <param name="file">要写入的文件名.</param>
|
||||||
/// <returns>返回一个可写的文件完整路径</returns>
|
/// <returns>返回一个可写的文件完整路径.</returns>
|
||||||
private static string BuildFilePath(string path, string file)
|
private static string BuildFilePath(string path, string file)
|
||||||
{
|
{
|
||||||
if (GetUseablePath(ref path))
|
|
||||||
// path 是一个存在的文件,已追加尾标
|
// path 是一个存在的文件,已追加尾标
|
||||||
|
if (GetUseablePath(ref path)) {
|
||||||
return path;
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
// ReSharper disable once InvertIf
|
// ReSharper disable once InvertIf
|
||||||
if (Directory.Exists(path)) { //path 是一个存在的目录。
|
if (Directory.Exists(path)) { //path 是一个存在的目录。
|
||||||
@ -41,7 +130,9 @@ internal partial class Main : ToolBase<Option>
|
|||||||
var name = Path.GetFileNameWithoutExtension(path);
|
var name = Path.GetFileNameWithoutExtension(path);
|
||||||
var ext = Path.GetExtension(path);
|
var ext = Path.GetExtension(path);
|
||||||
var ret = false;
|
var ret = false;
|
||||||
|
#pragma warning disable SA1002
|
||||||
for (var i = 1;; ++i) {
|
for (var i = 1;; ++i) {
|
||||||
|
#pragma warning restore SA1002
|
||||||
if (File.Exists(path)) {
|
if (File.Exists(path)) {
|
||||||
path = Path.Combine(dir!, $"{name}({i}){ext}");
|
path = Path.Combine(dir!, $"{name}({i}){ext}");
|
||||||
ret = true;
|
ret = true;
|
||||||
@ -56,7 +147,8 @@ internal partial class Main : ToolBase<Option>
|
|||||||
|
|
||||||
private static void MergeParts(string mainFilePath)
|
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)
|
, $"{Path.GetFileName(mainFilePath)}.*.{_PART}", SearchOption.TopDirectoryOnly)
|
||||||
.OrderBy(x => x)
|
.OrderBy(x => x)
|
||||||
.ToArray();
|
.ToArray();
|
||||||
@ -97,85 +189,4 @@ internal partial class Main : ToolBase<Option>
|
|||||||
rateHandle(read);
|
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}");
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Dot.Get;
|
namespace Dot.Get;
|
||||||
|
|
||||||
internal class Option : OptionBase
|
internal sealed class Option : OptionBase
|
||||||
{
|
{
|
||||||
[CommandOption("-b|--buffer-size")]
|
[CommandOption("-b|--buffer-size")]
|
||||||
[Description(nameof(Str.BufferSize))]
|
[Description(nameof(Str.BufferSize))]
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
|
|
||||||
using System.Collections.Concurrent;
|
using System.Collections.Concurrent;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using NSExt.Extensions;
|
using NSExt.Extensions;
|
||||||
|
|
||||||
@ -9,33 +10,44 @@ namespace Dot.Git;
|
|||||||
|
|
||||||
[Description(nameof(Str.GitTool))]
|
[Description(nameof(Str.GitTool))]
|
||||||
[Localization(typeof(Str))]
|
[Localization(typeof(Str))]
|
||||||
internal class Main : ToolBase<Option>
|
internal sealed class Main : ToolBase<Option>
|
||||||
{
|
{
|
||||||
private Encoding _gitOutputEnc; //git command rsp 编码
|
private Encoding _gitOutputEnc; //git command rsp 编码
|
||||||
private ConcurrentDictionary<string, StringBuilder> _repoRsp; //仓库信息容器
|
private ConcurrentDictionary<string, StringBuilder> _repoRsp; //仓库信息容器
|
||||||
private ConcurrentDictionary<string, TaskStatusColumn.Statues> _repoStatus;
|
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()
|
private async Task CoreInternal()
|
||||||
{
|
{
|
||||||
_gitOutputEnc = Encoding.GetEncoding(Opt.GitOutputEncoding);
|
_gitOutputEnc = Encoding.GetEncoding(Opt.GitOutputEncoding);
|
||||||
var progressBar = new ProgressBarColumn { Width = 10 };
|
var progressBar = new ProgressBarColumn { Width = 10 };
|
||||||
await AnsiConsole.Progress()
|
await AnsiConsole.Progress()
|
||||||
.Columns(progressBar //
|
.Columns( //
|
||||||
|
progressBar //
|
||||||
, new ElapsedTimeColumn() //
|
, new ElapsedTimeColumn() //
|
||||||
, new SpinnerColumn() //
|
, new SpinnerColumn() //
|
||||||
, new TaskStatusColumn() //
|
, new TaskStatusColumn() //
|
||||||
, new TaskDescriptionColumn { Alignment = Justify.Left } //
|
, new TaskDescriptionColumn { Alignment = Justify.Left }) //
|
||||||
)
|
|
||||||
.StartAsync(async ctx => {
|
.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" //
|
var paths = Directory.GetDirectories(Opt.Path, ".git" //
|
||||||
, new EnumerationOptions //
|
, new EnumerationOptions //
|
||||||
{
|
{
|
||||||
MaxRecursionDepth = Opt.MaxRecursionDepth
|
MaxRecursionDepth = Opt.MaxRecursionDepth
|
||||||
, RecurseSubdirectories = true
|
, RecurseSubdirectories = true
|
||||||
, IgnoreInaccessible = true
|
, IgnoreInaccessible = true
|
||||||
, AttributesToSkip
|
, AttributesToSkip = FileAttributes.ReparsePoint
|
||||||
= FileAttributes.ReparsePoint
|
|
||||||
})
|
})
|
||||||
.Select(x => Directory.GetParent(x)!.FullName);
|
.Select(x => Directory.GetParent(x)!.FullName);
|
||||||
|
|
||||||
@ -43,8 +55,8 @@ internal class Main : ToolBase<Option>
|
|||||||
_repoStatus = new ConcurrentDictionary<string, TaskStatusColumn.Statues>();
|
_repoStatus = new ConcurrentDictionary<string, TaskStatusColumn.Statues>();
|
||||||
var tasks = new Dictionary<string, ProgressTask>();
|
var tasks = new Dictionary<string, ProgressTask>();
|
||||||
foreach (var path in paths) {
|
foreach (var path in paths) {
|
||||||
_repoRsp.TryAdd(path, new StringBuilder());
|
_ = _repoRsp.TryAdd(path, new StringBuilder());
|
||||||
_repoStatus.TryAdd(path, default);
|
_ = _repoStatus.TryAdd(path, default);
|
||||||
var task = ctx.AddTask(new DirectoryInfo(path).Name, false).IsIndeterminate();
|
var task = ctx.AddTask(new DirectoryInfo(path).Name, false).IsIndeterminate();
|
||||||
tasks.Add(path, task);
|
tasks.Add(path, task);
|
||||||
}
|
}
|
||||||
@ -79,13 +91,15 @@ internal class Main : ToolBase<Option>
|
|||||||
// 打印 git command rsp
|
// 打印 git command rsp
|
||||||
void ExecRspReceived(object sender, DataReceivedEventArgs e)
|
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));
|
var msg = Encoding.UTF8.GetString(_gitOutputEnc.GetBytes(e.Data));
|
||||||
_repoRsp[payload.Key].Append(msg.EscapeMarkup());
|
_repoRsp[payload.Key].Append(msg.EscapeMarkup());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 启动git进程
|
// 启动git进程
|
||||||
|
|
||||||
var startInfo = new ProcessStartInfo {
|
var startInfo = new ProcessStartInfo {
|
||||||
CreateNoWindow = true
|
CreateNoWindow = true
|
||||||
, WorkingDirectory = payload.Key
|
, WorkingDirectory = payload.Key
|
||||||
@ -116,12 +130,4 @@ internal class Main : ToolBase<Option>
|
|||||||
|
|
||||||
payload.Value.StopTask();
|
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();
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Dot.Git;
|
namespace Dot.Git;
|
||||||
|
|
||||||
internal class Option : OptionBase
|
internal sealed class Option : OptionBase
|
||||||
{
|
{
|
||||||
[CommandOption("-a|--args")]
|
[CommandOption("-a|--args")]
|
||||||
[Description(nameof(Str.GitArgs))]
|
[Description(nameof(Str.GitArgs))]
|
||||||
|
@ -4,6 +4,6 @@ internal static class ProgressTaskStateExtensions
|
|||||||
{
|
{
|
||||||
public static void Status(this ProgressTaskState me, TaskStatusColumn.Statues value)
|
public static void Status(this ProgressTaskState me, TaskStatusColumn.Statues value)
|
||||||
{
|
{
|
||||||
me.Update<TaskStatusColumn.Statues>(nameof(TaskStatusColumn), _ => value);
|
_ = me.Update<TaskStatusColumn.Statues>(nameof(TaskStatusColumn), _ => value);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -6,11 +6,12 @@ using Spectre.Console.Rendering;
|
|||||||
|
|
||||||
namespace Dot.Git;
|
namespace Dot.Git;
|
||||||
|
|
||||||
internal class TaskStatusColumn : ProgressColumn
|
internal sealed class TaskStatusColumn : ProgressColumn
|
||||||
{
|
{
|
||||||
public enum Statues : byte
|
public enum Statues : byte
|
||||||
{
|
{
|
||||||
[Description($"[gray]{nameof(Ready)}[/]")]
|
[Description($"[gray]{nameof(Ready)}[/]")]
|
||||||
|
|
||||||
// ReSharper disable once UnusedMember.Global
|
// ReSharper disable once UnusedMember.Global
|
||||||
Ready
|
Ready
|
||||||
|
|
||||||
@ -27,6 +28,9 @@ internal class TaskStatusColumn : ProgressColumn
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the alignment of the task description.
|
/// Gets or sets the alignment of the task description.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The alignment of the task description.
|
||||||
|
/// </value>
|
||||||
public Justify Alignment { get; set; } = Justify.Right;
|
public Justify Alignment { get; set; } = Justify.Right;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
global using System.ComponentModel;
|
global using System.ComponentModel;
|
||||||
|
global using Dot.Lang;
|
||||||
global using Spectre.Console;
|
global using Spectre.Console;
|
||||||
global using Spectre.Console.Cli;
|
global using Spectre.Console.Cli;
|
||||||
global using Dot.Lang;
|
|
@ -1,5 +1,6 @@
|
|||||||
// ReSharper disable ClassNeverInstantiated.Global
|
// ReSharper disable ClassNeverInstantiated.Global
|
||||||
|
|
||||||
|
using System.Globalization;
|
||||||
#if NET7_0_WINDOWS
|
#if NET7_0_WINDOWS
|
||||||
using TextCopy;
|
using TextCopy;
|
||||||
#endif
|
#endif
|
||||||
@ -13,7 +14,10 @@ internal sealed class Main : ToolBase<Option>
|
|||||||
protected override Task Core()
|
protected override Task Core()
|
||||||
{
|
{
|
||||||
var guid = System.Guid.NewGuid().ToString();
|
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);
|
Console.WriteLine(Str.Copied, guid);
|
||||||
#if NET7_0_WINDOWS
|
#if NET7_0_WINDOWS
|
||||||
ClipboardService.SetText(guid);
|
ClipboardService.SetText(guid);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Dot.Guid;
|
namespace Dot.Guid;
|
||||||
|
|
||||||
internal class Option : OptionBase
|
internal sealed class Option : OptionBase
|
||||||
{
|
{
|
||||||
[CommandOption("-u|--upper")]
|
[CommandOption("-u|--upper")]
|
||||||
[Description(nameof(Str.UseUppercase))]
|
[Description(nameof(Str.UseUppercase))]
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
namespace Dot;
|
namespace Dot;
|
||||||
|
|
||||||
public interface IOption { }
|
internal interface IOption { }
|
@ -8,18 +8,19 @@ namespace Dot.IP;
|
|||||||
[Description(nameof(Str.Ip))]
|
[Description(nameof(Str.Ip))]
|
||||||
[Localization(typeof(Str))]
|
[Localization(typeof(Str))]
|
||||||
internal sealed class Main : ToolBase<Option>
|
internal sealed class Main : ToolBase<Option>
|
||||||
|
|
||||||
{
|
{
|
||||||
protected override async Task Core()
|
protected override async Task Core()
|
||||||
{
|
{
|
||||||
foreach (var item in NetworkInterface.GetAllNetworkInterfaces()) {
|
foreach (var item in NetworkInterface.GetAllNetworkInterfaces()) {
|
||||||
if (item.NetworkInterfaceType != NetworkInterfaceType.Ethernet ||
|
if (item.NetworkInterfaceType != NetworkInterfaceType.Ethernet ||
|
||||||
item.OperationalStatus != OperationalStatus.Up)
|
item.OperationalStatus != OperationalStatus.Up) {
|
||||||
continue;
|
continue;
|
||||||
var output = string.Join(Environment.NewLine
|
}
|
||||||
|
|
||||||
|
var output = string.Join( //
|
||||||
|
Environment.NewLine
|
||||||
, item.GetIPProperties()
|
, item.GetIPProperties()
|
||||||
.UnicastAddresses
|
.UnicastAddresses.Where(x => x.Address.AddressFamily == AddressFamily.InterNetwork)
|
||||||
.Where(x => x.Address.AddressFamily == AddressFamily.InterNetwork)
|
|
||||||
.Select(x => @$"{item.Name}: {x.Address}"));
|
.Select(x => @$"{item.Name}: {x.Address}"));
|
||||||
Console.WriteLine(output);
|
Console.WriteLine(output);
|
||||||
}
|
}
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
namespace Dot.IP;
|
namespace Dot.IP;
|
||||||
|
|
||||||
internal class Option : OptionBase { }
|
internal sealed class Option : OptionBase { }
|
@ -10,58 +10,22 @@ namespace Dot.Json;
|
|||||||
|
|
||||||
[Description(nameof(Str.Json))]
|
[Description(nameof(Str.Json))]
|
||||||
[Localization(typeof(Str))]
|
[Localization(typeof(Str))]
|
||||||
internal class Main : ToolBase<Option>
|
internal sealed class Main : ToolBase<Option>
|
||||||
{
|
{
|
||||||
private object _inputObj;
|
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()
|
protected override Task Core()
|
||||||
{
|
{
|
||||||
var inputText = Opt.InputText;
|
var inputText = Opt.InputText;
|
||||||
|
|
||||||
#if NET7_0_WINDOWS
|
#if NET7_0_WINDOWS
|
||||||
if (inputText.NullOrWhiteSpace()) inputText = ClipboardService.GetText();
|
if (inputText.NullOrWhiteSpace()) {
|
||||||
|
inputText = ClipboardService.GetText();
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
if (inputText.NullOrWhiteSpace()) throw new ArgumentException(Str.InputTextIsEmpty);
|
if (inputText.NullOrWhiteSpace()) {
|
||||||
|
throw new ArgumentException(Str.InputTextIsEmpty);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
_inputObj = inputText.Object<object>();
|
_inputObj = inputText.Object<object>();
|
||||||
@ -81,4 +45,48 @@ internal class Main : ToolBase<Option>
|
|||||||
|
|
||||||
return CoreInternal();
|
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);
|
||||||
|
}
|
||||||
}
|
}
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Dot.Json;
|
namespace Dot.Json;
|
||||||
|
|
||||||
internal class Option : OptionBase
|
internal sealed class Option : OptionBase
|
||||||
{
|
{
|
||||||
[CommandOption("-c|--compress")]
|
[CommandOption("-c|--compress")]
|
||||||
[Description(nameof(Str.CompressJson))]
|
[Description(nameof(Str.CompressJson))]
|
||||||
|
@ -135,7 +135,6 @@
|
|||||||
<value>密码长度</value>
|
<value>密码长度</value>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
|
|
||||||
<data name="PwdGenerateTypes" xml:space="preserve">
|
<data name="PwdGenerateTypes" xml:space="preserve">
|
||||||
<value>BitSet 1:[0-9],2:[a-z],4:[A-Z],8:[ascii.0x21-0x2F]</value>
|
<value>BitSet 1:[0-9],2:[a-z],4:[A-Z],8:[ascii.0x21-0x2F]</value>
|
||||||
</data>
|
</data>
|
||||||
|
@ -27,7 +27,7 @@ namespace Dot.Lang {
|
|||||||
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
|
||||||
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
|
||||||
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
|
||||||
internal class Str {
|
internal sealed class Str {
|
||||||
|
|
||||||
private static global::System.Resources.ResourceManager resourceMan;
|
private static global::System.Resources.ResourceManager resourceMan;
|
||||||
|
|
||||||
@ -68,7 +68,8 @@ namespace Dot.Lang {
|
|||||||
<#
|
<#
|
||||||
var xml = new XmlDocument();
|
var xml = new XmlDocument();
|
||||||
xml.Load("Str.resx");
|
xml.Load("Str.resx");
|
||||||
foreach (XmlNode data in xml.SelectNodes("//root/data")!) {
|
foreach (XmlNode data in xml.SelectNodes("//root/data")!)
|
||||||
|
{
|
||||||
#>
|
#>
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// <#= data.SelectSingleNode("value")?.InnerText #>
|
/// <#= data.SelectSingleNode("value")?.InnerText #>
|
||||||
|
@ -1,30 +1,43 @@
|
|||||||
|
using System.Globalization;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Dot;
|
|
||||||
using Dot.Git;
|
using Dot.Git;
|
||||||
|
#if NET7_0_WINDOWS
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace Dot;
|
||||||
|
|
||||||
|
internal sealed class Program
|
||||||
|
{
|
||||||
|
public static int Main(string[] args)
|
||||||
|
{
|
||||||
var app = new CommandApp();
|
var app = new CommandApp();
|
||||||
|
|
||||||
app.Configure(config => {
|
app.Configure(config => {
|
||||||
config.SetApplicationName(AssemblyInfo.ASSEMBLY_PRODUCT);
|
config.SetApplicationName(AssemblyInfo.ASSEMBLY_PRODUCT);
|
||||||
config.SetApplicationVersion(AssemblyInfo.ASSEMBLY_VERSION);
|
config.SetApplicationVersion(AssemblyInfo.ASSEMBLY_VERSION);
|
||||||
|
|
||||||
config.AddCommand<Main>(nameof(Dot.Git).ToLower());
|
config.AddCommand<Main>(nameof(Git).ToLower(CultureInfo.InvariantCulture));
|
||||||
#if NET7_0_WINDOWS
|
#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
|
#endif
|
||||||
config.AddCommand<Dot.Guid.Main>(nameof(Dot.Guid).ToLower());
|
config.AddCommand<Guid.Main>(nameof(Guid).ToLower(CultureInfo.InvariantCulture));
|
||||||
config.AddCommand<Dot.IP.Main>(nameof(Dot.IP).ToLower());
|
config.AddCommand<IP.Main>(nameof(IP).ToLower(CultureInfo.InvariantCulture));
|
||||||
config.AddCommand<Dot.Json.Main>(nameof(Dot.Json).ToLower());
|
config.AddCommand<Json.Main>(nameof(Json).ToLower(CultureInfo.InvariantCulture));
|
||||||
config.AddCommand<Dot.Pwd.Main>(nameof(Dot.Pwd).ToLower());
|
config.AddCommand<Pwd.Main>(nameof(Pwd).ToLower(CultureInfo.InvariantCulture));
|
||||||
config.AddCommand<Dot.Rbom.Main>(nameof(Dot.Rbom).ToLower());
|
config.AddCommand<Rbom.Main>(nameof(Rbom).ToLower(CultureInfo.InvariantCulture));
|
||||||
config.AddCommand<Dot.Trim.Main>(nameof(Dot.Trim).ToLower());
|
config.AddCommand<Trim.Main>(nameof(Trim).ToLower(CultureInfo.InvariantCulture));
|
||||||
config.AddCommand<Dot.Text.Main>(nameof(Dot.Text).ToLower());
|
config.AddCommand<Text.Main>(nameof(Text).ToLower(CultureInfo.InvariantCulture));
|
||||||
config.AddCommand<Dot.Time.Main>(nameof(Dot.Time).ToLower());
|
config.AddCommand<Time.Main>(nameof(Time).ToLower(CultureInfo.InvariantCulture));
|
||||||
config.AddCommand<Dot.ToLf.Main>(nameof(Dot.ToLf).ToLower());
|
config.AddCommand<ToLf.Main>(nameof(ToLf).ToLower(CultureInfo.InvariantCulture));
|
||||||
config.AddCommand<Dot.Get.Main>(nameof(Dot.Get).ToLower());
|
config.AddCommand<Get.Main>(nameof(Get).ToLower(CultureInfo.InvariantCulture));
|
||||||
|
|
||||||
config.ValidateExamples();
|
config.ValidateExamples();
|
||||||
});
|
});
|
||||||
|
|
||||||
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
|
||||||
return app.Run(args);
|
return app.Run(args);
|
||||||
|
}
|
||||||
|
}
|
@ -25,25 +25,34 @@ internal sealed class Main : ToolBase<Option>
|
|||||||
var pDest = stackalloc char[Opt.Length];
|
var pDest = stackalloc char[Opt.Length];
|
||||||
var sourceLen = 0;
|
var sourceLen = 0;
|
||||||
|
|
||||||
if (Opt.Type.HasFlag(Option.GenerateTypes.Number))
|
if (Opt.Type.HasFlag(Option.GenerateTypes.Number)) {
|
||||||
foreach (var c in _charTable[0])
|
foreach (var c in _charTable[0]) {
|
||||||
*(pSource + sourceLen++) = c;
|
*(pSource + sourceLen++) = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Opt.Type.HasFlag(Option.GenerateTypes.LowerCaseLetter))
|
if (Opt.Type.HasFlag(Option.GenerateTypes.LowerCaseLetter)) {
|
||||||
foreach (var c in _charTable[1])
|
foreach (var c in _charTable[1]) {
|
||||||
*(pSource + sourceLen++) = c;
|
*(pSource + sourceLen++) = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Opt.Type.HasFlag(Option.GenerateTypes.UpperCaseLetter))
|
if (Opt.Type.HasFlag(Option.GenerateTypes.UpperCaseLetter)) {
|
||||||
foreach (var c in _charTable[2])
|
foreach (var c in _charTable[2]) {
|
||||||
*(pSource + sourceLen++) = c;
|
*(pSource + sourceLen++) = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (Opt.Type.HasFlag(Option.GenerateTypes.SpecialCharacter))
|
if (Opt.Type.HasFlag(Option.GenerateTypes.SpecialCharacter)) {
|
||||||
foreach (var c in _charTable[3])
|
foreach (var c in _charTable[3]) {
|
||||||
*(pSource + sourceLen++) = c;
|
*(pSource + sourceLen++) = c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var randScope = new[] { 0, sourceLen };
|
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());
|
*(pDest + i) = *(pSource + randScope.Rand());
|
||||||
|
}
|
||||||
|
|
||||||
var result = new string(pDest, 0, Opt.Length);
|
var result = new string(pDest, 0, Opt.Length);
|
||||||
Console.WriteLine(Str.Copied, result);
|
Console.WriteLine(Str.Copied, result);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Dot.Pwd;
|
namespace Dot.Pwd;
|
||||||
|
|
||||||
internal class Option : OptionBase
|
internal sealed class Option : OptionBase
|
||||||
{
|
{
|
||||||
[Flags]
|
[Flags]
|
||||||
public enum GenerateTypes
|
public enum GenerateTypes
|
||||||
|
@ -8,18 +8,6 @@ internal sealed class Main : FilesTool<Option>
|
|||||||
{
|
{
|
||||||
private readonly byte[] _utf8Bom = { 0xef, 0xbb, 0xbf };
|
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)
|
protected override async ValueTask FileHandle(string file, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
ShowMessage(1, 0, 0);
|
ShowMessage(1, 0, 0);
|
||||||
@ -32,7 +20,10 @@ internal sealed class Main : FilesTool<Option>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (CloneFileWithoutBom(fsr, ref tmpFile)) {
|
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);
|
ShowMessage(0, 1, 0);
|
||||||
UpdateStats(Path.GetExtension(file));
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
namespace Dot.Rbom;
|
namespace Dot.Rbom;
|
||||||
|
|
||||||
internal class Option : DirOption { }
|
internal sealed class Option : DirOption { }
|
22
src/Text/Main.Output.cs
Normal file
22
src/Text/Main.Output.cs
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
@ -4,32 +4,35 @@ using System.Security.Cryptography;
|
|||||||
using System.Text;
|
using System.Text;
|
||||||
using NSExt.Extensions;
|
using NSExt.Extensions;
|
||||||
#if NET7_0_WINDOWS
|
#if NET7_0_WINDOWS
|
||||||
using TextCopy;
|
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using TextCopy;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
namespace Dot.Text;
|
namespace Dot.Text;
|
||||||
|
|
||||||
[Description(nameof(Str.TextTool))]
|
[Description(nameof(Str.TextTool))]
|
||||||
[Localization(typeof(Str))]
|
[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;
|
#if NET7_0_WINDOWS
|
||||||
public ReadOnlySpan<char> Base64DeCode;
|
if (Opt.Text.NullOrEmpty()) {
|
||||||
public ReadOnlySpan<char> Base64DeCodeHex;
|
Opt.Text = await ClipboardService.GetTextAsync();
|
||||||
public ReadOnlySpan<char> EncodingName;
|
}
|
||||||
public ReadOnlySpan<char> Hex;
|
#endif
|
||||||
public ReadOnlySpan<char> HtmlDecode;
|
if (Opt.Text.NullOrEmpty()) {
|
||||||
public ReadOnlySpan<char> HtmlEncode;
|
throw new ArgumentException(Str.InputTextIsEmpty);
|
||||||
public ReadOnlySpan<char> Md5;
|
}
|
||||||
public ReadOnlySpan<char> OriginText;
|
|
||||||
public ReadOnlySpan<char> Sha1;
|
ParseAndShow(Opt.Text);
|
||||||
public ReadOnlySpan<char> Sha256;
|
#if !NET7_0_WINDOWS
|
||||||
public ReadOnlySpan<char> Sha512;
|
return Task.CompletedTask;
|
||||||
public ReadOnlySpan<char> UrlDecode;
|
#endif
|
||||||
public ReadOnlySpan<char> UrlEncode;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static Output BuildOutput(string text, Encoding enc)
|
private static Output BuildOutput(string text, Encoding enc)
|
||||||
@ -51,7 +54,10 @@ internal sealed class Main : ToolBase<Option>
|
|||||||
ret.HtmlDecode = text.HtmlDe();
|
ret.HtmlDecode = text.HtmlDe();
|
||||||
ret.HtmlEncode = text.Html();
|
ret.HtmlEncode = text.Html();
|
||||||
|
|
||||||
if (!text.IsBase64String()) return ret;
|
if (!text.IsBase64String()) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
byte[] base64DeHex = null;
|
byte[] base64DeHex = null;
|
||||||
try {
|
try {
|
||||||
base64DeHex = text.Base64De();
|
base64DeHex = text.Base64De();
|
||||||
@ -60,7 +66,10 @@ internal sealed class Main : ToolBase<Option>
|
|||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
|
|
||||||
if (base64DeHex == null) return ret;
|
if (base64DeHex == null) {
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
ret.Base64DeCodeHex = base64DeHex.String();
|
ret.Base64DeCodeHex = base64DeHex.String();
|
||||||
ret.Base64DeCode = enc.GetString(base64DeHex);
|
ret.Base64DeCode = enc.GetString(base64DeHex);
|
||||||
|
|
||||||
@ -105,21 +114,4 @@ html-decode: {o.HtmlDecode}
|
|||||||
Process.Start("explorer", file);
|
Process.Start("explorer", file);
|
||||||
#endif
|
#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
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
namespace Dot.Text;
|
namespace Dot.Text;
|
||||||
|
|
||||||
internal class Option : OptionBase
|
internal sealed class Option : OptionBase
|
||||||
{
|
{
|
||||||
[CommandArgument(0, "[input text]")]
|
[CommandArgument(0, "[input text]")]
|
||||||
[Description(nameof(Str.TextTobeProcessed))]
|
[Description(nameof(Str.TextTobeProcessed))]
|
||||||
|
155
src/Time/Main.cs
155
src/Time/Main.cs
@ -1,5 +1,6 @@
|
|||||||
// ReSharper disable ClassNeverInstantiated.Global
|
// ReSharper disable ClassNeverInstantiated.Global
|
||||||
|
|
||||||
|
using System.Globalization;
|
||||||
using System.Net.Sockets;
|
using System.Net.Sockets;
|
||||||
|
|
||||||
namespace Dot.Time;
|
namespace Dot.Time;
|
||||||
@ -33,6 +34,81 @@ internal sealed class Main : ToolBase<Option>
|
|||||||
|
|
||||||
private int _successCnt;
|
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)
|
private TimeSpan GetNtpOffset(string server)
|
||||||
{
|
{
|
||||||
Span<byte> ntpData = stackalloc byte[48];
|
Span<byte> ntpData = stackalloc byte[48];
|
||||||
@ -44,9 +120,9 @@ internal sealed class Main : ToolBase<Option>
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
socket.Connect(server, _NTP_PORT);
|
socket.Connect(server, _NTP_PORT);
|
||||||
socket.Send(ntpData);
|
_ = socket.Send(ntpData);
|
||||||
var timeBefore = DateTime.Now;
|
var timeBefore = DateTime.Now;
|
||||||
socket.Receive(ntpData);
|
_ = socket.Receive(ntpData);
|
||||||
var transferTime = DateTime.Now - timeBefore;
|
var transferTime = DateTime.Now - timeBefore;
|
||||||
|
|
||||||
var intPart = ((ulong)ntpData[40] << 24) //
|
var intPart = ((ulong)ntpData[40] << 24) //
|
||||||
@ -86,79 +162,4 @@ internal sealed class Main : ToolBase<Option>
|
|||||||
payload.Value.StopTask();
|
payload.Value.StopTask();
|
||||||
return ValueTask.CompletedTask;
|
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
namespace Dot.Time;
|
namespace Dot.Time;
|
||||||
|
|
||||||
internal class Option : OptionBase
|
internal sealed class Option : OptionBase
|
||||||
{
|
{
|
||||||
[CommandOption("-s|--sync")]
|
[CommandOption("-s|--sync")]
|
||||||
[Description(nameof(Str.SyncToLocalTime))]
|
[Description(nameof(Str.SyncToLocalTime))]
|
||||||
|
@ -9,7 +9,7 @@ internal static class ProgressTaskStateExtensions
|
|||||||
|
|
||||||
public static void Result(this ProgressTaskState me, TimeSpan value)
|
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)
|
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)
|
public static void Status(this ProgressTaskState me, TaskStatusColumn.Statues value)
|
||||||
{
|
{
|
||||||
me.Update<TaskStatusColumn.Statues>(nameof(TaskStatusColumn), _ => value);
|
_ = me.Update<TaskStatusColumn.Statues>(nameof(TaskStatusColumn), _ => value);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -5,11 +5,14 @@ using Spectre.Console.Rendering;
|
|||||||
|
|
||||||
namespace Dot.Time;
|
namespace Dot.Time;
|
||||||
|
|
||||||
internal class TaskResultColumn : ProgressColumn
|
internal sealed class TaskResultColumn : ProgressColumn
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the alignment of the task description.
|
/// Gets or sets the alignment of the task description.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The alignment of the task description.
|
||||||
|
/// </value>
|
||||||
public Justify Alignment { get; set; } = Justify.Right;
|
public Justify Alignment { get; set; } = Justify.Right;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -6,12 +6,12 @@ using Spectre.Console.Rendering;
|
|||||||
|
|
||||||
namespace Dot.Time;
|
namespace Dot.Time;
|
||||||
|
|
||||||
internal class TaskStatusColumn : ProgressColumn
|
internal sealed class TaskStatusColumn : ProgressColumn
|
||||||
{
|
{
|
||||||
public enum Statues : byte
|
public enum Statues : byte
|
||||||
{
|
{
|
||||||
[Description($"[gray]{nameof(Ready)}[/]")]
|
|
||||||
// ReSharper disable once UnusedMember.Global
|
// ReSharper disable once UnusedMember.Global
|
||||||
|
[Description($"[gray]{nameof(Ready)}[/]")]
|
||||||
Ready
|
Ready
|
||||||
|
|
||||||
, [Description($"[yellow]{nameof(Connecting)}[/]")]
|
, [Description($"[yellow]{nameof(Connecting)}[/]")]
|
||||||
@ -27,6 +27,9 @@ internal class TaskStatusColumn : ProgressColumn
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the alignment of the task description.
|
/// Gets or sets the alignment of the task description.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
/// <value>
|
||||||
|
/// The alignment of the task description.
|
||||||
|
/// </value>
|
||||||
public Justify Alignment { get; set; } = Justify.Right;
|
public Justify Alignment { get; set; } = Justify.Right;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
@ -13,6 +13,7 @@ internal sealed class Main : FilesTool<Option>
|
|||||||
var hasWrote = false;
|
var hasWrote = false;
|
||||||
var isBin = false;
|
var isBin = false;
|
||||||
string tmpFile;
|
string tmpFile;
|
||||||
|
|
||||||
// ReSharper disable once TooWideLocalVariableScope
|
// ReSharper disable once TooWideLocalVariableScope
|
||||||
int data;
|
int data;
|
||||||
|
|
||||||
@ -32,7 +33,7 @@ internal sealed class Main : FilesTool<Option>
|
|||||||
continue;
|
continue;
|
||||||
case 0x0d: //cr macos
|
case 0x0d: //cr macos
|
||||||
fsw.WriteByte(0x0a);
|
fsw.WriteByte(0x0a);
|
||||||
fsr.Seek(-1, SeekOrigin.Current);
|
_ = fsr.Seek(-1, SeekOrigin.Current);
|
||||||
hasWrote = true;
|
hasWrote = true;
|
||||||
continue;
|
continue;
|
||||||
case 0x00 or 0xff: //非文本文件
|
case 0x00 or 0xff: //非文本文件
|
||||||
@ -47,10 +48,11 @@ internal sealed class Main : FilesTool<Option>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma warning disable S2583
|
|
||||||
if (hasWrote && !isBin) {
|
if (hasWrote && !isBin) {
|
||||||
#pragma warning restore S2583
|
if (Opt.WriteMode) {
|
||||||
if (Opt.WriteMode) File.Copy(tmpFile, file, true);
|
File.Copy(tmpFile, file, true);
|
||||||
|
}
|
||||||
|
|
||||||
ShowMessage(0, 1, 0);
|
ShowMessage(0, 1, 0);
|
||||||
UpdateStats(Path.GetExtension(file));
|
UpdateStats(Path.GetExtension(file));
|
||||||
}
|
}
|
||||||
|
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
namespace Dot.ToLf;
|
namespace Dot.ToLf;
|
||||||
|
|
||||||
internal class Option : DirOption { }
|
internal sealed class Option : DirOption { }
|
@ -1,18 +1,9 @@
|
|||||||
namespace Dot;
|
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 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)
|
public override int Execute(CommandContext context, TOption settings)
|
||||||
{
|
{
|
||||||
@ -20,4 +11,15 @@ internal abstract class ToolBase<TOption> : Command<TOption> where TOption : Opt
|
|||||||
Run().Wait();
|
Run().Wait();
|
||||||
return 0;
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
@ -8,24 +8,6 @@ namespace Dot.Trim;
|
|||||||
[Localization(typeof(Str))]
|
[Localization(typeof(Str))]
|
||||||
internal sealed class Main : FilesTool<Option>
|
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)
|
protected override async ValueTask FileHandle(string file, CancellationToken cancelToken)
|
||||||
{
|
{
|
||||||
ShowMessage(1, 0, 0);
|
ShowMessage(1, 0, 0);
|
||||||
@ -38,14 +20,39 @@ internal sealed class Main : FilesTool<Option>
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
fsrw.Seek(0, SeekOrigin.Begin);
|
_ = fsrw.Seek(0, SeekOrigin.Begin);
|
||||||
if (!fsrw.IsTextStream()) {
|
if (!fsrw.IsTextStream()) {
|
||||||
ShowMessage(0, 0, 1);
|
ShowMessage(0, 0, 1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Opt.WriteMode) fsrw.SetLength(fsrw.Length - spacesCnt);
|
if (Opt.WriteMode) {
|
||||||
|
fsrw.SetLength(fsrw.Length - spacesCnt);
|
||||||
|
}
|
||||||
|
|
||||||
ShowMessage(0, 1, 0);
|
ShowMessage(0, 1, 0);
|
||||||
UpdateStats(Path.GetExtension(file));
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
@ -2,4 +2,4 @@
|
|||||||
|
|
||||||
namespace Dot.Trim;
|
namespace Dot.Trim;
|
||||||
|
|
||||||
internal class Option : DirOption { }
|
internal sealed class Option : DirOption { }
|
36
src/Win32.cs
36
src/Win32.cs
@ -5,27 +5,13 @@ using System.Runtime.InteropServices;
|
|||||||
|
|
||||||
namespace Dot;
|
namespace Dot;
|
||||||
|
|
||||||
public static partial class Win32
|
internal static partial class Win32
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
public const int SW_HIDE = 0;
|
||||||
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);
|
|
||||||
|
|
||||||
private const string _GDI32_DLL = "gdi32.dll";
|
private const string _GDI32_DLL = "gdi32.dll";
|
||||||
private const string _KERNEL32_DLL = "kernel32.dll";
|
private const string _KERNEL32_DLL = "kernel32.dll";
|
||||||
private const string _USER32_DLL = "user32.dll";
|
private const string _USER32_DLL = "user32.dll";
|
||||||
public const int SW_HIDE = 0;
|
|
||||||
|
|
||||||
[LibraryImport(_USER32_DLL)]
|
[LibraryImport(_USER32_DLL)]
|
||||||
internal static partial nint CallNextHookEx(nint hhk, int nCode, nint wParam, nint lParam);
|
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);
|
internal static partial void SetLocalTime(Systemtime st);
|
||||||
|
|
||||||
[LibraryImport(_USER32_DLL)]
|
[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)]
|
[LibraryImport(_USER32_DLL)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
@ -61,4 +48,19 @@ public static partial class Win32
|
|||||||
[LibraryImport(_USER32_DLL)]
|
[LibraryImport(_USER32_DLL)]
|
||||||
[return: MarshalAs(UnmanagedType.Bool)]
|
[return: MarshalAs(UnmanagedType.Bool)]
|
||||||
internal static partial bool UnhookWindowsHookEx(nint hhk);
|
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
|
||||||
|
}
|
||||||
}
|
}
|
@ -1,13 +1,12 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||||
|
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||||
|
<GenerateDocumentationFile>true</GenerateDocumentationFile>
|
||||||
<OutputType>Exe</OutputType>
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>Dot</RootNamespace>
|
||||||
<TargetFrameworks>net7.0-windows;net7.0</TargetFrameworks>
|
<TargetFrameworks>net7.0-windows;net7.0</TargetFrameworks>
|
||||||
<UseWindowsForms Condition="'$(TargetFramework)' == 'net7.0-windows'">true</UseWindowsForms>
|
<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>
|
||||||
<PropertyGroup Condition="'$(TargetFramework)' == 'net7.0-windows'">
|
<PropertyGroup Condition="'$(TargetFramework)' == 'net7.0-windows'">
|
||||||
<DefineConstants>$(DefineConstants);NET7_0_WINDOWS</DefineConstants>
|
<DefineConstants>$(DefineConstants);NET7_0_WINDOWS</DefineConstants>
|
||||||
@ -16,10 +15,6 @@
|
|||||||
<PackageReference Include="NSExt" Version="1.0.9-alpha.0.1"/>
|
<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.Cli.NS" Version="0.45.1-preview.0.48"/>
|
||||||
<PackageReference Include="Spectre.Console.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"/>
|
<PackageReference Condition="'$(TargetFramework)' == 'net7.0-windows'" Include="TextCopy" Version="6.2.0"/>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
@ -28,11 +23,6 @@
|
|||||||
<LastGenOutput>Str.Designer.cs</LastGenOutput>
|
<LastGenOutput>Str.Designer.cs</LastGenOutput>
|
||||||
</EmbeddedResource>
|
</EmbeddedResource>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<Import Project="../CodeQuality.props"/>
|
||||||
<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="../GenerateResx.targets"/>
|
<Import Project="../GenerateResx.targets"/>
|
||||||
</Project>
|
</Project>
|
9
stylecop.json
Normal file
9
stylecop.json
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -5,12 +5,6 @@ namespace Dot.Tests;
|
|||||||
|
|
||||||
public class TestGet
|
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]
|
[Test]
|
||||||
public void DownloadFile()
|
public void DownloadFile()
|
||||||
{
|
{
|
||||||
@ -35,4 +29,10 @@ public class TestGet
|
|||||||
|
|
||||||
[SetUp]
|
[SetUp]
|
||||||
public void 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));
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user