From de264e58a0181a7198446915b5915519b2ac8eae Mon Sep 17 00:00:00 2001 From: nsnail <taokeu@gmail.com> Date: Thu, 1 Dec 2022 17:26:37 +0800 Subject: [PATCH] 1.1.0 (#2) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * <feat> 多语言支持 * <feat> text tool 只读模式 --- .editorconfig | 45 ++ .gitignore | 816 ++++++++++++++++++++++++++++++++++- .tgitconfig | 6 +- README.md | 3 +- build.ps1 | 6 +- code-format.cmd | 6 +- dot.sln | 16 + dot.sln.DotSettings | 19 +- global.json | 10 + src/DirOption.cs | 15 + src/GlobalUsings.cs | 3 +- src/Guid/Main.cs | 2 +- src/Guid/Option.cs | 4 +- src/Lang/Strings.Designer.cs | 251 +++++++++++ src/Lang/Strings.en-US.resx | 86 ++++ src/Lang/Strings.resx | 94 ++++ src/Pwd/Main.cs | 53 +++ src/Pwd/Option.cs | 21 + src/RmBlank/Main.cs | 113 +++++ src/RmBlank/Option.cs | 4 + src/RmBom/Main.cs | 103 +++++ src/RmBom/Option.cs | 4 + src/Text/Main.cs | 4 +- src/Text/Option.cs | 4 +- src/ToLf/Main.cs | 127 ++++++ src/ToLf/Option.cs | 4 + src/Tool.cs | 23 +- src/ToolsFactory.cs | 16 +- src/dot.csproj | 19 +- 29 files changed, 1818 insertions(+), 59 deletions(-) create mode 100644 .editorconfig create mode 100644 global.json create mode 100644 src/DirOption.cs create mode 100644 src/Lang/Strings.Designer.cs create mode 100644 src/Lang/Strings.en-US.resx create mode 100644 src/Lang/Strings.resx create mode 100644 src/Pwd/Main.cs create mode 100644 src/Pwd/Option.cs create mode 100644 src/RmBlank/Main.cs create mode 100644 src/RmBlank/Option.cs create mode 100644 src/RmBom/Main.cs create mode 100644 src/RmBom/Option.cs create mode 100644 src/ToLf/Main.cs create mode 100644 src/ToLf/Option.cs diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8c3845c --- /dev/null +++ b/.editorconfig @@ -0,0 +1,45 @@ +root = true + +[*] +indent_style = space +indent_size = 4 +end_of_line = lf +charset = utf-8 +trim_trailing_whitespace = true + + +# ReSharper properties +resharper_align_linq_query = true +resharper_align_multiline_argument = true +resharper_align_multiline_array_and_object_initializer = true +resharper_align_multiline_binary_patterns = true +resharper_align_multiline_calls_chain = true +resharper_align_multiline_extends_list = true +resharper_align_multiline_parameter = true +resharper_align_multiline_property_pattern = true +resharper_align_multiline_switch_expression = true +resharper_align_multiple_declaration = true +resharper_align_multline_type_parameter_constrains = true +resharper_align_multline_type_parameter_list = true +resharper_align_tuple_components = true +resharper_allow_comment_after_lbrace = true +resharper_csharp_empty_block_style = together_same_line +resharper_csharp_outdent_commas = true +resharper_csharp_stick_comment = false +resharper_csharp_wrap_before_comma = true +resharper_indent_nested_foreach_stmt = true +resharper_indent_nested_for_stmt = true +resharper_indent_nested_while_stmt = true +resharper_indent_preprocessor_if = usual_indent +resharper_indent_preprocessor_other = usual_indent +resharper_int_align = true +resharper_keep_existing_arrangement = false +resharper_place_linq_into_on_new_line = false +resharper_place_simple_switch_expression_on_single_line = true +resharper_wrap_before_eq = true +resharper_wrap_chained_method_calls = chop_if_long +resharper_wrap_switch_expression = chop_if_long + +# Microsoft .NET properties +csharp_indent_braces = false +csharp_new_line_before_open_brace = local_functions, methods, types \ No newline at end of file diff --git a/.gitignore b/.gitignore index 03eec4a..3b36b84 100644 --- a/.gitignore +++ b/.gitignore @@ -1,23 +1,805 @@ -build -bin -obj -packages -Migrations -_gsdata_ -_ReSharper* -TestResults -app_data -nuget.config +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser *.suo *.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj *.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted *.pubxml -*.publish.xml -.svn -.vs +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ *.dbmdl +*.dbproj.schemaview *.jfm -*.exe -.idea -node_modules -dist \ No newline at end of file +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea/ + +# User define + +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. +## +## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore + +# User-specific files +*.rsuser +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Mono auto generated files +mono_crash.* + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +[Ww][Ii][Nn]32/ +[Aa][Rr][Mm]/ +[Aa][Rr][Mm]64/ +bld/ +[Bb]in/ +[Oo]bj/ +[Ll]og/ +[Ll]ogs/ + +# Visual Studio 2015/2017 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# Visual Studio 2017 auto generated files +Generated\ Files/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUnit +*.VisualState.xml +TestResult.xml +nunit-*.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# Benchmark Results +BenchmarkDotNet.Artifacts/ + +# .NET Core +project.lock.json +project.fragment.lock.json +artifacts/ + +# ASP.NET Scaffolding +ScaffoldingReadMe.txt + +# StyleCop +StyleCopReport.xml + +# Files built by Visual Studio +*_i.c +*_p.c +*_h.h +*.ilk +*.meta +*.obj +*.iobj +*.pch +*.pdb +*.ipdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*_wpftmp.csproj +*.log +*.tlog +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opendb +*.opensdf +*.sdf +*.cachefile +*.VC.db +*.VC.VC.opendb + +# Visual Studio profiler +*.psess +*.vsp +*.vspx +*.sap + +# Visual Studio Trace Files +*.e2e + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# AxoCover is a Code Coverage Tool +.axoCover/* +!.axoCover/settings.json + +# Coverlet is a free, cross platform Code Coverage Tool +coverage*.json +coverage*.xml +coverage*.info + +# Visual Studio code coverage results +*.coverage +*.coveragexml + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# Note: Comment the next line if you want to checkin your web deploy settings, +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# Microsoft Azure Web App publish settings. Comment the next line if you want to +# checkin your Azure Web App publish settings, but sensitive information contained +# in these scripts will be unencrypted +PublishScripts/ + +# NuGet Packages +*.nupkg +# NuGet Symbol Packages +*.snupkg +# The packages folder can be ignored because of Package Restore +**/[Pp]ackages/* +# except build/, which is used as an MSBuild target. +!**/[Pp]ackages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/[Pp]ackages/repositories.config +# NuGet v3's project.json files produces more ignorable files +*.nuget.props +*.nuget.targets + +# Microsoft Azure Build Output +csx/ +*.build.csdef + +# Microsoft Azure Emulator +ecf/ +rcf/ + +# Windows Store app package directories and files +AppPackages/ +BundleArtifacts/ +Package.StoreAssociation.xml +_pkginfo.txt +*.appx +*.appxbundle +*.appxupload + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!?*.[Cc]ache/ + +# Others +ClientBin/ +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.jfm +*.pfx +*.publishsettings +orleans.codegen.cs + +# Including strong name files can present a security risk +# (https://github.com/github/gitignore/pull/2483#issue-259490424) +#*.snk + +# Since there are multiple workflows, uncomment next line to ignore bower_components +# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622) +#bower_components/ + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm +ServiceFabricBackup/ +*.rptproj.bak + +# SQL Server files +*.mdf +*.ldf +*.ndf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings +*.rptproj.rsuser +*- [Bb]ackup.rdl +*- [Bb]ackup ([0-9]).rdl +*- [Bb]ackup ([0-9][0-9]).rdl + +# Microsoft Fakes +FakesAssemblies/ + +# GhostDoc plugin setting file +*.GhostDoc.xml + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat +node_modules/ + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio 6 auto-generated workspace file (contains which files were open etc.) +*.vbw + +# Visual Studio 6 auto-generated project file (contains which files were open etc.) +*.vbp + +# Visual Studio 6 workspace and project file (working project files containing files to include in project) +*.dsw +*.dsp + +# Visual Studio 6 technical files +*.ncb +*.aps + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions + +# Paket dependency manager +.paket/paket.exe +paket-files/ + +# FAKE - F# Make +.fake/ + +# CodeRush personal settings +.cr/personal + +# Python Tools for Visual Studio (PTVS) +__pycache__/ +*.pyc + +# Cake - Uncomment if you are using it +# tools/** +# !tools/packages.config + +# Tabs Studio +*.tss + +# Telerik's JustMock configuration file +*.jmconfig + +# BizTalk build output +*.btp.cs +*.btm.cs +*.odx.cs +*.xsd.cs + +# OpenCover UI analysis results +OpenCover/ + +# Azure Stream Analytics local run output +ASALocalRun/ + +# MSBuild Binary and Structured Log +*.binlog + +# NVidia Nsight GPU debugger configuration file +*.nvuser + +# MFractors (Xamarin productivity tool) working folder +.mfractor/ + +# Local History for Visual Studio +.localhistory/ + +# Visual Studio History (VSHistory) files +.vshistory/ + +# BeatPulse healthcheck temp database +healthchecksdb + +# Backup folder for Package Reference Convert tool in Visual Studio 2017 +MigrationBackup/ + +# Ionide (cross platform F# VS Code tools) working folder +.ionide/ + +# Fody - auto-generated XML schema +FodyWeavers.xsd + +# VS Code files for those working on multiple tools +.vscode/* +!.vscode/settings.json +!.vscode/tasks.json +!.vscode/launch.json +!.vscode/extensions.json +*.code-workspace + +# Local History for Visual Studio Code +.history/ + +# Windows Installer files from build outputs +*.cab +*.msi +*.msix +*.msm +*.msp + +# JetBrains Rider +*.sln.iml +.idea/ + +# User Define +build/ +nuget.config \ No newline at end of file diff --git a/.tgitconfig b/.tgitconfig index c98b9ad..380a28a 100644 --- a/.tgitconfig +++ b/.tgitconfig @@ -1,4 +1,4 @@ [hook "startcommit"] - cmdline = code-format.cmd - wait = true - show = true \ No newline at end of file + cmdline = code-format.cmd + wait = true + show = true \ No newline at end of file diff --git a/README.md b/README.md index 0c85949..d83fc0a 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,3 @@ # dot -功能全面的实用工具-程序员的瑞士军刀 \ No newline at end of file + +A full-featured utility - the programmer's swiss army knife \ No newline at end of file diff --git a/build.ps1 b/build.ps1 index 58318bd..339e42a 100644 --- a/build.ps1 +++ b/build.ps1 @@ -1,3 +1,3 @@ -dotnet build -dotnet publish -c Release -r win-x64 --sc -p:PublishSingleFile=true -o ./build/win-x64 -rm -r ./build/temp \ No newline at end of file +dotnet build +dotnet publish -c Release -r win-x64 --sc -p:"PublishSingleFile=true" -o ./build/win-x64 +Remove-Item -r ./build/temp \ No newline at end of file diff --git a/code-format.cmd b/code-format.cmd index 82c9512..253fbb5 100644 --- a/code-format.cmd +++ b/code-format.cmd @@ -1,3 +1,3 @@ -dot trim-utf8-bom -dot remove-whitespace -dot convert-lf \ No newline at end of file +dot rm-bom +dot rm-blank +dot tolf \ No newline at end of file diff --git a/dot.sln b/dot.sln index d27bc7f..f1cf980 100644 --- a/dot.sln +++ b/dot.sln @@ -5,6 +5,22 @@ VisualStudioVersion = 17.0.31903.59 MinimumVisualStudioVersion = 10.0.40219.1 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "dot", "src\dot.csproj", "{E7608D54-4A3B-4B4B-ADA0-7852987CA21F}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "root-files", "root-files", "{AD79881E-74D9-4EC7-AFE9-82D10CD32C3A}" + ProjectSection(SolutionItems) = preProject + .editorconfig = .editorconfig + .gitattributes = .gitattributes + .gitignore = .gitignore + .tgitconfig = .tgitconfig + build.ps1 = build.ps1 + code-format.cmd = code-format.cmd + Directory.Build.props = Directory.Build.props + dot.sln.DotSettings = dot.sln.DotSettings + git-clean.ps1 = git-clean.ps1 + LICENSE = LICENSE + README.md = README.md + global.json = global.json + EndProjectSection +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU diff --git a/dot.sln.DotSettings b/dot.sln.DotSettings index f7cba85..5f67123 100644 --- a/dot.sln.DotSettings +++ b/dot.sln.DotSettings @@ -1,4 +1,7 @@ -<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation"> +<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:String x:Key="/Default/CodeStyle/CSharpFileLayoutPatterns/Pattern/@EntryValue"><?xml version="1.0" encoding="utf-16"?> <Patterns xmlns="urn:schemas-jetbrains-com:member-reordering-patterns"> <TypePattern> @@ -36,10 +39,12 @@ </Entry> </TypePattern> </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> + <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> \ No newline at end of file diff --git a/global.json b/global.json new file mode 100644 index 0000000..0e46db0 --- /dev/null +++ b/global.json @@ -0,0 +1,10 @@ +{ + "sdk": { + "version": "7.0.100", + "allowPrerelease": true, + "rollForward": "major" + }, + "tools": { + "dotnet": "7.0.100" + } +} \ No newline at end of file diff --git a/src/DirOption.cs b/src/DirOption.cs new file mode 100644 index 0000000..a86564a --- /dev/null +++ b/src/DirOption.cs @@ -0,0 +1,15 @@ +namespace Dot; + +public class DirOption : IOption +{ + [Option('f', "filter", HelpText = nameof(Strings.FileSearchPattern), Default = "*.*" + , ResourceType = typeof(Strings))] + public string Filter { get; set; } + + [Value(0, HelpText = nameof(Strings.FolderPath), Default = ".", ResourceType = typeof(Strings))] + public string Path { get; set; } + + + [Option('r', "readonly", HelpText = nameof(Strings.ReadOnly), Default = false, ResourceType = typeof(Strings))] + public bool ReadOnly { get; set; } +} \ No newline at end of file diff --git a/src/GlobalUsings.cs b/src/GlobalUsings.cs index a9e96a1..38b2f93 100644 --- a/src/GlobalUsings.cs +++ b/src/GlobalUsings.cs @@ -1,2 +1,3 @@ global using ShellProgressBar; -global using CommandLine; \ No newline at end of file +global using CommandLine; +global using Dot.Lang; \ No newline at end of file diff --git a/src/Guid/Main.cs b/src/Guid/Main.cs index 7537bc3..0b157ce 100644 --- a/src/Guid/Main.cs +++ b/src/Guid/Main.cs @@ -12,6 +12,6 @@ public sealed class Main : Tool<Option> var guid = System.Guid.NewGuid().ToString(); if (Opt.Upper) guid = guid.ToUpper(); ClipboardService.SetText(guid); - Console.WriteLine($"已复制到剪贴板:{guid}"); + Console.WriteLine(Strings.Copied, guid); } } \ No newline at end of file diff --git a/src/Guid/Option.cs b/src/Guid/Option.cs index 0c1c419..44801e2 100644 --- a/src/Guid/Option.cs +++ b/src/Guid/Option.cs @@ -1,8 +1,8 @@ namespace Dot.Guid; -[Verb("guid", HelpText = "GUID工具")] +[Verb("guid", HelpText = nameof(Strings.GuidTool), ResourceType = typeof(Strings))] public class Option : IOption { - [Option('u', "upper", HelpText = "大写", Default = false)] + [Option('u', "upper", HelpText = nameof(Strings.UseUppercase), Default = false, ResourceType = typeof(Strings))] public bool Upper { get; set; } //normal options here } \ No newline at end of file diff --git a/src/Lang/Strings.Designer.cs b/src/Lang/Strings.Designer.cs new file mode 100644 index 0000000..b053a6d --- /dev/null +++ b/src/Lang/Strings.Designer.cs @@ -0,0 +1,251 @@ +//------------------------------------------------------------------------------ +// <auto-generated> +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// </auto-generated> +//------------------------------------------------------------------------------ + +namespace Dot.Lang { + using System; + + + /// <summary> + /// A strongly-typed resource class, for looking up localized strings, etc. + /// </summary> + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class Strings { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Strings() { + } + + /// <summary> + /// Returns the cached ResourceManager instance used by this class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Dot.Lang.Strings", typeof(Strings).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// <summary> + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// </summary> + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// <summary> + /// Looks up a localized string similar to 转换换行符为LF. + /// </summary> + public static string ConvertEndOfLineToLF { + get { + return ResourceManager.GetString("ConvertEndOfLineToLF", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to {0}(已复制到剪贴板). + /// </summary> + public static string Copied { + get { + return ResourceManager.GetString("Copied", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 文件通配符. + /// </summary> + public static string FileSearchPattern { + get { + return ResourceManager.GetString("FileSearchPattern", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 要处理的目录路径. + /// </summary> + public static string FolderPath { + get { + return ResourceManager.GetString("FolderPath", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to GUID工具. + /// </summary> + public static string GuidTool { + get { + return ResourceManager.GetString("GuidTool", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 文本编码工具. + /// </summary> + public static string HelpForText { + get { + return ResourceManager.GetString("HelpForText", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 输入文本为空. + /// </summary> + public static string InputTextIsEmpty { + get { + return ResourceManager.GetString("InputTextIsEmpty", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 没有需要处理的文件. + /// </summary> + public static string NoFileToBeProcessed { + get { + return ResourceManager.GetString("NoFileToBeProcessed", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 指定的路径“{0}”不存在. + /// </summary> + public static string PathNotFound { + get { + return ResourceManager.GetString("PathNotFound", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 按下任意键继续.... + /// </summary> + public static string PressAnyKey { + get { + return ResourceManager.GetString("PressAnyKey", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to BitSet 1:[0-9],2:[a-z],4:[A-Z],8:[ascii.0x21-0x2F]. + /// </summary> + public static string PwdGenerateTypes { + get { + return ResourceManager.GetString("PwdGenerateTypes", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 密码长度. + /// </summary> + public static string PwdLength { + get { + return ResourceManager.GetString("PwdLength", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 随机密码生成器. + /// </summary> + public static string RandomPasswordGenerator { + get { + return ResourceManager.GetString("RandomPasswordGenerator", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 只读模式(仅做测试,不实际修改). + /// </summary> + public static string ReadOnly { + get { + return ResourceManager.GetString("ReadOnly", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 移除文件尾部换行和空格. + /// </summary> + public static string RemoveTrailingWhiteSpaces { + get { + return ResourceManager.GetString("RemoveTrailingWhiteSpaces", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 查找文件.... + /// </summary> + public static string SearchingFile { + get { + return ResourceManager.GetString("SearchingFile", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to {0} 个文件. + /// </summary> + public static string SearchingFileOK { + get { + return ResourceManager.GetString("SearchingFileOK", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 已读取:{0}/{1},处理:{2},跳过:{3}. + /// </summary> + public static string ShowMessageTemp { + get { + return ResourceManager.GetString("ShowMessageTemp", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 要处理的文本(默认取取剪贴板值). + /// </summary> + public static string TextTobeProcessed { + get { + return ResourceManager.GetString("TextTobeProcessed", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 移除文件的uf8 bom. + /// </summary> + public static string TrimUtf8Bom { + get { + return ResourceManager.GetString("TrimUtf8Bom", resourceCulture); + } + } + + /// <summary> + /// Looks up a localized string similar to 使用大写输出. + /// </summary> + public static string UseUppercase { + get { + return ResourceManager.GetString("UseUppercase", resourceCulture); + } + } + } +} \ No newline at end of file diff --git a/src/Lang/Strings.en-US.resx b/src/Lang/Strings.en-US.resx new file mode 100644 index 0000000..d9d42b0 --- /dev/null +++ b/src/Lang/Strings.en-US.resx @@ -0,0 +1,86 @@ +<?xml version="1.0" encoding="utf-8"?> +<root> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" + id="root" xmlns=""> + <xsd:element name="root" msdata:IsDataSet="true"></xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>1.3</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + </value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + </value> + </resheader> + <data name="InputTextIsEmpty" xml:space="preserve"> + <value>The input text is empty</value> + </data> + <data name="SearchingFile" xml:space="preserve"> + <value>Find files...</value> + </data> + <data name="PathNotFound" xml:space="preserve"> + <value>The specified path "{0}" does not exist</value> + </data> + <data name="SearchingFileOK" xml:space="preserve"> + <value>Find files...OK</value> + </data> + <data name="ShowMessageTemp" xml:space="preserve"> + <value>Read: {0}/{1}, processed: {2}, skipped: {3}</value> + </data> + <data name="HelpForText" xml:space="preserve"> + <value>Text encoding tool</value> + </data> + <data name="Copied" xml:space="preserve"> + <value>{0}(copied to clipboard)</value> + </data> + <data name="FileSearchPattern" xml:space="preserve"> + <value>File wildcards</value> + </data> + <data name="FolderPath" xml:space="preserve"> + <value>Directory path to be processed</value> + </data> + <data name="ConvertEndOfLineToLF" xml:space="preserve"> + <value>Convert newline characters to LF</value> + </data> + <data name="GuidTool" xml:space="preserve"> + <value>GUID tool</value> + </data> + <data name="UseUppercase" xml:space="preserve"> + <value>Use uppercase output</value> + </data> + <data name="RandomPasswordGenerator" xml:space="preserve"> + <value>Random password generator</value> + </data> + <data name="PwdLength" xml:space="preserve"> + <value>Password length</value> + </data> + <data name="PwdGenerateTypes" xml:space="preserve"> + <value>BitSet 1:[0-9],2:[a-z],4:[A-Z],8:[ascii.0x21-0x2F]</value> + </data> + <data name="RemoveTrailingWhiteSpaces" xml:space="preserve"> + <value>Remove line breaks and spaces at the end of the file</value> + </data> + <data name="TrimUtf8Bom" xml:space="preserve"> + <value>Remove the uf8 bom of the file</value> + </data> + <data name="TextTobeProcessed" xml:space="preserve"> + <value>Text to be processed (clipboard value is taken by default)</value> + </data> + <data name="PressAnyKey" xml:space="preserve"> + <value>Press any key to continue...</value> + </data> + <data name="ReadOnly" xml:space="preserve"> + <value>Read-only mode (only for testing, no actual modification)</value> + </data> + <data name="NoFileToBeProcessed" xml:space="preserve"> + <value>No documents to be processed</value> + </data> +</root> \ No newline at end of file diff --git a/src/Lang/Strings.resx b/src/Lang/Strings.resx new file mode 100644 index 0000000..49467fb --- /dev/null +++ b/src/Lang/Strings.resx @@ -0,0 +1,94 @@ +<?xml version="1.0" encoding="utf-8"?> + +<root> + <xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata" + id="root" + xmlns=""> + <xsd:element name="root" msdata:IsDataSet="true"> + + </xsd:element> + </xsd:schema> + <resheader name="resmimetype"> + <value>text/microsoft-resx</value> + </resheader> + <resheader name="version"> + <value>1.3</value> + </resheader> + <resheader name="reader"> + <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + </value> + </resheader> + <resheader name="writer"> + <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, + PublicKeyToken=b77a5c561934e089 + </value> + </resheader> + <data name="InputTextIsEmpty" xml:space="preserve"> + <value>输入文本为空</value> + </data> + <data name="SearchingFile" xml:space="preserve"> + <value>查找文件...</value> + </data> + <data name="PathNotFound" xml:space="preserve"> + <value>指定的路径“{0}”不存在</value> + </data> + <data name="SearchingFileOK" xml:space="preserve"> + <value>{0} 个文件</value> + </data> + <data name="ShowMessageTemp" xml:space="preserve"> + <value>已读取:{0}/{1},处理:{2},跳过:{3}</value> + </data> + <data name="HelpForText" xml:space="preserve"> + <value>文本编码工具</value> + </data> + <data name="TextTobeProcessed" xml:space="preserve"> + <value>要处理的文本(默认取取剪贴板值)</value> + </data> + <data name="Copied" xml:space="preserve"> + <value>{0}(已复制到剪贴板)</value> + </data> + <data name="FileSearchPattern" xml:space="preserve"> + <value>文件通配符</value> + </data> + <data name="FolderPath" xml:space="preserve"> + <value>要处理的目录路径</value> + </data> + <data name="ConvertEndOfLineToLF" xml:space="preserve"> + <value>转换换行符为LF</value> + </data> + <data name="GuidTool" xml:space="preserve"> + <value>GUID工具</value> + </data> + <data name="UseUppercase" xml:space="preserve"> + <value>使用大写输出</value> + </data> + <data name="RandomPasswordGenerator" xml:space="preserve"> + <value>随机密码生成器</value> + </data> + + <data name="PwdLength" xml:space="preserve"> + <value>密码长度</value> + </data> + + + <data name="PwdGenerateTypes" xml:space="preserve"> + <value>BitSet 1:[0-9],2:[a-z],4:[A-Z],8:[ascii.0x21-0x2F]</value> + </data> + + <data name="RemoveTrailingWhiteSpaces" xml:space="preserve"> + <value>移除文件尾部换行和空格</value> + </data> + <data name="TrimUtf8Bom" xml:space="preserve"> + <value>移除文件的uf8 bom</value> + </data> + <data name="PressAnyKey" xml:space="preserve"> + <value>按下任意键继续...</value> + </data> + <data name="ReadOnly" xml:space="preserve"> + <value>只读模式(仅做测试,不实际修改)</value> + </data> + <data name="NoFileToBeProcessed" xml:space="preserve"> + <value>没有需要处理的文件</value> + </data> +</root> \ No newline at end of file diff --git a/src/Pwd/Main.cs b/src/Pwd/Main.cs new file mode 100644 index 0000000..7cdf363 --- /dev/null +++ b/src/Pwd/Main.cs @@ -0,0 +1,53 @@ +using NSExt.Extensions; +using TextCopy; + +namespace Dot.Pwd; + +public sealed class Main : Tool<Option> +{ + private readonly char[][] _charTable = { + "0123456789".ToCharArray() // + , "abcdefghijklmnopqrstuvwxyz".ToCharArray() + , "ABCDEFGHIJKLMNOPQRSTUVWXYZ".ToCharArray() + , "!\"#$%&'()*+,-./:;<=>?@[\\]^_`{|}~".ToCharArray() + }; + + + public Main(Option opt) : base(opt) { } + + public override void Run() + { + unsafe { + var pSource = stackalloc char[_charTable.Sum(x => x.Length)]; + var pDest = stackalloc char[Opt.Length]; + var sourceLen = 0; + + if (Opt.Type.HasFlag(Option.GenerateTypes.Number)) + foreach (var c in _charTable[0]) + *(pSource + sourceLen++) = c; + + + if (Opt.Type.HasFlag(Option.GenerateTypes.LowerCaseLetter)) + foreach (var c in _charTable[1]) + *(pSource + sourceLen++) = c; + + if (Opt.Type.HasFlag(Option.GenerateTypes.UpperCaseLetter)) + foreach (var c in _charTable[2]) + *(pSource + sourceLen++) = c; + + + if (Opt.Type.HasFlag(Option.GenerateTypes.SpecialCharacter)) + foreach (var c in _charTable[3]) + *(pSource + sourceLen++) = c; + + + var randScope = new[] { 0, sourceLen }; + for (var i = 0; i != Opt.Length; ++i) // + *(pDest + i) = *(pSource + randScope.Rand()); + + var result = new string(pDest, 0, Opt.Length); + ClipboardService.SetText(result); + Console.WriteLine(Strings.Copied, result); + } + } +} \ No newline at end of file diff --git a/src/Pwd/Option.cs b/src/Pwd/Option.cs new file mode 100644 index 0000000..80f9558 --- /dev/null +++ b/src/Pwd/Option.cs @@ -0,0 +1,21 @@ +namespace Dot.Pwd; + +[Verb("pwd", HelpText = nameof(Strings.RandomPasswordGenerator), ResourceType = typeof(Strings))] +public class Option : IOption +{ + [Flags] + public enum GenerateTypes + { + Number = 1 + , LowerCaseLetter = 2 + , UpperCaseLetter = 4 + , SpecialCharacter = 8 + } + + [Value(1, Required = true, HelpText = nameof(Strings.PwdLength), ResourceType = typeof(Strings))] + public int Length { get; set; } + + + [Value(0, Required = true, HelpText = nameof(Strings.PwdGenerateTypes), ResourceType = typeof(Strings))] + public GenerateTypes Type { get; set; } +} \ No newline at end of file diff --git a/src/RmBlank/Main.cs b/src/RmBlank/Main.cs new file mode 100644 index 0000000..d1af5bc --- /dev/null +++ b/src/RmBlank/Main.cs @@ -0,0 +1,113 @@ +using System.Diagnostics.CodeAnalysis; +using NSExt.Extensions; + +namespace Dot.RmBlank; + +public sealed class Main : Tool<Option>, IDisposable +{ + private int _breakCnt; + private bool _disposed; + private static readonly object _lockObj = new(); + private int _procedCnt; + private int _replaceCnt; + private ChildProgressBar _step2Bar; + private int _totalCnt; + public Main(Option opt) : base(opt) { } + + + ~Main() + { + Dispose(false); + } + + private void Dispose(bool disposing) + { + if (_disposed) return; + if (disposing) _step2Bar?.Dispose(); + _disposed = true; + } + + private void FileHandle(string file) + { + _step2Bar.Tick(); + ShowMessage(1, 0, 0); + var spacesCnt = 0; + + using var fsrw = OpenFileStream(file, FileMode.Open, FileAccess.ReadWrite); + + if (Opt.ReadOnly) { //测试,只读模式 + ShowMessage(0, 1, 0); + return; + } + + + if (fsrw is null || fsrw.Length == 0 || (spacesCnt = GetSpacesCnt(fsrw)) == 0) { + ShowMessage(0, 0, 1); + return; + } + + fsrw.Seek(0, SeekOrigin.Begin); + if (!fsrw.IsTextStream()) return; + ShowMessage(0, 1, 0); + fsrw.SetLength(fsrw.Length - spacesCnt); + } + + 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; + } + + + private void ShowMessage(int procedCnt, int removeCnt, int breakCnt) + { + lock (_lockObj) { + _procedCnt += procedCnt; + _replaceCnt += removeCnt; + _breakCnt += breakCnt; + _step2Bar.Message = string.Format(Strings.ShowMessageTemp, _procedCnt, _totalCnt, _replaceCnt, _breakCnt); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + /// <inheritdoc /> + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] + public override void Run() + { + if (!Directory.Exists(Opt.Path)) + throw new ArgumentException(nameof(Opt.Path), string.Format(Strings.PathNotFound, Opt.Path)); + + + using var step1Bar = new IndeterminateProgressBar(Strings.SearchingFile, DefaultProgressBarOptions); + + + var fileList = EnumerateFiles(Opt.Path, Opt.Filter); + _totalCnt = fileList.Count(); + + step1Bar.Message = string.Format(Strings.SearchingFileOK, _totalCnt); + step1Bar.Finished(); + if (_totalCnt == 0) return; + + + _step2Bar = step1Bar.Spawn(_totalCnt, string.Empty, DefaultProgressBarOptions); + + Parallel.ForEach(fileList, FileHandle); + } +} \ No newline at end of file diff --git a/src/RmBlank/Option.cs b/src/RmBlank/Option.cs new file mode 100644 index 0000000..e9523d9 --- /dev/null +++ b/src/RmBlank/Option.cs @@ -0,0 +1,4 @@ +namespace Dot.RmBlank; + +[Verb("rm-blank", HelpText = nameof(Strings.RemoveTrailingWhiteSpaces), ResourceType = typeof(Strings))] +public class Option : DirOption { } \ No newline at end of file diff --git a/src/RmBom/Main.cs b/src/RmBom/Main.cs new file mode 100644 index 0000000..c38a003 --- /dev/null +++ b/src/RmBom/Main.cs @@ -0,0 +1,103 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Dot.RmBom; + +public sealed class Main : Tool<Option>, IDisposable +{ + private int _breakCnt; + private bool _disposed; + private static readonly object _lockObj = new(); + private int _procedCnt; + private ChildProgressBar _step2Bar; + private int _totalCnt; + private int _trimCnt; + public Main(Option opt) : base(opt) { } + + + ~Main() + { + Dispose(false); + } + + private void Dispose(bool disposing) + { + if (_disposed) return; + if (disposing) _step2Bar?.Dispose(); + _disposed = true; + } + + + private void ShowMessage(int procedCnt, int replaceCnt, int breakCnt) + { + lock (_lockObj) { + _procedCnt += procedCnt; + _trimCnt += replaceCnt; + _breakCnt += breakCnt; + _step2Bar.Message = string.Format(Strings.ShowMessageTemp, _procedCnt, _totalCnt, _trimCnt, _breakCnt); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] + public override void Run() + { + if (!Directory.Exists(Opt.Path)) + throw new ArgumentException(nameof(Opt.Path), string.Format(Strings.PathNotFound, Opt.Path)); + + + var utf8Bom = new byte[] { 0xef, 0xbb, 0xbf }; + using var step1Bar = new IndeterminateProgressBar(Strings.SearchingFile, DefaultProgressBarOptions); + + + var fileList = EnumerateFiles(Opt.Path, Opt.Filter); + _totalCnt = fileList.Count(); + + step1Bar.Message = string.Format(Strings.SearchingFileOK, _totalCnt); + step1Bar.Finished(); + if (_totalCnt == 0) return; + + _step2Bar = step1Bar.Spawn(_totalCnt, string.Empty, DefaultProgressBarOptions); + + Parallel.ForEach(fileList, file => { + _step2Bar.Tick(); + ShowMessage(1, 0, 0); + + var tmpFile = $"{file}.tmp"; + var isReplaced = false; + using (var fsr = OpenFileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { + if (Opt.ReadOnly) { //测试,只读模式 + ShowMessage(0, 1, 0); + return; + } + + if (fsr is null) { + ShowMessage(0, 0, 1); + return; + } + + + Span<byte> buffer = stackalloc byte[utf8Bom.Length]; + var readLen = fsr.Read(buffer); + if (readLen == utf8Bom.Length && buffer.SequenceEqual(utf8Bom)) { + using var fsw = OpenFileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.Write); + int data; + while ((data = fsr.ReadByte()) != -1) fsw.WriteByte((byte)data); + isReplaced = true; + } + } + + if (isReplaced) { + MoveFile(tmpFile, file); + ShowMessage(0, 1, 0); + } + else { + ShowMessage(0, 0, 1); + } + }); + } +} \ No newline at end of file diff --git a/src/RmBom/Option.cs b/src/RmBom/Option.cs new file mode 100644 index 0000000..579a772 --- /dev/null +++ b/src/RmBom/Option.cs @@ -0,0 +1,4 @@ +namespace Dot.RmBom; + +[Verb("rm-bom", HelpText = nameof(Strings.TrimUtf8Bom), ResourceType = typeof(Strings))] +public class Option : DirOption { } \ No newline at end of file diff --git a/src/Text/Main.cs b/src/Text/Main.cs index b84dd1a..f083935 100644 --- a/src/Text/Main.cs +++ b/src/Text/Main.cs @@ -28,7 +28,7 @@ public sealed class Main : Tool<Option> public Main(Option opt) : base(opt) { if (Opt.Text.NullOrEmpty()) Opt.Text = ClipboardService.GetText(); - if (Opt.Text.NullOrEmpty()) throw new ArgumentException("输入文本为空"); + if (Opt.Text.NullOrEmpty()) throw new ArgumentException(Strings.InputTextIsEmpty); } private static Output BuildOutput(string text, Encoding enc) @@ -102,5 +102,7 @@ html-decode: {o.HtmlDecode} PrintOutput(utf8); PrintOutput(unicodeLittleEndian); PrintOutput(unicodeBigEndian); + Console.Write(Strings.PressAnyKey); + Console.ReadKey(); } } \ No newline at end of file diff --git a/src/Text/Option.cs b/src/Text/Option.cs index 3ce844b..17af8ac 100644 --- a/src/Text/Option.cs +++ b/src/Text/Option.cs @@ -1,8 +1,8 @@ namespace Dot.Text; -[Verb("text", HelpText = "文本编码工具")] +[Verb("text", HelpText = nameof(Strings.HelpForText), ResourceType = typeof(Strings))] public class Option : IOption { - [Value(0, MetaName = "文本", HelpText = "要处理的文本,不指定此参数:取剪贴板值")] + [Value(0, HelpText = nameof(Strings.TextTobeProcessed), ResourceType = typeof(Strings))] public string Text { get; set; } } \ No newline at end of file diff --git a/src/ToLf/Main.cs b/src/ToLf/Main.cs new file mode 100644 index 0000000..e53741b --- /dev/null +++ b/src/ToLf/Main.cs @@ -0,0 +1,127 @@ +using System.Diagnostics.CodeAnalysis; + +namespace Dot.ToLf; + +public sealed class Main : Tool<Option>, IDisposable +{ + private int _breakCnt; + private bool _disposed; + private static readonly object _lockObj = new(); + private int _procedCnt; + private int _replaceCnt; + private ChildProgressBar _step2Bar; + private int _totalCnt; + public Main(Option opt) : base(opt) { } + + + ~Main() + { + Dispose(false); + } + + private void Dispose(bool disposing) + { + if (_disposed) return; + if (disposing) _step2Bar?.Dispose(); + _disposed = true; + } + + private void FileHandle(string file) + { + _step2Bar.Tick(); + ShowMessage(1, 0, 0); + + var tmpFile = $"{file}.tmp"; + var isReplaced = false; + var isBin = false; + int data; + + using (var fsr = OpenFileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) { + if (Opt.ReadOnly) { //测试,只读模式 + ShowMessage(0, 1, 0); + return; + } + + if (fsr is null) { + ShowMessage(0, 0, 1); + return; + } + + + using var fsw = OpenFileStream(tmpFile, FileMode.OpenOrCreate, FileAccess.Write); + + while ((data = fsr.ReadByte()) != -1) { + switch (data) { + case 0x0d when fsr.ReadByte() == 0x0a: // crlf windows + fsw.WriteByte(0x0a); + isReplaced = true; + continue; + case 0x0d: //cr macos + fsw.WriteByte(0x0a); + fsr.Seek(-1, SeekOrigin.Current); + isReplaced = true; + continue; + case 0x00 or 0xff: //非文本文件 + isBin = true; + break; + default: + fsw.WriteByte((byte)data); + continue; + } + + break; + } + } + + + if (isReplaced && !isBin) { + MoveFile(tmpFile, file); + + ShowMessage(0, 1, 0); + } + else { + File.Delete(tmpFile); + ShowMessage(0, 0, 1); + } + } + + + private void ShowMessage(int procedCnt, int replaceCnt, int breakCnt) + { + lock (_lockObj) { + _procedCnt += procedCnt; + _replaceCnt += replaceCnt; + _breakCnt += breakCnt; + _step2Bar.Message = string.Format(Strings.ShowMessageTemp, _procedCnt, _totalCnt, _replaceCnt, _breakCnt); + } + } + + public void Dispose() + { + Dispose(true); + GC.SuppressFinalize(this); + } + + [SuppressMessage("ReSharper", "PossibleMultipleEnumeration")] + public override void Run() + { + if (!Directory.Exists(Opt.Path)) + throw new ArgumentException(nameof(Opt.Path), string.Format(Strings.PathNotFound, Opt.Path)); + + + using var step1Bar = new IndeterminateProgressBar(Strings.SearchingFile, DefaultProgressBarOptions); + + + var fileList = EnumerateFiles(Opt.Path, Opt.Filter); + _totalCnt = fileList.Count(); + + step1Bar.Message = string.Format(Strings.SearchingFileOK, _totalCnt); + step1Bar.Finished(); + if (_totalCnt == 0) return; + + + _step2Bar = step1Bar.Spawn(_totalCnt, string.Empty, DefaultProgressBarOptions); + + Parallel.ForEach(fileList, FileHandle); + } +} \ No newline at end of file diff --git a/src/ToLf/Option.cs b/src/ToLf/Option.cs new file mode 100644 index 0000000..e5637f2 --- /dev/null +++ b/src/ToLf/Option.cs @@ -0,0 +1,4 @@ +namespace Dot.ToLf; + +[Verb("tolf", HelpText = nameof(Strings.ConvertEndOfLineToLF), ResourceType = typeof(Strings))] +public class Option : DirOption { } \ No newline at end of file diff --git a/src/Tool.cs b/src/Tool.cs index ff4641c..1f06c3e 100644 --- a/src/Tool.cs +++ b/src/Tool.cs @@ -9,10 +9,11 @@ public abstract class Tool<TOption> : ITool , ForegroundColor = ConsoleColor.Yellow , ForegroundColorDone = ConsoleColor.DarkGreen , BackgroundColor = ConsoleColor.DarkGray - , BackgroundCharacter = '\u2593' + , BackgroundCharacter = '\u2500' + , ProgressCharacter = '\u2500' }; - protected virtual TOption Opt { get; set; } + protected TOption Opt { get; set; } protected Tool(TOption opt) { @@ -43,17 +44,23 @@ public abstract class Tool<TOption> : ITool } } - protected static FileStream OpenFileToWrite(string file) + protected static FileStream OpenFileStream(string file, FileMode mode, FileAccess access + , FileShare share = FileShare.Read) { - FileStream fsr; + FileStream fsr = null; try { - fsr = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); + fsr = new FileStream(file, mode, access, share); } catch (UnauthorizedAccessException) { - File.SetAttributes(file, new FileInfo(file).Attributes & ~FileAttributes.ReadOnly); - fsr = new FileStream(file, FileMode.Open, FileAccess.ReadWrite, FileShare.Read); + try { + File.SetAttributes(file, new FileInfo(file).Attributes & ~FileAttributes.ReadOnly); + fsr = new FileStream(file, mode, access, share); + } + catch (Exception) { + // ignored + } } - + catch (IOException) { } return fsr; } diff --git a/src/ToolsFactory.cs b/src/ToolsFactory.cs index b02ca76..67d2f1f 100644 --- a/src/ToolsFactory.cs +++ b/src/ToolsFactory.cs @@ -1,4 +1,4 @@ -using Dot.TrimUtf8Bom; +using Dot.RmBom; namespace Dot; @@ -7,13 +7,13 @@ public static class ToolsFactory public static ITool Create(IOption option) { return option switch { - Option o => new Main(o) - , Convert2Lf.Option o => new Convert2Lf.Main(o) - , RemoveTrailingWhiteSpace.Option o => new RemoveTrailingWhiteSpace.Main(o) - , Random.Option o => new Random.Main(o) - , Text.Option o => new Text.Main(o) - , Guid.Option o => new Guid.Main(o) - , _ => throw new ArgumentOutOfRangeException(nameof(option)) + Option o => new Main(o) + , ToLf.Option o => new ToLf.Main(o) + , RmBlank.Option o => new RmBlank.Main(o) + , Pwd.Option o => new Pwd.Main(o) + , Text.Option o => new Text.Main(o) + , Guid.Option o => new Guid.Main(o) + , _ => throw new ArgumentOutOfRangeException(nameof(option)) }; } } \ No newline at end of file diff --git a/src/dot.csproj b/src/dot.csproj index b168f25..ec1a403 100644 --- a/src/dot.csproj +++ b/src/dot.csproj @@ -6,12 +6,12 @@ <ImplicitUsings>enable</ImplicitUsings> <RootNamespace>Dot</RootNamespace> <AssemblyName>dot</AssemblyName> - <Version>1.0.1</Version> + <Version>1.1.0</Version> <Authors>nsnail</Authors> <Copyright>Copyright (c) 2022 nsnail</Copyright> <RepositoryUrl>https://github.com/nsnail/dot.git</RepositoryUrl> <RepositoryType>git</RepositoryType> - <AssemblyTitle>功能全面的实用工具-程序员的瑞士军刀</AssemblyTitle> + <AssemblyTitle>功能全面的实用工具 - 程序员的瑞士军刀</AssemblyTitle> </PropertyGroup> <PropertyGroup Condition=" '$(Configuration)' == 'Debug' "> @@ -29,4 +29,19 @@ <PackageReference Include="TextCopy" Version="6.2.0"/> </ItemGroup> + <ItemGroup> + <EmbeddedResource Update="Lang\Strings.resx"> + <Generator>PublicResXFileCodeGenerator</Generator> + <LastGenOutput>Strings.Designer.cs</LastGenOutput> + </EmbeddedResource> + </ItemGroup> + + <ItemGroup> + <Compile Update="Lang\Strings.Designer.cs"> + <DesignTime>True</DesignTime> + <AutoGen>True</AutoGen> + <DependentUpon>Strings.resx</DependentUpon> + </Compile> + </ItemGroup> + </Project> \ No newline at end of file