This commit is contained in:
nsnail 2022-12-09 16:39:04 +08:00
parent f4b7c5d0ad
commit 0594ec1836
37 changed files with 276 additions and 183 deletions

View File

@ -1,4 +1,6 @@
dotnet build dotnet build
dotnet publish -f net7.0-windows -c Release -r win-x64 --sc -p:"PublishSingleFile=true" -o ./build/win-x64 mkdir ./build/win-x64/lite
dotnet publish -f net7.0 -c Release -r win-x64 --sc -p:"PublishSingleFile=true" -p:"PublishTrimmed=true" -p:"UseSystemResourceKeys=true" -o ./build/win-x64/lite
dotnet publish -f net7.0-windows -c Release -r win-x64 --sc -p:"PublishSingleFile=true" -o ./build/win-x64/full
dotnet publish -f net7.0 -c Release -r linux-x64 --sc -p:"PublishSingleFile=true" -o ./build/linux-x64 dotnet publish -f net7.0 -c Release -r linux-x64 --sc -p:"PublishSingleFile=true" -o ./build/linux-x64
Remove-Item -r ./build/temp Remove-Item -r ./build/temp

12
dot.sln
View File

@ -30,6 +30,10 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "meta", "meta", "{AD79881E-7
switcher.json = switcher.json switcher.json = switcher.json
EndProjectSection EndProjectSection
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NSExt", "..\..\..\..\ForkedGitReps\ns-ext\src\NSExt.csproj", "{E937021D-2D7D-4741-8B59-DE835F7D0E09}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Spectre.Console.Cli", "..\..\..\..\ForkedGitReps\spectre.console\src\Spectre.Console.Cli\Spectre.Console.Cli.csproj", "{7C7321B4-C4BD-4DB4-9DF4-E487EFB8F307}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
@ -43,5 +47,13 @@ Global
{E7608D54-4A3B-4B4B-ADA0-7852987CA21F}.Debug|Any CPU.Build.0 = Debug|Any CPU {E7608D54-4A3B-4B4B-ADA0-7852987CA21F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E7608D54-4A3B-4B4B-ADA0-7852987CA21F}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7608D54-4A3B-4B4B-ADA0-7852987CA21F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E7608D54-4A3B-4B4B-ADA0-7852987CA21F}.Release|Any CPU.Build.0 = Release|Any CPU {E7608D54-4A3B-4B4B-ADA0-7852987CA21F}.Release|Any CPU.Build.0 = Release|Any CPU
{E937021D-2D7D-4741-8B59-DE835F7D0E09}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E937021D-2D7D-4741-8B59-DE835F7D0E09}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E937021D-2D7D-4741-8B59-DE835F7D0E09}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E937021D-2D7D-4741-8B59-DE835F7D0E09}.Release|Any CPU.Build.0 = Release|Any CPU
{7C7321B4-C4BD-4DB4-9DF4-E487EFB8F307}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7C7321B4-C4BD-4DB4-9DF4-E487EFB8F307}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7C7321B4-C4BD-4DB4-9DF4-E487EFB8F307}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7C7321B4-C4BD-4DB4-9DF4-E487EFB8F307}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
EndGlobal EndGlobal

28
src/AssemblyInfo.cs Normal file
View File

@ -0,0 +1,28 @@
using System.Reflection;
using Dot;
[assembly: AssemblyCompany(AssemblyInfo.ASSEMBLY_COMPANY)]
[assembly: AssemblyCopyright(AssemblyInfo.ASSEMBLY_COPYRIGHT)]
[assembly: AssemblyFileVersion(AssemblyInfo.ASSEMBLY_FILE_VERSION)]
[assembly: AssemblyInformationalVersion(AssemblyInfo.ASSEMBLY_INFORMATIONAL_VERSION)]
[assembly: AssemblyProduct(AssemblyInfo.ASSEMBLY_PRODUCT)]
[assembly: AssemblyTitle(AssemblyInfo.ASSEMBLY_TITLE)]
[assembly: AssemblyVersion(AssemblyInfo.ASSEMBLY_VERSION)]
[assembly: AssemblyMetadata("RepositoryUrl", AssemblyInfo.ASSEMBLY_METADATA_REPOSITORY_URL)]
[assembly: AssemblyMetadata("RepositoryType", AssemblyInfo.ASSEMBLY_METADATA_REPOSITORY_TYPE)]
namespace Dot;
public static class AssemblyInfo
{
private const string _VERSION = "1.1.5";
public const string ASSEMBLY_COMPANY = "nsnail";
public const string ASSEMBLY_COPYRIGHT = $"Copyright (c) 2022 {ASSEMBLY_COMPANY}";
public const string ASSEMBLY_FILE_VERSION = _VERSION;
public const string ASSEMBLY_INFORMATIONAL_VERSION = _VERSION;
public const string ASSEMBLY_METADATA_REPOSITORY_TYPE = "git";
public const string ASSEMBLY_METADATA_REPOSITORY_URL = "https://github.com/nsnail/dot.git";
public const string ASSEMBLY_PRODUCT = "dot";
public const string ASSEMBLY_TITLE = "功能全面的实用工具 - 程序员的瑞士军刀";
public const string ASSEMBLY_VERSION = _VERSION;
}

View File

@ -1,11 +1,11 @@
#if NET7_0_WINDOWS #if NET7_0_WINDOWS
namespace Dot.Color; namespace Dot.Color;
[Description(nameof(Str.ScreenPixelTool))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option> public sealed class Main : ToolBase<Option>
{ {
public Main(Option opt) : base(opt) { }
protected override Task Core() protected override Task Core()
{ {
Application.Run(new WinMain()); Application.Run(new WinMain());

View File

@ -1,4 +1,3 @@
namespace Dot.Color; namespace Dot.Color;
[Verb("color", HelpText = nameof(Str.ScreenPixelTool), ResourceType = typeof(Str))]
public class Option : OptionBase { } public class Option : OptionBase { }

View File

@ -2,21 +2,36 @@ namespace Dot;
public class DirOption : OptionBase public class DirOption : OptionBase
{ {
[Option('e', "exclude", HelpText = nameof(Str.ExcludePathRegexes), ResourceType = typeof(Str))] [CommandOption("-e|--exclude")]
[Description(nameof(Str.ExcludePathRegexes))]
[Localization(typeof(Str))]
public IEnumerable<string> ExcludeRegexes { get; set; } public IEnumerable<string> ExcludeRegexes { get; set; }
[Option('f', "filter", HelpText = nameof(Str.FileSearchPattern), Default = "*", ResourceType = typeof(Str))]
[CommandOption("-f|--filter")]
[Description(nameof(Str.FileSearchPattern))]
[Localization(typeof(Str))]
[DefaultValue("*")]
public string Filter { get; set; } public string Filter { get; set; }
[Option('d', "max-depth", HelpText = nameof(Str.MaxRecursionDepth), Default = int.MaxValue [CommandOption("-d|--max-depth")]
, ResourceType = typeof(Str))] [Description(nameof(Str.MaxRecursionDepth))]
[Localization(typeof(Str))]
[DefaultValue(int.MaxValue)]
public int MaxRecursionDepth { get; set; } public int MaxRecursionDepth { get; set; }
[Value(0, HelpText = nameof(Str.FolderPath), Default = ".", ResourceType = typeof(Str))]
[CommandArgument(0, "[path]")]
[Description(nameof(Str.FolderPath))]
[Localization(typeof(Str))]
[DefaultValue(".")]
public string Path { get; set; } public string Path { get; set; }
[Option('w', "write", HelpText = nameof(Str.WriteMode), Default = false, ResourceType = typeof(Str))] [CommandOption("-w|--write")]
[Description(nameof(Str.WriteMode))]
[Localization(typeof(Str))]
[DefaultValue(false)]
public bool WriteMode { get; set; } public bool WriteMode { get; set; }
} }

View File

@ -15,7 +15,7 @@ public abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : Dir
private int _writeCnt; //写入文件数 private int _writeCnt; //写入文件数
private readonly ConcurrentDictionary<string, int> _writeStats = new(); //写入统计:后缀,数量 private readonly ConcurrentDictionary<string, int> _writeStats = new(); //写入统计:后缀,数量
protected FilesTool(TOption opt) : base(opt) protected FilesTool()
{ {
if (!Directory.Exists(Opt.Path)) if (!Directory.Exists(Opt.Path))
throw new ArgumentException(nameof(Opt.Path), string.Format(Str.PathNotFound, Opt.Path)); throw new ArgumentException(nameof(Opt.Path), string.Format(Str.PathNotFound, Opt.Path));

View File

@ -5,20 +5,14 @@ using NSExt.Extensions;
namespace Dot.Git; namespace Dot.Git;
[Description(nameof(Str.GitTool))]
[Localization(typeof(Str))]
public class Main : ToolBase<Option> public class Main : ToolBase<Option>
{ {
private readonly 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;
public Main(Option opt) : base(opt)
{
_gitOutputEnc = Encoding.GetEncoding(Opt.GitOutputEncoding);
if (!Directory.Exists(Opt.Path))
throw new ArgumentException(nameof(Opt.Path) //
, string.Format(Str.PathNotFound, Opt.Path));
}
private async ValueTask DirHandle(KeyValuePair<string, ProgressTask> payload, CancellationToken _) private async ValueTask DirHandle(KeyValuePair<string, ProgressTask> payload, CancellationToken _)
{ {
@ -67,9 +61,14 @@ public class Main : ToolBase<Option>
} }
} }
protected override async Task Core() protected override async Task Core()
{ {
_gitOutputEnc = Encoding.GetEncoding(Opt.GitOutputEncoding);
if (!Directory.Exists(Opt.Path))
throw new ArgumentException(nameof(Opt.Path) //
, string.Format(Str.PathNotFound, Opt.Path));
var progressBar = new ProgressBarColumn { Width = 10 }; var progressBar = new ProgressBarColumn { Width = 10 };
await AnsiConsole.Progress() await AnsiConsole.Progress()
.Columns(progressBar // .Columns(progressBar //

View File

@ -1,19 +1,29 @@
namespace Dot.Git; namespace Dot.Git;
[Verb("git", HelpText = nameof(Str.GitTool), ResourceType = typeof(Str))]
public class Option : OptionBase public class Option : OptionBase
{ {
[Option('a', "args", HelpText = nameof(Str.GitArgs), Default = "status", ResourceType = typeof(Str))] [CommandOption("-a|--args")]
[Description(nameof(Str.GitArgs))]
[Localization(typeof(Str))]
[DefaultValue("status")]
public string Args { get; set; } public string Args { get; set; }
[Option('e', "git-output-encoding", HelpText = nameof(Str.GitOutputEncoding), Default = "utf-8" [CommandOption("-e|--git-output-encoding")]
, ResourceType = typeof(Str))] [Description(nameof(Str.GitOutputEncoding))]
[Localization(typeof(Str))]
[DefaultValue("utf-8")]
public string GitOutputEncoding { get; set; } public string GitOutputEncoding { get; set; }
[Option('d', "max-recursion-depth", HelpText = nameof(Str.MaxRecursionDepth), Default = int.MaxValue [CommandOption("-d|--max-recursion-depth")]
, ResourceType = typeof(Str))] [Description(nameof(Str.MaxRecursionDepth))]
[Localization(typeof(Str))]
[DefaultValue(int.MaxValue)]
public int MaxRecursionDepth { get; set; } public int MaxRecursionDepth { get; set; }
[Value(0, HelpText = nameof(Str.FolderPath), Default = ".", ResourceType = typeof(Str))]
[CommandArgument(0, "[path]")]
[Description(nameof(Str.FolderPath))]
[Localization(typeof(Str))]
[DefaultValue(".")]
public string Path { get; set; } public string Path { get; set; }
} }

View File

@ -1,4 +1,3 @@
using System.ComponentModel;
using NSExt.Extensions; using NSExt.Extensions;
using Spectre.Console.Rendering; using Spectre.Console.Rendering;

View File

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

View File

@ -4,11 +4,10 @@ using TextCopy;
namespace Dot.Guid; namespace Dot.Guid;
[Description(nameof(Str.GuidTool))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option> public sealed class Main : ToolBase<Option>
{ {
public Main(Option opt) : base(opt) { }
protected override Task Core() protected override Task Core()
{ {
var guid = System.Guid.NewGuid().ToString(); var guid = System.Guid.NewGuid().ToString();

View File

@ -1,8 +1,10 @@
namespace Dot.Guid; namespace Dot.Guid;
[Verb("guid", HelpText = nameof(Str.GuidTool), ResourceType = typeof(Str))]
public class Option : OptionBase public class Option : OptionBase
{ {
[Option('u', "upper", HelpText = nameof(Str.UseUppercase), Default = false, ResourceType = typeof(Str))] [CommandOption("-u|--upper")]
[Description(nameof(Str.UseUppercase))]
[Localization(typeof(Str))]
[DefaultValue(false)]
public bool Upper { get; set; } //normal options here public bool Upper { get; set; } //normal options here
} }

View File

@ -3,11 +3,11 @@ using System.Net.Sockets;
namespace Dot.IP; namespace Dot.IP;
[Description(nameof(Str.Ip))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option> public sealed class Main : ToolBase<Option>
{ {
public Main(Option opt) : base(opt) { }
protected override async Task Core() protected override async Task Core()
{ {
foreach (var item in NetworkInterface.GetAllNetworkInterfaces()) { foreach (var item in NetworkInterface.GetAllNetworkInterfaces()) {

View File

@ -1,4 +1,3 @@
namespace Dot.IP; namespace Dot.IP;
[Verb("ip", HelpText = nameof(Str.Ip), ResourceType = typeof(Str))]
public class Option : OptionBase { } public class Option : OptionBase { }

View File

@ -1,6 +0,0 @@
namespace Dot;
public interface ITool
{
Task Run();
}

View File

@ -7,33 +7,11 @@ using TextCopy;
namespace Dot.Json; namespace Dot.Json;
[Description(nameof(Str.Json))]
[Localization(typeof(Str))]
public class Main : ToolBase<Option> public class Main : ToolBase<Option>
{ {
private readonly object _inputObj; private object _inputObj;
public Main(Option opt) : base(opt)
{
var inputText = Opt.InputText;
#if NET7_0_WINDOWS
if (inputText.NullOrWhiteSpace()) inputText = ClipboardService.GetText();
#endif
if (inputText.NullOrWhiteSpace()) throw new ArgumentException(Str.InputTextIsEmpty);
try {
_inputObj = inputText.Object<object>();
}
catch (JsonException) {
try {
inputText = UnescapeString(inputText);
_inputObj = inputText.Object<object>();
return;
}
catch (JsonException) { }
throw new ArgumentException(Str.InvalidJsonString);
}
}
private async Task<string> ConvertToString() private async Task<string> ConvertToString()
@ -62,6 +40,28 @@ public class Main : ToolBase<Option>
protected override async Task Core() protected override async Task Core()
{ {
var inputText = Opt.InputText;
#if NET7_0_WINDOWS
if (inputText.NullOrWhiteSpace()) inputText = ClipboardService.GetText();
#endif
if (inputText.NullOrWhiteSpace()) throw new ArgumentException(Str.InputTextIsEmpty);
try {
_inputObj = inputText.Object<object>();
}
catch (JsonException) {
try {
inputText = UnescapeString(inputText);
_inputObj = inputText.Object<object>();
return;
}
catch (JsonException) { }
throw new ArgumentException(Str.InvalidJsonString);
}
string result = null; string result = null;
if (Opt.Compress) if (Opt.Compress)
result = await JsonCompress(); result = await JsonCompress();

View File

@ -1,18 +1,30 @@
namespace Dot.Json; namespace Dot.Json;
[Verb("json", HelpText = nameof(Str.Json), ResourceType = typeof(Str))]
public class Option : OptionBase public class Option : OptionBase
{ {
[Option('c', "compress", HelpText = nameof(Str.CompressJson), Default = false, ResourceType = typeof(Str))] [CommandOption("-c|--compress")]
[Description(nameof(Str.CompressJson))]
[Localization(typeof(Str))]
[DefaultValue(false)]
public bool Compress { get; set; } public bool Compress { get; set; }
[Option('s', "convert-to-string", HelpText = nameof(Str.FormatJson), Default = false, ResourceType = typeof(Str))] [CommandOption("-s|--convert-to-string")]
[Description(nameof(Str.JsonToString))]
[Localization(typeof(Str))]
[DefaultValue(false)]
public bool ConvertToString { get; set; } public bool ConvertToString { get; set; }
[Option('f', "format", HelpText = nameof(Str.FormatJson), Default = true, ResourceType = typeof(Str))]
[CommandOption("-f|--format")]
[Description(nameof(Str.FormatJson))]
[Localization(typeof(Str))]
[DefaultValue(true)]
public bool Format { get; set; } public bool Format { get; set; }
[Value(0, HelpText = nameof(Str.TextTobeProcessed), ResourceType = typeof(Str))]
[CommandArgument(0, "[input text]")]
[Description(nameof(Str.TextTobeProcessed))]
[Localization(typeof(Str))]
public string InputText { get; set; } public string InputText { get; set; }
} }

View File

@ -1,7 +1,10 @@
namespace Dot; namespace Dot;
public abstract class OptionBase : IOption public abstract class OptionBase : CommandSettings, IOption
{ {
[Option('k', "keep-session", HelpText = nameof(Str.KeepSession), Default = false, ResourceType = typeof(Str))] [CommandOption("-k|--keep--session")]
[Description(nameof(Str.KeepSession))]
[Localization(typeof(Str))]
[DefaultValue(false)]
public virtual bool KeepSession { get; set; } public virtual bool KeepSession { get; set; }
} }

View File

@ -1,4 +1,34 @@
using System.Reflection; using Dot;
using Dot.Git;
var app = new CommandApp();
app.Configure(config => {
config.SetApplicationName(AssemblyInfo.ASSEMBLY_PRODUCT);
config.SetApplicationVersion(AssemblyInfo.ASSEMBLY_VERSION);
config.AddCommand<Main>("git");
#if NET7_0_WINDOWS
config.AddCommand<Dot.Color.Main>("color");
#endif
config.AddCommand<Dot.Guid.Main>("guid");
config.AddCommand<Dot.IP.Main>("ip");
config.AddCommand<Dot.Json.Main>("json");
config.AddCommand<Dot.Pwd.Main>("pwd");
config.AddCommand<Dot.RmBlank.Main>("rblank");
config.AddCommand<Dot.RmBom.Main>("rbom");
config.AddCommand<Dot.Text.Main>("text");
config.AddCommand<Dot.Time.Main>("time");
config.AddCommand<Dot.ToLf.Main>("tolf");
config.ValidateExamples();
});
return app.Run(args);
/*using System.Reflection;
using System.Text; using System.Text;
using Dot; using Dot;
@ -31,4 +61,4 @@ catch (ArgumentException ex) {
return -1; return -1;
} }
return 0; return 0;*/

View File

@ -6,6 +6,8 @@ using TextCopy;
namespace Dot.Pwd; namespace Dot.Pwd;
[Description(nameof(Str.RandomPasswordGenerator))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option> public sealed class Main : ToolBase<Option>
{ {
private readonly char[][] _charTable = { private readonly char[][] _charTable = {
@ -16,8 +18,6 @@ public sealed class Main : ToolBase<Option>
}; };
public Main(Option opt) : base(opt) { }
protected override Task Core() protected override Task Core()
{ {
unsafe { unsafe {

View File

@ -1,6 +1,5 @@
namespace Dot.Pwd; namespace Dot.Pwd;
[Verb("pwd", HelpText = nameof(Str.RandomPasswordGenerator), ResourceType = typeof(Str))]
public class Option : OptionBase public class Option : OptionBase
{ {
[Flags] [Flags]
@ -12,10 +11,15 @@ public class Option : OptionBase
, SpecialCharacter = 0b1000 , SpecialCharacter = 0b1000
} }
[Value(1, Required = true, HelpText = nameof(Str.PwdLength), ResourceType = typeof(Str))]
[CommandArgument(1, "<password length>")]
[Description(nameof(Str.PwdLength))]
[Localization(typeof(Str))]
public int Length { get; set; } public int Length { get; set; }
[Value(0, Required = true, HelpText = nameof(Str.PwdGenerateTypes), ResourceType = typeof(Str))] [CommandArgument(0, "<generate type>")]
[Description(nameof(Str.PwdGenerateTypes))]
[Localization(typeof(Str))]
public GenerateTypes Type { get; set; } public GenerateTypes Type { get; set; }
} }

View File

@ -2,10 +2,10 @@ using NSExt.Extensions;
namespace Dot.RmBlank; namespace Dot.RmBlank;
[Description(nameof(Str.RemoveTrailingWhiteSpaces))]
[Localization(typeof(Str))]
public sealed class Main : FilesTool<Option> public sealed class Main : FilesTool<Option>
{ {
public Main(Option opt) : base(opt) { }
private static int GetSpacesCnt(Stream fsr) private static int GetSpacesCnt(Stream fsr)
{ {
var trimLen = 0; var trimLen = 0;

View File

@ -1,4 +1,3 @@
namespace Dot.RmBlank; namespace Dot.RmBlank;
[Verb("trim", HelpText = nameof(Str.RemoveTrailingWhiteSpaces), ResourceType = typeof(Str))]
public class Option : DirOption { } public class Option : DirOption { }

View File

@ -1,13 +1,12 @@
namespace Dot.RmBom; namespace Dot.RmBom;
[Description(nameof(Str.TrimUtf8Bom))]
[Localization(typeof(Str))]
public sealed class Main : FilesTool<Option> public sealed class Main : FilesTool<Option>
{ {
private readonly byte[] _utf8Bom = { 0xef, 0xbb, 0xbf }; private readonly byte[] _utf8Bom = { 0xef, 0xbb, 0xbf };
public Main(Option opt) : base(opt) { }
private bool CloneFileWithoutBom(Stream fsr, ref string tempFile) private bool CloneFileWithoutBom(Stream fsr, ref string tempFile)
{ {
Span<byte> buffer = stackalloc byte[_utf8Bom.Length]; Span<byte> buffer = stackalloc byte[_utf8Bom.Length];

View File

@ -1,4 +1,3 @@
namespace Dot.RmBom; namespace Dot.RmBom;
[Verb("rbom", HelpText = nameof(Str.TrimUtf8Bom), ResourceType = typeof(Str))]
public class Option : DirOption { } public class Option : DirOption { }

View File

@ -8,6 +8,8 @@ using System.Diagnostics;
namespace Dot.Text; namespace Dot.Text;
[Description(nameof(Str.TextTool))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option> public sealed class Main : ToolBase<Option>
{ {
private ref struct Output private ref struct Output
@ -28,7 +30,6 @@ public sealed class Main : ToolBase<Option>
public ReadOnlySpan<char> UrlEncode; public ReadOnlySpan<char> UrlEncode;
} }
public Main(Option opt) : base(opt) { }
private static Output BuildOutput(string text, Encoding enc) private static Output BuildOutput(string text, Encoding enc)
{ {
@ -107,7 +108,11 @@ html-decode: {o.HtmlDecode}
#endif #endif
} }
#if NET7_0_WINDOWS
protected override async Task Core() protected override async Task Core()
#else
protected override Task Core()
#endif
{ {
#if NET7_0_WINDOWS #if NET7_0_WINDOWS
if (Opt.Text.NullOrEmpty()) Opt.Text = await ClipboardService.GetTextAsync(); if (Opt.Text.NullOrEmpty()) Opt.Text = await ClipboardService.GetTextAsync();
@ -116,5 +121,8 @@ html-decode: {o.HtmlDecode}
ParseAndShow(Opt.Text); ParseAndShow(Opt.Text);
#if !NET7_0_WINDOWS
return Task.CompletedTask;
#endif
} }
} }

View File

@ -1,8 +1,9 @@
namespace Dot.Text; namespace Dot.Text;
[Verb("text", HelpText = nameof(Str.TextTool), ResourceType = typeof(Str))]
public class Option : OptionBase public class Option : OptionBase
{ {
[Value(0, HelpText = nameof(Str.TextTobeProcessed), ResourceType = typeof(Str))] [CommandArgument(0, "[input text]")]
[Description(nameof(Str.TextTobeProcessed))]
[Localization(typeof(Str))]
public string Text { get; set; } public string Text { get; set; }
} }

View File

@ -2,6 +2,8 @@ using System.Net.Sockets;
namespace Dot.Time; namespace Dot.Time;
[Description(nameof(Str.TimeTool))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option> public sealed class Main : ToolBase<Option>
{ {
private const int _MAX_DEGREE_OF_PARALLELISM = 10; private const int _MAX_DEGREE_OF_PARALLELISM = 10;
@ -31,9 +33,6 @@ public sealed class Main : ToolBase<Option>
private int _successCnt; private int _successCnt;
public Main(Option opt) : base(opt) { }
private TimeSpan GetNtpOffset(string server) private TimeSpan GetNtpOffset(string server)
{ {
Span<byte> ntpData = stackalloc byte[48]; Span<byte> ntpData = stackalloc byte[48];

View File

@ -1,11 +1,17 @@
namespace Dot.Time; namespace Dot.Time;
[Verb("time", HelpText = nameof(Str.TimeTool), ResourceType = typeof(Str))]
public class Option : OptionBase public class Option : OptionBase
{ {
[Option('s', "sync", HelpText = nameof(Str.SyncToLocalTime), Default = false, ResourceType = typeof(Str))] [CommandOption("-s|--sync")]
[Description(nameof(Str.SyncToLocalTime))]
[Localization(typeof(Str))]
[DefaultValue(false)]
public bool Sync { get; set; } public bool Sync { get; set; }
[Option('t', "timeout", HelpText = nameof(Str.TimeoutMillSecs), Default = 2000, ResourceType = typeof(Str))]
[CommandOption("-t|--timeout")]
[Description(nameof(Str.TimeoutMillSecs))]
[Localization(typeof(Str))]
[DefaultValue(2000)]
public int Timeout { get; set; } public int Timeout { get; set; }
} }

View File

@ -1,4 +1,3 @@
using System.ComponentModel;
using NSExt.Extensions; using NSExt.Extensions;
using Spectre.Console.Rendering; using Spectre.Console.Rendering;

View File

@ -1,9 +1,9 @@
namespace Dot.ToLf; namespace Dot.ToLf;
[Description(nameof(Str.ConvertEndOfLineToLF))]
[Localization(typeof(Str))]
public sealed class Main : FilesTool<Option> public sealed class Main : FilesTool<Option>
{ {
public Main(Option opt) : base(opt) { }
protected override async ValueTask FileHandle(string file, CancellationToken _) protected override async ValueTask FileHandle(string file, CancellationToken _)
{ {
ShowMessage(1, 0, 0); ShowMessage(1, 0, 0);

View File

@ -1,4 +1,3 @@
namespace Dot.ToLf; namespace Dot.ToLf;
[Verb("tolf", HelpText = nameof(Str.ConvertEndOfLineToLF), ResourceType = typeof(Str))]
public class Option : DirOption { } public class Option : DirOption { }

View File

@ -1,55 +1,15 @@
namespace Dot; namespace Dot;
public abstract class ToolBase<TOption> : ITool where TOption : OptionBase public abstract class ToolBase<TOption> : Command<TOption> where TOption : OptionBase
{ {
// ReSharper disable once StaticMemberInGenericType protected TOption Opt { get; set; }
private static SpinLock _spinlock;
protected TOption Opt { get; }
protected ToolBase(TOption opt)
{
Opt = opt;
}
protected static void ConcurrentWrite(int x, int y, string text)
{
var lockTaken = false;
try {
_spinlock.Enter(ref lockTaken);
Console.SetCursorPosition(x, y);
Console.Write(text);
}
finally {
if (lockTaken) _spinlock.Exit(false);
}
}
protected abstract Task Core(); protected abstract Task Core();
public override int Execute(CommandContext context, TOption option)
protected static Task LoadingAnimate(int x, int y, out CancellationTokenSource cts)
{ {
char[] animateChars = { '-', '\\', '|', '/' }; Opt = option;
long counter = 0; Run().Wait();
return 0;
cts = new CancellationTokenSource();
var cancelToken = cts.Token;
return Task.Run(async () => {
for (;;) {
if (cancelToken.IsCancellationRequested) {
ConcurrentWrite(x, y, @" ");
return;
}
ConcurrentWrite(x, y, animateChars[counter++ % 4].ToString());
await Task.Delay(100);
}
});
} }
public virtual async Task Run() public virtual async Task Run()

View File

@ -1,26 +1,24 @@
using Dot.RmBom;
namespace Dot; namespace Dot;
public static class ToolsFactory public static class ToolsFactory
{ {
public static ITool Create(IOption option) // public static ITool Create(IOption option)
{ // {
return option switch { // return option switch {
Option o => new Main(o) // Option o => new Main(o)
, ToLf.Option o => new ToLf.Main(o) // , ToLf.Option o => new ToLf.Main(o)
, RmBlank.Option o => new RmBlank.Main(o) // , RmBlank.Option o => new RmBlank.Main(o)
, Pwd.Option o => new Pwd.Main(o) // , Pwd.Option o => new Pwd.Main(o)
, Text.Option o => new Text.Main(o) // , Text.Option o => new Text.Main(o)
, Guid.Option o => new Guid.Main(o) // , Guid.Option o => new Guid.Main(o)
, Time.Option o => new Time.Main(o) // , Time.Option o => new Time.Main(o)
#if NET7_0_WINDOWS // #if NET7_0_WINDOWS
, Color.Option o => new Color.Main(o) // , Color.Option o => new Color.Main(o)
#endif // #endif
, IP.Option o => new IP.Main(o) // , IP.Option o => new IP.Main(o)
, Git.Option o => new Git.Main(o) // // , Git.Option o => new Git.Main(o)
, Json.Option o => new Json.Main(o) // , Json.Option o => new Json.Main(o)
, _ => throw new ArgumentOutOfRangeException(nameof(option)) // , _ => throw new ArgumentOutOfRangeException(nameof(option))
}; // };
} // }
} }

View File

@ -5,13 +5,8 @@
<UseWindowsForms Condition="'$(TargetFramework)' == 'net7.0-windows'">true</UseWindowsForms> <UseWindowsForms Condition="'$(TargetFramework)' == 'net7.0-windows'">true</UseWindowsForms>
<ImplicitUsings>enable</ImplicitUsings> <ImplicitUsings>enable</ImplicitUsings>
<RootNamespace>Dot</RootNamespace> <RootNamespace>Dot</RootNamespace>
<AssemblyName>dot</AssemblyName> <GenerateAssemblyInfo>false</GenerateAssemblyInfo>
<Version>1.1.5</Version> <NoWarn>CA1416;</NoWarn>
<Authors>nsnail</Authors>
<Copyright>Copyright (c) 2022 nsnail</Copyright>
<RepositoryUrl>https://github.com/nsnail/dot.git</RepositoryUrl>
<RepositoryType>git</RepositoryType>
<AssemblyTitle>功能全面的实用工具 - 程序员的瑞士军刀</AssemblyTitle>
</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>
@ -23,8 +18,6 @@
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="CommandLineParser" Version="2.9.1"/>
<PackageReference Include="NSExt" Version="1.0.8"/>
<PackageReference Include="Spectre.Console" Version="0.45.1-preview.0.46"/> <PackageReference Include="Spectre.Console" Version="0.45.1-preview.0.46"/>
<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>
@ -34,5 +27,14 @@
<LastGenOutput>Str.Designer.cs</LastGenOutput> <LastGenOutput>Str.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
</ItemGroup> </ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\..\..\ForkedGitReps\ns-ext\src\NSExt.csproj"/>
<ProjectReference Include="..\..\..\..\..\ForkedGitReps\spectre.console\src\Spectre.Console.Cli\Spectre.Console.Cli.csproj"/>
</ItemGroup>
<ItemGroup>
<Reference Include="Spectre.Console">
<HintPath>..\..\..\..\..\ForkedGitReps\spectre.console\src\Spectre.Console\bin\Debug\net6.0\Spectre.Console.dll</HintPath>
</Reference>
</ItemGroup>
<Import Project="../GenerateResx.targets"/> <Import Project="../GenerateResx.targets"/>
</Project> </Project>

View File

@ -2,7 +2,23 @@
"solution": "dot.sln", "solution": "dot.sln",
"solutionFolder": null, "solutionFolder": null,
"mappings": { "mappings": {
"NSExt": "../../../../ForkedGitReps/ns-ext/src/NSExt.csproj" "NSExt": "../../../../ForkedGitReps/ns-ext/src/NSExt.csproj",
"Spectre.Console.Cli": "../../../../ForkedGitReps/spectre.console/src/Spectre.Console.Cli/Spectre.Console.Cli.csproj"
}, },
"restore": [
{
"name": "dot",
"packages": [
{
"packageName": "NSExt",
"version": "1.0.8"
},
{
"packageName": "Spectre.Console.Cli",
"version": "0.45.1-preview.0.46"
}
]
}
],
"removeProjects": true "removeProjects": true
} }