This commit is contained in:
nsnail 2022-12-13 11:20:53 +08:00
parent 6693a66b30
commit 750545c2d0
43 changed files with 179 additions and 109 deletions

View File

@ -6,7 +6,8 @@ Cross-platform, all-around utility set with a beautiful character interface-the
### Brief introduction
The dot is the one based on the one. NET 7, a cross-platform command-line tool, integrates more than 10 utilities that program developers often use in their daily work, and is constantly increasing.
The dot is the one based on the one. NET 7, a cross-platform command-line tool, integrates more than 10 utilities that
program developers often use in their daily work, and is constantly increasing.
```
USAGE:
@ -33,8 +34,6 @@ COMMANDS:
```
### Some functional examples
- ##### Git batch management
@ -56,7 +55,10 @@ dot git -a "config --get http.proxy" d:\repos
![20221212213957](./assets/snapshots/20221212213957.png)
- ##### High-precision time-clock synchronization
Supports parallel requests from multiple NTP clock servers, while removing the network communication duration to set the precise synchronization of the native clocks with the NTP standard time:
Supports parallel requests from multiple NTP clock servers, while removing the network communication duration to set the
precise synchronization of the native clocks with the NTP standard time:
```
dot time -k
```
@ -64,25 +66,29 @@ dot time -k
![20221212214514](./assets/snapshots/20221212214514.png)
- ##### Text codec
Copy you need to view various codec text in the clipboard, and then enter the following command to view
```
dot text
```
![20221212214904](./assets/snapshots/20221212214904.png)
- ##### Multi-threading download tool
Support setting the block size, number of threads to replace the single thread wget tool:
```
dot get https://github.com/nsnail/dot/releases/download/v1.1.1/dot-v1.1.1-win-x64.7z
```
![20221212215259](./assets/snapshots/20221212215259.png)
- ##### Remove the blank at the end of the file
Remove excess spaces and line breaks in the tail of all files in the specified directory:
```
dot trim d:\repos
```

View File

@ -32,8 +32,6 @@ COMMANDS:
```
### 部分功能示例
- ##### Git批量管理
@ -55,7 +53,9 @@ dot git -a "config --get http.proxy" d:\repos
![20221212213957](./assets/snapshots/20221212213957.png)
- ##### 高精度时钟同步
支持多个NTP时钟服务器并行请求同时除去网络通信时长以设置本机时钟与NTP标准时间精确同步
```
dot time -k
```
@ -63,25 +63,29 @@ dot time -k
![20221212214514](./assets/snapshots/20221212214514.png)
- ##### 文本编解码
复制你需要查看各种编解码的文本在剪贴板中,然后输入如下命令,即可查看
```
dot text
```
![20221212214904](./assets/snapshots/20221212214904.png)
- ##### 多线程下载工具
支持设置分块大小线程数量用以替代单线程的wget工具
```
dot get https://github.com/nsnail/dot/releases/download/v1.1.1/dot-v1.1.1-win-x64.7z
```
![20221212215259](./assets/snapshots/20221212215259.png)
- ##### 移除文件末尾空白
移除指定目录下所有文件尾部多余的空格和换行符:
```
dot trim d:\repos
```

View File

@ -1,9 +1,11 @@
// ReSharper disable ClassNeverInstantiated.Global
#if NET7_0_WINDOWS
namespace Dot.Color;
[Description(nameof(Str.ScreenPixelTool))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option>
internal sealed class Main : ToolBase<Option>
{
protected override Task Core()

View File

@ -1,10 +1,12 @@
// ReSharper disable ClassNeverInstantiated.Global
#if NET7_0_WINDOWS
using System.Diagnostics;
using System.Runtime.InteropServices;
namespace Dot.Color;
public class MouseHook : IDisposable
internal class MouseHook : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
private struct Msllhookstruct
@ -18,6 +20,7 @@ public class MouseHook : IDisposable
}
// ReSharper disable once EventNeverSubscribedTo.Global
public event MouseEventHandler MouseEvent = delegate { };
private const int _WH_MOUSE_LL = 14;
private const int _WM_LBUTTONDOWN = 0x0201;

View File

@ -1,3 +1,5 @@
// ReSharper disable ClassNeverInstantiated.Global
namespace Dot.Color;
public class Option : OptionBase { }
internal class Option : OptionBase { }

View File

@ -4,7 +4,7 @@ using Size = System.Drawing.Size;
namespace Dot.Color;
public class WinInfo : Form
internal class WinInfo : Form
{
private const int _WINDOW_SIZE = 480; //窗口大小
private const int _ZOOM_RATE = 16; //缩放倍率

View File

@ -3,7 +3,7 @@ using TextCopy;
namespace Dot.Color;
public class WinMain : Form
internal class WinMain : Form
{
private readonly Bitmap _bmp;
private bool _disposed;

View File

@ -1,7 +1,7 @@
namespace Dot;
// ReSharper disable once UnusedType.Global
public class CsxEditor
internal class CsxEditor
{
// ReSharper disable once UnusedMember.Local
#pragma warning disable CA1822

View File

@ -1,6 +1,8 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Dot;
public class DirOption : OptionBase
internal class DirOption : OptionBase
{
[CommandOption("-e|--exclude")]
[Description(nameof(Str.ExcludePathRegexes))]

View File

@ -4,11 +4,13 @@ using Panel = Spectre.Console.Panel;
namespace Dot;
public abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : DirOption
internal abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : DirOption
{
private int _breakCnt; //跳过文件数
private ProgressTask _childTask; //子任务进度
private int _excludeCnt; //排除文件数
// ReSharper disable once StaticMemberInGenericType
private static readonly object _lock = new(); //线程锁
private int _readCnt; //读取文件数
private int _totalCnt; //总文件数
@ -16,6 +18,7 @@ public abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : Dir
private readonly ConcurrentDictionary<string, int> _writeStats = new(); //写入统计:后缀,数量
// ReSharper disable once ReturnTypeCanBeEnumerable.Local
private string[] EnumerateFiles(string path, string searchPattern, out int excludeCnt)
{
var exCnt = 0;
@ -76,7 +79,7 @@ public abstract class FilesTool<TOption> : ToolBase<TOption> where TOption : Dir
}
protected FileStream CreateTempFile(out string file)
protected static FileStream CreateTempFile(out string file)
{
file = Path.Combine(Path.GetTempPath(), $"{System.Guid.NewGuid()}.tmp");
return OpenFileStream(file, FileMode.OpenOrCreate, FileAccess.Write);

View File

@ -1,3 +1,5 @@
// ReSharper disable ClassNeverInstantiated.Global
using System.Net.Http.Headers;
using System.Text.RegularExpressions;
using NSExt.Extensions;
@ -6,7 +8,7 @@ namespace Dot.Get;
[Description(nameof(Str.DownloadTool))]
[Localization(typeof(Str))]
public partial class Main : ToolBase<Option>
internal partial class Main : ToolBase<Option>
{
private const string _PART = "part";

View File

@ -1,6 +1,9 @@
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Dot.Get;
public class Option : OptionBase
internal class Option : OptionBase
{
[CommandOption("-b|--buffer-size")]
[Description(nameof(Str.BufferSize))]

View File

@ -1,3 +1,5 @@
// ReSharper disable ClassNeverInstantiated.Global
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
@ -7,7 +9,7 @@ namespace Dot.Git;
[Description(nameof(Str.GitTool))]
[Localization(typeof(Str))]
public class Main : ToolBase<Option>
internal class Main : ToolBase<Option>
{
private Encoding _gitOutputEnc; //git command rsp 编码
private ConcurrentDictionary<string, StringBuilder> _repoRsp; //仓库信息容器
@ -43,7 +45,7 @@ public class Main : ToolBase<Option>
p.ErrorDataReceived += ExecRspReceived;
p.BeginOutputReadLine();
p.BeginErrorReadLine();
await p.WaitForExitAsync();
await p.WaitForExitAsync(CancellationToken.None);
if (p.ExitCode == 0) {
payload.Value.State.Status(TaskStatusColumn.Statues.Succeed);

View File

@ -1,6 +1,9 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
// ReSharper disable ClassNeverInstantiated.Global
namespace Dot.Git;
public class Option : OptionBase
internal class Option : OptionBase
{
[CommandOption("-a|--args")]
[Description(nameof(Str.GitArgs))]

View File

@ -1,12 +1,7 @@
namespace Dot.Git;
public static class ProgressTaskStateExtensions
internal static class ProgressTaskStateExtensions
{
public static TaskStatusColumn.Statues Status(this ProgressTaskState me)
{
return me.Get<TaskStatusColumn.Statues>(nameof(TaskStatusColumn));
}
public static void Status(this ProgressTaskState me, TaskStatusColumn.Statues value)
{
me.Update<TaskStatusColumn.Statues>(nameof(TaskStatusColumn), _ => value);

View File

@ -1,13 +1,17 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
using NSExt.Extensions;
using Spectre.Console.Rendering;
namespace Dot.Git;
public class TaskStatusColumn : ProgressColumn
internal class TaskStatusColumn : ProgressColumn
{
public enum Statues : byte
{
[Description($"[gray]{nameof(Ready)}[/]")]
// ReSharper disable once UnusedMember.Global
Ready
, [Description($"[yellow]{nameof(Executing)}[/]")]

View File

@ -1,3 +1,6 @@
// ReSharper disable ClassNeverInstantiated.Global
#if NET7_0_WINDOWS
using TextCopy;
#endif
@ -6,7 +9,7 @@ namespace Dot.Guid;
[Description(nameof(Str.GuidTool))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option>
internal sealed class Main : ToolBase<Option>
{
protected override Task Core()
{

View File

@ -1,10 +1,13 @@
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Dot.Guid;
public class Option : OptionBase
internal class Option : OptionBase
{
[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; }
}

View File

@ -1,3 +1,5 @@
// ReSharper disable ClassNeverInstantiated.Global
using System.Net.NetworkInformation;
using System.Net.Sockets;
@ -5,7 +7,7 @@ namespace Dot.IP;
[Description(nameof(Str.Ip))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option>
internal sealed class Main : ToolBase<Option>
{
protected override async Task Core()

View File

@ -1,3 +1,5 @@
// ReSharper disable ClassNeverInstantiated.Global
namespace Dot.IP;
public class Option : OptionBase { }
internal class Option : OptionBase { }

View File

@ -1,3 +1,5 @@
// ReSharper disable ClassNeverInstantiated.Global
using System.Text.Json;
using NSExt.Extensions;
#if NET7_0_WINDOWS
@ -9,7 +11,7 @@ namespace Dot.Json;
[Description(nameof(Str.Json))]
[Localization(typeof(Str))]
public class Main : ToolBase<Option>
internal class Main : ToolBase<Option>
{
private object _inputObj;
@ -43,7 +45,7 @@ public class Main : ToolBase<Option>
var inputText = Opt.InputText;
#if NET7_0_WINDOWS
if (inputText.NullOrWhiteSpace()) inputText = ClipboardService.GetText();
if (inputText.NullOrWhiteSpace()) inputText = await ClipboardService.GetTextAsync();
#endif
if (inputText.NullOrWhiteSpace()) throw new ArgumentException(Str.InputTextIsEmpty);

View File

@ -1,6 +1,9 @@
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Dot.Json;
public class Option : OptionBase
internal class Option : OptionBase
{
[CommandOption("-c|--compress")]
[Description(nameof(Str.CompressJson))]

View File

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

View File

@ -1,10 +1,12 @@
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Dot;
public abstract class OptionBase : CommandSettings, IOption
internal abstract class OptionBase : CommandSettings, IOption
{
[CommandOption("-k|--keep--session")]
[Description(nameof(Str.KeepSession))]
[Localization(typeof(Str))]
[DefaultValue(false)]
public virtual bool KeepSession { get; set; }
public bool KeepSession { get; set; }
}

View File

@ -1,3 +1,5 @@
// ReSharper disable ClassNeverInstantiated.Global
using NSExt.Extensions;
#if NET7_0_WINDOWS
using TextCopy;
@ -8,7 +10,7 @@ namespace Dot.Pwd;
[Description(nameof(Str.RandomPasswordGenerator))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option>
internal sealed class Main : ToolBase<Option>
{
private readonly char[][] _charTable = {
"0123456789".ToCharArray() //

View File

@ -1,6 +1,9 @@
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Dot.Pwd;
public class Option : OptionBase
internal class Option : OptionBase
{
[Flags]
public enum GenerateTypes

View File

@ -1,8 +1,11 @@
// ReSharper disable ClassNeverInstantiated.Global
namespace Dot.Rbom;
[Description(nameof(Str.TrimUtf8Bom))]
[Localization(typeof(Str))]
public sealed class Main : FilesTool<Option>
internal sealed class Main : FilesTool<Option>
{
private readonly byte[] _utf8Bom = { 0xef, 0xbb, 0xbf };

View File

@ -1,3 +1,6 @@
// ReSharper disable ClassNeverInstantiated.Global
namespace Dot.Rbom;
public class Option : DirOption { }
internal class Option : DirOption { }

View File

@ -1,3 +1,6 @@
// ReSharper disable ClassNeverInstantiated.Global
using System.Security.Cryptography;
using System.Text;
using NSExt.Extensions;
@ -10,7 +13,7 @@ namespace Dot.Text;
[Description(nameof(Str.TextTool))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option>
internal sealed class Main : ToolBase<Option>
{
private ref struct Output
{

View File

@ -1,6 +1,9 @@
// ReSharper disable ClassNeverInstantiated.Global
namespace Dot.Text;
public class Option : OptionBase
internal class Option : OptionBase
{
[CommandArgument(0, "[input text]")]
[Description(nameof(Str.TextTobeProcessed))]

View File

@ -1,10 +1,13 @@
// ReSharper disable ClassNeverInstantiated.Global
using System.Net.Sockets;
namespace Dot.Time;
[Description(nameof(Str.TimeTool))]
[Localization(typeof(Str))]
public sealed class Main : ToolBase<Option>
internal sealed class Main : ToolBase<Option>
{
private const int _MAX_DEGREE_OF_PARALLELISM = 10;
private const int _NTP_PORT = 123;

View File

@ -1,6 +1,9 @@
// ReSharper disable ClassNeverInstantiated.Global
// ReSharper disable UnusedAutoPropertyAccessor.Global
namespace Dot.Time;
public class Option : OptionBase
internal class Option : OptionBase
{
[CommandOption("-s|--sync")]
[Description(nameof(Str.SyncToLocalTime))]

View File

@ -1,6 +1,6 @@
namespace Dot.Time;
public static class ProgressTaskStateExtensions
internal static class ProgressTaskStateExtensions
{
public static TimeSpan Result(this ProgressTaskState me)
{

View File

@ -1,8 +1,11 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
using Spectre.Console.Rendering;
namespace Dot.Time;
public class TaskResultColumn : ProgressColumn
internal class TaskResultColumn : ProgressColumn
{
/// <summary>
/// Gets or sets the alignment of the task description.

View File

@ -1,13 +1,18 @@
// ReSharper disable MemberCanBePrivate.Global
// ReSharper disable AutoPropertyCanBeMadeGetOnly.Global
using NSExt.Extensions;
using Spectre.Console.Rendering;
namespace Dot.Time;
public class TaskStatusColumn : ProgressColumn
internal class TaskStatusColumn : ProgressColumn
{
public enum Statues : byte
{
[Description($"[gray]{nameof(Ready)}[/]")]
// ReSharper disable once UnusedMember.Global
Ready
, [Description($"[yellow]{nameof(Connecting)}[/]")]

View File

@ -1,8 +1,11 @@
// ReSharper disable ClassNeverInstantiated.Global
namespace Dot.ToLf;
[Description(nameof(Str.ConvertEndOfLineToLF))]
[Localization(typeof(Str))]
public sealed class Main : FilesTool<Option>
internal sealed class Main : FilesTool<Option>
{
protected override async ValueTask FileHandle(string file, CancellationToken _)
{
@ -11,6 +14,7 @@ public sealed class Main : FilesTool<Option>
var hasWrote = false;
var isBin = false;
string tmpFile;
// ReSharper disable once TooWideLocalVariableScope
int data;
await using (var fsr = OpenFileStream(file, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) {

View File

@ -1,3 +1,6 @@
// ReSharper disable ClassNeverInstantiated.Global
namespace Dot.ToLf;
public class Option : DirOption { }
internal class Option : DirOption { }

View File

@ -1,17 +1,10 @@
namespace Dot;
public abstract class ToolBase<TOption> : Command<TOption> where TOption : OptionBase
internal abstract class ToolBase<TOption> : Command<TOption> where TOption : OptionBase
{
protected TOption Opt { get; private set; }
protected abstract Task Core();
public override int Execute(CommandContext context, TOption option)
{
Opt = option;
Run().Wait();
return 0;
}
protected virtual async Task Run()
{
await Core();
@ -20,4 +13,11 @@ public abstract class ToolBase<TOption> : Command<TOption> where TOption : Optio
AnsiConsole.Console.Input.ReadKey(true);
}
}
public override int Execute(CommandContext context, TOption option)
{
Opt = option;
Run().Wait();
return 0;
}
}

View File

@ -1,24 +0,0 @@
namespace Dot;
public static class ToolsFactory
{
// public static ITool Create(IOption option)
// {
// return option switch {
// 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)
// , Time.Option o => new Time.Main(o)
// #if NET7_0_WINDOWS
// , Color.Option o => new Color.Main(o)
// #endif
// , IP.Option o => new IP.Main(o)
// // , Git.Option o => new Git.Main(o)
// , Json.Option o => new Json.Main(o)
// , _ => throw new ArgumentOutOfRangeException(nameof(option))
// };
// }
}

View File

@ -1,11 +1,13 @@
using Dot.RmBlank;
// ReSharper disable ClassNeverInstantiated.Global
using NSExt.Extensions;
namespace Dot.Trim;
[Description(nameof(Str.RemoveTrailingWhiteSpaces))]
[Localization(typeof(Str))]
public sealed class Main : FilesTool<Option>
internal sealed class Main : FilesTool<Option>
{
private static int GetSpacesCnt(Stream fsr)
{

View File

@ -1,3 +1,6 @@
namespace Dot.RmBlank;
// ReSharper disable ClassNeverInstantiated.Global
public class Option : DirOption { }
namespace Dot.Trim;
internal class Option : DirOption { }

View File

@ -1,3 +1,6 @@
// ReSharper disable UnusedMember.Global
// ReSharper disable UnusedMethodReturnValue.Global
using System.Runtime.InteropServices;
namespace Dot;