CodingTookit
CodingTookit\src\DeploymentScript\Program.cs
using System.Diagnostics;
using System.Reflection;
using System.Security.Principal;
using System.Text;
class Program
{
static void Main()
{
if (!IsRunningAsAdmin())
{
RestartAsAdmin();
return;
}
Console.WriteLine("=== 管理员权限已获取 ===");
Dictionary<string, string> dictionary = new Dictionary<string, string>
{
{ "Pron", "Pronunciation" },
{ "code2md", "Code2md" },
{ "md2code", "Md2code" },
{ "backup", "CopyFileV2" },
{ "qq", "Warp" },
{ "bing", "Bing" },
};
foreach (var key in dictionary)
{
string scriptName = key.Key;
string project = key.Value;
string scriptPath = GetScriptPath(scriptName);
try
{
bool isPublishSuccess = PublishProgram(project, scriptName);
if (!isPublishSuccess)
{
continue;
}
string targetFramework = GetTargetFramework(project);
string content = GetCode2mdScriptContent(project, scriptName, targetFramework);
File.WriteAllText(scriptPath, content);
System.Console.WriteLine($"已成功创建 {scriptPath} 文件");
}
catch (Exception ex)
{
System.Console.WriteLine($"创建 {scriptPath} 文件失败: {ex.Message}");
continue;
}
System.Console.WriteLine("按回车键继续...");
System.Console.ReadKey();
}
}
private static string GetScriptPath(string scriptName)
{
string platform = GetPlatform();
if (platform.Equals("win-x64", StringComparison.OrdinalIgnoreCase))
{
return Path.Combine("C:\\Windows", $"{scriptName.ToLower()}.bat");
}
else
{
throw new NotSupportedException($"不支持的操作系统: {platform}");
}
}
private static string GetPlatform()
{
string platform = Environment.OSVersion.Platform.ToString();
if (platform.Equals("Win32NT", StringComparison.OrdinalIgnoreCase))
{
return "win-x64";
}
throw new NotSupportedException($"不支持的操作系统: {platform}");
}
public static string GetTargetFramework(string projectName)
{
string platform = GetPlatform();
if (platform.Equals("win-x64", StringComparison.OrdinalIgnoreCase))
{
string csprojPath = Path.Combine(@"D:\CodingTookit\src", projectName, $"{projectName}.csproj");
string targetFramework = File.ReadAllLines(csprojPath, Encoding.UTF8).FirstOrDefault(line => line.Contains("<TargetFramework>"))?.Trim().Replace("<TargetFramework>", "").Replace("</TargetFramework>", "") ?? throw new Exception("未找到 TargetFramework");
return targetFramework;
}
else
{
throw new NotSupportedException("不支持的操作系统");
}
}
private static string GetCode2mdScriptContent(string projectName, string scriptName, string targetFramework)
{
string platform = GetPlatform();
if (platform.Equals("win-x64", StringComparison.OrdinalIgnoreCase))
{
Path.Combine("");
return $@"@echo off
set ""scriptPath=%cd%""
D: && cd D:\CodingTookit\src\{projectName}\bin\Release\{targetFramework}\{platform}\publish\ && D:\CodingTookit\src\{projectName}\bin\Release\{targetFramework}\{platform}\publish\{scriptName}.exe ""%scriptPath%""";
}
else
{
throw new NotSupportedException($"不支持的操作系统: {platform}");
}
}
private static bool PublishProgram(string projectName, string scriptName)
{
string workDir = string.Empty;
string platform = GetPlatform();
if (platform.Equals("win-x64", StringComparison.OrdinalIgnoreCase))
{
workDir = @"D:\CodingTookit";
}
else
{
throw new NotSupportedException($"不支持的操作系统: {platform}");
}
var publishStartInfo = new ProcessStartInfo
{
UseShellExecute = false,
WorkingDirectory = workDir,
FileName = "dotnet",
Arguments = @$"publish .\src\{projectName}\{projectName}.csproj -c Release -r {platform} --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true /p:AssemblyName={scriptName}",
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
};
using (var publishProcess = Process.Start(publishStartInfo))
{
var stdout = publishProcess!.StandardOutput.ReadToEnd();
var stderr = publishProcess.StandardError.ReadToEnd();
publishProcess.WaitForExit();
if (publishProcess.ExitCode != 0)
{
Console.WriteLine($"发布失败: {stderr}");
return false;
}
Console.WriteLine($"发布成功: {projectName}");
Console.WriteLine(stdout);
}
return true;
}
private static bool OverwriteCheck(string scirptPath)
{
if (File.Exists(scirptPath))
{
System.Console.Write($"已有 {scirptPath} 文件,是否覆盖? (y/n) : ");
string? v = System.Console.ReadLine();
if (v?.ToLower() != "y")
{
System.Console.WriteLine("已取消操作");
return false;
}
}
return true;
}
static bool IsRunningAsAdmin()
{
#pragma warning disable CA1416 // Validate platform compatibility
using var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
#pragma warning restore CA1416 // Validate platform compatibility
}
static void RestartAsAdmin()
{
var startInfo = new ProcessStartInfo
{
UseShellExecute = true,
WorkingDirectory = Environment.CurrentDirectory,
FileName = Environment.ProcessPath,
Arguments = string.Join(" ", Environment.GetCommandLineArgs().Skip(1)),
};
startInfo.Verb = "runas";
try
{
Process.Start(startInfo);
}
catch (Exception ex)
{
Console.WriteLine($"无法获取管理员权限: {ex.Message}");
}
}
}
CodingTookit\src\DeploymentScript\DeploymentScript.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<!-- 添加 AssemblyMetadata 属性 -->
<ItemGroup>
<AssemblyMetadata Include="TargetFramework">
<Value>$(TargetFramework)</Value>
</AssemblyMetadata>
</ItemGroup>
</Project>
CodingTookit\run.bat
chcp 65001 >nul
set "scriptPath=%cd%"
@REM dotnet run --project ./src/Code2md/Code2md.csproj -- "%scriptPath%"
@REM dotnet run --project ./src/Code2mdV2/Code2mdV2.csproj -- "%scriptPath%"
@REM dotnet run --project ./src/LastestSqlFinder/LastestSqlFinder.csproj -- "%scriptPath%"
@REM dotnet run --project ./src/SqlServerRunner/SqlServerRunner.csproj -- "%scriptPath%"
@REM dotnet run --project ./src/Md2code/Md2code.csproj -- "%scriptPath%"
@REM dotnet run --project D:\CodingTookit\consoletests\MarkdownLineTest\MarkdownLineTest.csproj
@REM dotnet run --project ./src/LatestCode2mdFinder/LatestCode2mdFinder.csproj -- "%scriptPath%"
@REM dotnet run --project D:\CodingTookit\src\Warp\Warp.csproj -- "%scriptPath%"
@REM dotnet run --project D:\CodingTookit\src\SqlcmdRunner\SqlcmdRunner.csproj -- "%scriptPath%" --run
dotnet run --project D:\CodingTookit\src\DeploymentScript\
@REM dotnet run --project D:\CodingTookit\src\Bing\
CodingTookit\src\Pronunciation\Program.cs
using System;
using System.Windows.Forms;
namespace Pronunciation
{
internal class Program
{
[STAThread]
static void Main()
{
var clipboardText = Clipboard.GetText();
var encodedText = Uri.EscapeDataString(clipboardText);
var url = $"https://dict.youdao.com/dictvoice?type=2&audio={encodedText}";
System.Diagnostics.Process.Start(
new System.Diagnostics.ProcessStartInfo
{
FileName = "msedge",
Arguments = url,
UseShellExecute = true,
}
);
}
}
}
CodingTookit\src\Pronunciation\Pronunciation.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0-windows</TargetFramework>
<ImplicitUsings>disable</ImplicitUsings>
<Nullable>enable</Nullable>
<UseWindowsForms>true</UseWindowsForms>
<StartupObject>Pronunciation.Program</StartupObject>
</PropertyGroup>
</Project>
CodingTookit\build.bat
dotnet build
CodingTookit\CodingTookit.sln
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{827E0CD3-B72D-47B6-A68D-7590B98EB39B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Code2md", "src\Code2md\Code2md.csproj", "{CF860317-708A-4964-AB32-042D023F2315}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CopyFileV2", "src\CopyFileV2\CopyFileV2.csproj", "{6FA435BC-E305-4790-8175-F463ED91B92A}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlServerRunner", "src\SqlServerRunner\SqlServerRunner.csproj", "{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LatestSqlFinder", "src\LatestSqlFinder\LatestSqlFinder.csproj", "{F5013E74-5805-4C2E-8E60-EC697D06AD93}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Md2code", "src\Md2code\Md2code.csproj", "{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Warp", "src\Warp\Warp.csproj", "{F4F83E71-AA1C-432B-894E-2904D37BB93B}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SqlcmdRunner", "src\SqlcmdRunner\SqlcmdRunner.csproj", "{EC04A9FC-032B-40C6-9652-7796F04A9F30}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "DeploymentScript", "src\DeploymentScript\DeploymentScript.csproj", "{0CA2410F-35B9-4449-8C1D-59A986435BA0}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Bing", "src\Bing\Bing.csproj", "{C63065A9-710C-416A-9399-57A19DE9B172}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Pronunciation", "src\Pronunciation\Pronunciation.csproj", "{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CF860317-708A-4964-AB32-042D023F2315}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Debug|x64.ActiveCfg = Debug|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Debug|x64.Build.0 = Debug|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Debug|x86.ActiveCfg = Debug|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Debug|x86.Build.0 = Debug|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Release|Any CPU.Build.0 = Release|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Release|x64.ActiveCfg = Release|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Release|x64.Build.0 = Release|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Release|x86.ActiveCfg = Release|Any CPU
{CF860317-708A-4964-AB32-042D023F2315}.Release|x86.Build.0 = Release|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|x64.ActiveCfg = Debug|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|x64.Build.0 = Debug|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|x86.ActiveCfg = Debug|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Debug|x86.Build.0 = Debug|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|Any CPU.Build.0 = Release|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|x64.ActiveCfg = Release|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|x64.Build.0 = Release|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|x86.ActiveCfg = Release|Any CPU
{6FA435BC-E305-4790-8175-F463ED91B92A}.Release|x86.Build.0 = Release|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|x64.ActiveCfg = Debug|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|x64.Build.0 = Debug|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|x86.ActiveCfg = Debug|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Debug|x86.Build.0 = Debug|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|Any CPU.Build.0 = Release|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|x64.ActiveCfg = Release|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|x64.Build.0 = Release|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|x86.ActiveCfg = Release|Any CPU
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB}.Release|x86.Build.0 = Release|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|x64.ActiveCfg = Debug|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|x64.Build.0 = Debug|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|x86.ActiveCfg = Debug|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Debug|x86.Build.0 = Debug|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|Any CPU.Build.0 = Release|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|x64.ActiveCfg = Release|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|x64.Build.0 = Release|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|x86.ActiveCfg = Release|Any CPU
{F5013E74-5805-4C2E-8E60-EC697D06AD93}.Release|x86.Build.0 = Release|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|x64.ActiveCfg = Debug|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|x64.Build.0 = Debug|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|x86.ActiveCfg = Debug|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Debug|x86.Build.0 = Debug|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|Any CPU.Build.0 = Release|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|x64.ActiveCfg = Release|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|x64.Build.0 = Release|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|x86.ActiveCfg = Release|Any CPU
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63}.Release|x86.Build.0 = Release|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Debug|x64.ActiveCfg = Debug|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Debug|x64.Build.0 = Debug|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Debug|x86.ActiveCfg = Debug|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Debug|x86.Build.0 = Debug|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Release|Any CPU.Build.0 = Release|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Release|x64.ActiveCfg = Release|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Release|x64.Build.0 = Release|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Release|x86.ActiveCfg = Release|Any CPU
{F4F83E71-AA1C-432B-894E-2904D37BB93B}.Release|x86.Build.0 = Release|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Debug|x64.ActiveCfg = Debug|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Debug|x64.Build.0 = Debug|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Debug|x86.ActiveCfg = Debug|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Debug|x86.Build.0 = Debug|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Release|Any CPU.Build.0 = Release|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Release|x64.ActiveCfg = Release|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Release|x64.Build.0 = Release|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Release|x86.ActiveCfg = Release|Any CPU
{EC04A9FC-032B-40C6-9652-7796F04A9F30}.Release|x86.Build.0 = Release|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Debug|x64.ActiveCfg = Debug|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Debug|x64.Build.0 = Debug|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Debug|x86.ActiveCfg = Debug|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Debug|x86.Build.0 = Debug|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Release|Any CPU.Build.0 = Release|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Release|x64.ActiveCfg = Release|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Release|x64.Build.0 = Release|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Release|x86.ActiveCfg = Release|Any CPU
{0CA2410F-35B9-4449-8C1D-59A986435BA0}.Release|x86.Build.0 = Release|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Debug|x64.ActiveCfg = Debug|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Debug|x64.Build.0 = Debug|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Debug|x86.ActiveCfg = Debug|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Debug|x86.Build.0 = Debug|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Release|Any CPU.Build.0 = Release|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Release|x64.ActiveCfg = Release|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Release|x64.Build.0 = Release|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Release|x86.ActiveCfg = Release|Any CPU
{C63065A9-710C-416A-9399-57A19DE9B172}.Release|x86.Build.0 = Release|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Debug|x64.ActiveCfg = Debug|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Debug|x64.Build.0 = Debug|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Debug|x86.ActiveCfg = Debug|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Debug|x86.Build.0 = Debug|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Release|Any CPU.Build.0 = Release|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Release|x64.ActiveCfg = Release|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Release|x64.Build.0 = Release|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Release|x86.ActiveCfg = Release|Any CPU
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{CF860317-708A-4964-AB32-042D023F2315} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{6FA435BC-E305-4790-8175-F463ED91B92A} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{F7E3C168-FD4B-42AA-80FD-5656D472E6DB} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{F5013E74-5805-4C2E-8E60-EC697D06AD93} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{FD3EC2B3-EA2E-4D1B-A3BA-AFBD2ABAAC63} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{F4F83E71-AA1C-432B-894E-2904D37BB93B} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{EC04A9FC-032B-40C6-9652-7796F04A9F30} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{0CA2410F-35B9-4449-8C1D-59A986435BA0} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{C63065A9-710C-416A-9399-57A19DE9B172} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
{1DA9BC68-86E8-43AE-B78B-D34E4AC45398} = {827E0CD3-B72D-47B6-A68D-7590B98EB39B}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {952E0F08-889A-4D42-8C09-9A6CE65269E2}
EndGlobalSection
EndGlobal
CodingTookit\src\LatestSqlFinder\Program.cs
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
class Program
{
static async Task Main(string[] args)
{
string path = args.Length > 0 ? args[0] : Directory.GetCurrentDirectory();
var config = new Config(path);
bool hasConfig = config.CheckCmdSqlConfig();
if (!hasConfig)
{
System.Console.WriteLine("初次使用,使用默认配置文件");
}
config.LoadConfig();
var stopwatch = Stopwatch.StartNew();
var result = await FindLatestSqlFileAsync(path, config);
var tempPath = Path.Combine(@"C:\Users", Environment.UserName, @"AppData\Local\Temp");
var dstPath = FindLatestDstSqlFileAsync(tempPath);
stopwatch.Stop();
if (result == null || dstPath == null)
{
Console.WriteLine("\nNo .sql files found.");
Console.WriteLine($"\nScanned in {stopwatch.ElapsedMilliseconds}ms");
return;
}
Console.WriteLine($"\nFound latest SQL file:");
string latestSrcSqlFilePath = result.Path;
Console.WriteLine(latestSrcSqlFilePath);
string latestDstSqlFilePath = dstPath;
List<string> bottoms = ReverseReadLines(latestSrcSqlFilePath);
File.WriteAllText(latestDstSqlFilePath, string.Join(Environment.NewLine, bottoms), System.Text.Encoding.UTF8);
Console.WriteLine($"\nScanned in {stopwatch.ElapsedMilliseconds}ms");
}
public static List<string> ReverseReadLines(string filePath)
{
List<string> resultLines = new List<string>();
List<byte> currentLineBuffer = new List<byte>();
int consecutiveEmptyLines = 0;
bool foundFirstContent = false;
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
long position = fs.Length;
while (position > 0)
{
position--;
fs.Position = position;
int byteValue = fs.ReadByte();
if (byteValue == -1)
continue;
char c = (char)byteValue;
if (c == '\n')
{
currentLineBuffer.Reverse();
string line = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
currentLineBuffer.Clear();
if (!foundFirstContent)
{
if (!string.IsNullOrWhiteSpace(line))
{
foundFirstContent = true;
resultLines.Add(line);
}
}
else
{
if (string.IsNullOrWhiteSpace(line))
{
consecutiveEmptyLines++;
if (consecutiveEmptyLines >= 3)
{
break;
}
}
else
{
resultLines.Add(line);
consecutiveEmptyLines = 0;
}
}
}
else
{
currentLineBuffer.Add((byte)byteValue);
}
}
if (currentLineBuffer.Count > 0 && (foundFirstContent && consecutiveEmptyLines < 3))
{
currentLineBuffer.Reverse();
string firstLine = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
if (!string.IsNullOrWhiteSpace(firstLine))
{
resultLines.Add(firstLine);
}
}
else if (currentLineBuffer.Count > 0 && !foundFirstContent)
{
currentLineBuffer.Reverse();
string onlyLine = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
if (!string.IsNullOrWhiteSpace(onlyLine))
{
resultLines.Add(onlyLine);
}
}
}
resultLines.Reverse();
return resultLines;
}
private static string? FindLatestDstSqlFileAsync(string v)
{
string[] sqlFiles = Directory.GetFiles(v, "*.sql", SearchOption.TopDirectoryOnly);
if (sqlFiles.Length == 0)
return null;
string? latestFile = null;
DateTimeOffset latestTime = DateTimeOffset.MinValue;
foreach (var file in sqlFiles)
{
try
{
var fileInfo = new FileInfo(file);
if (fileInfo.LastWriteTimeUtc > latestTime)
{
latestTime = fileInfo.LastWriteTimeUtc;
latestFile = file;
}
}
catch { }
}
return latestFile;
}
private static async Task<SqlFileInfo?> FindLatestSqlFileAsync(string rootPath, Config config)
{
var latestFile = new ConcurrentBag<SqlFileInfo>();
var directories = new ConcurrentStack<string>();
directories.Push(rootPath);
var filesProcessed = new ConcurrentCounter();
var directoriesScanned = new ConcurrentCounter();
await Task.Run(() =>
{
Parallel.ForEach(
Partitioner.Create(1, int.MaxValue),
range =>
{
var localLatest = (DateTimeOffset?)null;
SqlFileInfo? localLatestFile = null;
while (directories.TryPop(out string? dir))
{
try
{
string[] subDirs = Array.Empty<string>();
string[] files = Array.Empty<string>();
try
{
subDirs = Directory.GetDirectories(dir);
files = Directory.GetFiles(dir, "*.sql");
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
foreach (var file in files)
{
try
{
var fileInfo = new FileInfo(file);
if (localLatest == null || fileInfo.LastWriteTimeUtc > localLatest.Value)
{
localLatest = fileInfo.LastWriteTimeUtc;
localLatestFile = new SqlFileInfo(file, fileInfo.LastWriteTimeUtc);
}
}
catch { }
}
foreach (var subDir in subDirs)
{
if (!config.ShouldExcludeDirectory(subDir))
{
directories.Push(subDir);
}
}
directoriesScanned.Increment(1);
filesProcessed.Increment(files.Length);
}
catch { }
}
if (localLatestFile != null)
{
latestFile.Add(localLatestFile);
}
}
);
});
return latestFile.OrderByDescending(f => f.LastModifiedTime).FirstOrDefault();
}
}
public class SqlFileInfo
{
public string Path { get; }
public DateTimeOffset LastModifiedTime { get; }
public SqlFileInfo(string path, DateTimeOffset lastModifiedTime)
{
Path = path;
LastModifiedTime = lastModifiedTime;
}
}
public class ConcurrentCounter
{
private long _count = 0;
public void Increment(long value = 1)
{
Interlocked.Add(ref _count, value);
}
public long Value => Interlocked.Read(ref _count);
}
CodingTookit\src\Bing\Program.cs
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
class Program
{
static async Task Main(string[] args)
{
string path = args.Length > 0 ? args[0] : Directory.GetCurrentDirectory();
var config = new Config(path);
bool hasConfig = config.CheckCmdSqlConfig();
if (!hasConfig)
{
System.Console.WriteLine("初次使用,使用默认配置文件");
}
config.LoadConfig();
var result = await FindLatestMarkdownFileAsync(path, config);
if (result == null)
{
System.Console.WriteLine("未找到任何 Markdown 文件");
return;
}
string? latestSrcMdFilePath = result?.Path;
if (latestSrcMdFilePath == null)
{
System.Console.WriteLine("未找到任何 Markdown 文件");
return;
}
List<string> bottoms = ReadTheLastFewLinesByBlankLine(latestSrcMdFilePath);
string content = string.Join(Environment.NewLine, bottoms);
Console.WriteLine("搜索的内容:");
Console.WriteLine(content);
List<string> searchEngines = new List<string>
{
"https://www.bing.com/search?q=", //
"https://chat.baidu.com/search?word=", //
"https://www.baidu.com/s?wd=", //
"https://m.quark.cn/s?q=", //
"https://www.n.cn/?q=", //
"https://metaso.cn/?q=", //
};
foreach (string engine in searchEngines)
{
string queryContentEncoded = System.Net.WebUtility.UrlEncode(content);
string searchUrl = engine + queryContentEncoded;
OpenUrl(searchUrl);
}
}
public static List<string> ReadTheLastFewLinesByBlankLine(string filePath, int blankLineCount = 3)
{
List<string> resultLines = new List<string>();
List<byte> currentLineBuffer = new List<byte>();
int consecutiveEmptyLines = 0;
bool foundFirstContent = false;
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
long position = fs.Length;
while (position > 0)
{
position--;
fs.Position = position;
int byteValue = fs.ReadByte();
if (byteValue == -1)
continue;
char c = (char)byteValue;
if (c == '\n')
{
currentLineBuffer.Reverse();
string line = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
currentLineBuffer.Clear();
if (!foundFirstContent)
{
if (!string.IsNullOrWhiteSpace(line))
{
foundFirstContent = true;
resultLines.Add(line);
}
}
else
{
if (string.IsNullOrWhiteSpace(line))
{
consecutiveEmptyLines++;
if (consecutiveEmptyLines >= blankLineCount)
{
break;
}
}
else
{
resultLines.Add(line);
consecutiveEmptyLines = 0;
}
}
}
else
{
currentLineBuffer.Add((byte)byteValue);
}
}
if (currentLineBuffer.Count > 0 && (foundFirstContent && consecutiveEmptyLines < 3))
{
currentLineBuffer.Reverse();
string firstLine = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
if (!string.IsNullOrWhiteSpace(firstLine))
{
resultLines.Add(firstLine);
}
}
else if (currentLineBuffer.Count > 0 && !foundFirstContent)
{
currentLineBuffer.Reverse();
string onlyLine = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
if (!string.IsNullOrWhiteSpace(onlyLine))
{
resultLines.Add(onlyLine);
}
}
}
resultLines.Reverse();
return resultLines;
}
private static void OpenUrl(string bing, string softWarePath = @"C:\Program Files (x86)\Microsoft\Edge\Application\msedge.exe")
{
Process.Start(
new ProcessStartInfo
{
FileName = softWarePath,
Arguments = bing,
UseShellExecute = true,
}
);
}
private static async Task<MarkdownFileInfo?> FindLatestMarkdownFileAsync(string rootPath, Config config)
{
var latestFile = new ConcurrentBag<MarkdownFileInfo>();
var directories = new ConcurrentStack<string>();
directories.Push(rootPath);
var filesProcessed = new ConcurrentCounter();
var directoriesScanned = new ConcurrentCounter();
await Task.Run(() =>
{
Parallel.ForEach(
Partitioner.Create(1, int.MaxValue),
range =>
{
var localLatest = (DateTimeOffset?)null;
MarkdownFileInfo? localLatestFile = null;
while (directories.TryPop(out string? dir))
{
try
{
string[] subDirs = Array.Empty<string>();
string[] files = Array.Empty<string>();
try
{
subDirs = Directory.GetDirectories(dir);
files = Directory.GetFiles(dir, "*.md");
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
foreach (var file in files)
{
try
{
var fileInfo = new FileInfo(file);
if (localLatest == null || fileInfo.LastWriteTimeUtc > localLatest.Value)
{
localLatest = fileInfo.LastWriteTimeUtc;
localLatestFile = new MarkdownFileInfo(file, fileInfo.LastWriteTimeUtc);
}
}
catch { }
}
foreach (var subDir in subDirs)
{
if (!config.ShouldExcludeDirectory(subDir))
{
directories.Push(subDir);
}
}
directoriesScanned.Increment(1);
filesProcessed.Increment(files.Length);
}
catch { }
}
if (localLatestFile != null)
{
latestFile.Add(localLatestFile);
}
}
);
});
return latestFile.OrderByDescending(f => f.LastModifiedTime).FirstOrDefault();
}
}
public class MarkdownFileInfo
{
public string Path { get; }
public DateTimeOffset LastModifiedTime { get; }
public MarkdownFileInfo(string path, DateTimeOffset lastModifiedTime)
{
Path = path;
LastModifiedTime = lastModifiedTime;
}
}
public class ConcurrentCounter
{
private long _count = 0;
public void Increment(long value = 1)
{
Interlocked.Add(ref _count, value);
}
public long Value => Interlocked.Read(ref _count);
}
CodingTookit\src\Bing\Config.cs
using Microsoft.Extensions.Configuration;
public class Config
{
private readonly string _srcPath;
private readonly string _configPath;
private IConfigurationRoot _configurationRoot = null!;
public List<string> ExcludeEqualDirs { get; set; } = new();
public List<string> ExcludeStartDirs { get; set; } = new();
public List<string> ExcludeEndDirs { get; set; } = new();
public Config(string srcPath)
{
_srcPath = srcPath;
_configPath = Path.Combine(srcPath, ".vscode", "bing.yaml");
}
public bool CheckCmdSqlConfig()
{
string configDir = Path.GetDirectoryName(_configPath) ?? ".vscode";
if (!Directory.Exists(configDir))
{
Directory.CreateDirectory(configDir);
}
if (!File.Exists(_configPath))
{
File.WriteAllText(_configPath, GenerateCmdSqlConfigYaml(), System.Text.Encoding.UTF8);
return false;
}
return true;
}
public void LoadConfig()
{
if (!File.Exists(_configPath))
return;
try
{
_configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_configPath, optional: true, reloadOnChange: true).Build();
ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
}
catch (Exception ex)
{
Console.WriteLine($"Warning: Could not load config file: {ex.Message}");
ExcludeEqualDirs.Clear();
ExcludeStartDirs.Clear();
ExcludeEndDirs.Clear();
}
}
public bool ShouldExcludeDirectory(string dirPath)
{
string dirName = Path.GetFileName(dirPath);
if (ExcludeEqualDirs.Contains(dirName))
return true;
if (ExcludeStartDirs.Any(prefix => dirName.StartsWith(prefix)))
return true;
if (ExcludeEndDirs.Any(suffix => dirName.EndsWith(suffix)))
return true;
return false;
}
private List<string> GetConfigList(string sectionName)
{
return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).Where(v => !string.IsNullOrEmpty(v)).ToList();
}
public static string GenerateCmdSqlConfigYaml()
{
return @"ExcludeEqualDirs:
- ""res""
- ""docs""
- ""note""
- ""config""
- ""Publish""
- "".idea""
- "".vs""
- "".vscode""
- "".git""
- ""zz_pro""
- ""zz_res""
- ""zz_zz""
- ""bin""
- ""zz_config""
- ""zz_note""
- ""zz_cache""
- ""node_modules""
- ""obj""
- ""zz_zz_publish""
- ""zz_zz_pro""
- ""Migrations""
- ""log""
- ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []";
}
}
CodingTookit\src\Bing\Bing.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
<PackageReference Include="YamlDotNet" Version="15.1.2" />
</ItemGroup>
</Project>
CodingTookit\src\LatestSqlFinder\LatestSqlFinder.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
<PackageReference Include="YamlDotNet" Version="15.1.2" />
</ItemGroup>
</Project>
CodingTookit\src\Warp\Program.cs
using System;
using System.Runtime.InteropServices;
namespace Warp
{
class Program
{
[STAThread]
static void Main(string[] args)
{
string? content = GetClipboardText();
if (content != null)
{
content = Environment.NewLine + "```" + Environment.NewLine + content + Environment.NewLine + "```" + Environment.NewLine;
Console.WriteLine(content);
string? input = System.Console.ReadLine();
if (!string.IsNullOrEmpty(input))
{
content += input;
}
SetClipboardText(content);
System.Console.WriteLine("Done");
}
else
{
Console.WriteLine("No text in clipboard or clipboard not accessible.");
}
}
static string? GetClipboardText()
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
return GetWindowsClipboardText();
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
return GetLinuxClipboardText();
}
return null;
}
static void SetClipboardText(string text)
{
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
SetWindowsClipboardText(text);
}
else if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
SetLinuxClipboardText(text);
}
}
static string? GetWindowsClipboardText()
{
if (!OpenClipboard(IntPtr.Zero))
return null;
try
{
IntPtr handle = GetClipboardData(CF_UNICODETEXT);
if (handle == IntPtr.Zero)
return null;
IntPtr ptr = GlobalLock(handle);
if (ptr == IntPtr.Zero)
return null;
try
{
return Marshal.PtrToStringUni(ptr);
}
finally
{
GlobalUnlock(handle);
}
}
finally
{
CloseClipboard();
}
}
static void SetWindowsClipboardText(string text)
{
if (!OpenClipboard(IntPtr.Zero))
return;
try
{
EmptyClipboard();
int size = (text.Length + 1) * 2;
IntPtr handle = GlobalAlloc(GMEM_FIXED, size);
if (handle == IntPtr.Zero)
return;
try
{
IntPtr ptr = GlobalLock(handle);
if (ptr == IntPtr.Zero)
{
GlobalFree(handle);
return;
}
try
{
Marshal.Copy(text.ToCharArray(), 0, ptr, text.Length);
Marshal.WriteInt16(ptr, text.Length * 2, 0);
}
finally
{
GlobalUnlock(handle);
}
SetClipboardData(CF_UNICODETEXT, handle);
}
catch
{
GlobalFree(handle);
}
}
finally
{
CloseClipboard();
}
}
const uint CF_UNICODETEXT = 13;
const uint GMEM_FIXED = 0x0000;
[DllImport("user32.dll", SetLastError = true)]
static extern bool OpenClipboard(IntPtr hWndNewOwner);
[DllImport("user32.dll", SetLastError = true)]
static extern bool CloseClipboard();
[DllImport("user32.dll", SetLastError = true)]
static extern bool EmptyClipboard();
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr SetClipboardData(uint uFormat, IntPtr hMem);
[DllImport("user32.dll", SetLastError = true)]
static extern IntPtr GetClipboardData(uint uFormat);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GlobalAlloc(uint uFlags, IntPtr dwBytes);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GlobalLock(IntPtr hMem);
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool GlobalUnlock(IntPtr hMem);
[DllImport("kernel32.dll", SetLastError = true)]
static extern IntPtr GlobalFree(IntPtr hMem);
static string? GetLinuxClipboardText()
{
string[] commands = ["xclip -selection clipboard -o", "xsel --clipboard --output"];
foreach (var cmd in commands)
{
var (stdout, _) = RunBashCommand(cmd);
if (!string.IsNullOrEmpty(stdout))
return stdout;
}
return null;
}
static void SetLinuxClipboardText(string text)
{
string[] commands = [$"printf '%s' \"{EscapeShell(text)}\" | xclip -selection clipboard", $"printf '%s' \"{EscapeShell(text)}\" | xsel --clipboard --input"];
foreach (var cmd in commands)
{
var (_, exitCode) = RunBashCommand(cmd);
if (exitCode == 0)
return;
}
}
static (string stdout, int exitCode) RunBashCommand(string cmd)
{
var process = new System.Diagnostics.Process
{
StartInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = "/bin/bash",
Arguments = $"-c \"{cmd}\"",
RedirectStandardOutput = true,
RedirectStandardError = true,
UseShellExecute = false,
CreateNoWindow = true,
},
};
process.Start();
string stdout = process.StandardOutput.ReadToEnd();
process.WaitForExit();
return (stdout.Trim(), process.ExitCode);
}
static string EscapeShell(string text)
{
return text.Replace("\"", "\\\"").Replace("$", "\\$").Replace("`", "\\`");
}
}
}
CodingTookit\src\Md2code\Program.cs
using System.Collections.Concurrent;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
internal class Program
{
private static async Task Main(string[] args)
{
var now = DateTime.Now;
string srcPath = args.Length > 0 ? args[0] : Directory.GetCurrentDirectory();
var config = new Config(srcPath);
bool hasConfig = config.CheckMd2CodeConfig();
if (!hasConfig)
{
System.Console.WriteLine("初次使用,使用默认配置文件");
}
config.LoadConfig();
var result = await FindLatestCode2mdFileAsync(srcPath, config);
if (result == null)
{
Console.WriteLine("\nNo .md files found.");
return;
}
Console.WriteLine($" Path: {result.Path}");
string mdPath = result.Path;
using var fs = new FileStream(mdPath, FileMode.Open, FileAccess.Read, FileShare.Read, 4096);
using var sr = new StreamReader(fs, Encoding.UTF8);
bool articleStart = false;
bool articleEnd = false;
bool articleRealStart = false;
bool mdStart = false;
string? codeFilePath = null;
string? title = null;
string? line;
while ((line = sr.ReadLine()?.Trim()) != null)
{
if (string.IsNullOrEmpty(line))
{
if (!string.IsNullOrEmpty(codeFilePath))
{
File.AppendAllText(codeFilePath, Environment.NewLine, Encoding.UTF8);
}
continue;
}
if (string.IsNullOrEmpty(title))
{
if (line.StartsWith("# ") && !mdStart)
{
title = line.TrimStart('#').Trim();
continue;
}
}
if (!articleEnd && line.StartsWith($"## `{title}") && line.EndsWith('`') && !mdStart)
{
string latestCodeFilePath = Path.Combine(srcPath, $"{title}_{now:yyyyMMdd_HHmmss}", line.Split(title + '\\').Last().TrimEnd('`'));
if (latestCodeFilePath != codeFilePath)
{
codeFilePath = latestCodeFilePath;
Console.WriteLine(codeFilePath);
string? codeDirPath = Path.GetDirectoryName(codeFilePath);
if (!string.IsNullOrEmpty(codeDirPath))
{
if (!Directory.Exists(codeDirPath))
{
Directory.CreateDirectory(codeDirPath);
}
articleStart = true;
continue;
}
}
}
if (articleStart && !string.IsNullOrEmpty(codeFilePath) && !mdStart)
{
if (line.StartsWith("```"))
{
articleRealStart = true;
continue;
}
}
if (articleRealStart && !string.IsNullOrEmpty(codeFilePath) && !mdStart)
{
if (line.StartsWith($"## `{title}") && line.EndsWith('`'))
{
articleEnd = true;
continue;
}
File.AppendAllText(codeFilePath, line + Environment.NewLine, Encoding.UTF8);
}
if (line.StartsWith($"# `{title}\\") && line.EndsWith('`') && line.Count(c => c.Equals('`')).Equals(4) && line.Contains("`\\_`"))
{
string mdTitle = line.Split(title + '\\').Last().Split("`\\_`").First();
string latestCodeFilePath = Path.Combine(srcPath, $"{title}_{now:yyyyMMdd_HHmmss}", mdTitle);
if (codeFilePath != latestCodeFilePath)
{
codeFilePath = latestCodeFilePath;
Console.WriteLine(codeFilePath);
}
string? latestCodeDirPath = Path.GetDirectoryName(latestCodeFilePath);
if (!string.IsNullOrEmpty(latestCodeDirPath))
{
if (!Directory.Exists(latestCodeDirPath))
{
Directory.CreateDirectory(latestCodeDirPath);
}
string firstLine = line.Split(title + '\\').Last().Split("`\\_`").Last().TrimEnd('`') + Environment.NewLine;
File.AppendAllText(codeFilePath, firstLine, Encoding.UTF8);
mdStart = true;
continue;
}
}
if (mdStart)
{
if (!string.IsNullOrEmpty(codeFilePath))
{
File.AppendAllText(codeFilePath, line + Environment.NewLine, Encoding.UTF8);
}
}
}
}
private static async Task<MdFileInfo?> FindLatestCode2mdFileAsync(string rootPath, Config config)
{
var latestFile = new ConcurrentBag<MdFileInfo>();
var directories = new ConcurrentStack<string>();
directories.Push(rootPath);
var filesProcessed = new ConcurrentCounter();
var directoriesScanned = new ConcurrentCounter();
await Task.Run(() =>
{
Parallel.ForEach(
Partitioner.Create(1, int.MaxValue),
range =>
{
var localLatest = (DateTimeOffset?)null;
MdFileInfo? localLatestFile = null;
while (directories.TryPop(out string? dir))
{
try
{
string[] subDirs = Array.Empty<string>();
string[] files = Array.Empty<string>();
try
{
subDirs = Directory.GetDirectories(dir);
files = Directory.GetFiles(dir, "zz_project_*.md");
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
foreach (var file in files)
{
try
{
var fileInfo = new FileInfo(file);
if (localLatest == null || fileInfo.LastWriteTimeUtc > localLatest.Value)
{
localLatest = fileInfo.LastWriteTimeUtc;
localLatestFile = new MdFileInfo(file, fileInfo.LastWriteTimeUtc);
}
}
catch { }
}
foreach (var subDir in subDirs)
{
if (!config.ShouldExcludeDirectory(subDir))
{
directories.Push(subDir);
}
}
directoriesScanned.Increment(1);
filesProcessed.Increment(files.Length);
}
catch { }
}
if (localLatestFile != null)
{
latestFile.Add(localLatestFile);
}
}
);
});
return latestFile.OrderByDescending(f => f.LastModifiedTime).FirstOrDefault();
}
}
CodingTookit\src\SqlcmdRunner\Program.cs
using System.Collections.Concurrent;
using System.Diagnostics;
using System.Text;
class Program
{
static async Task Main(string[] args)
{
Console.OutputEncoding = System.Text.Encoding.Default;
string path = args.Length > 0 ? args[0] : Directory.GetCurrentDirectory();
var config = new Config(path);
bool hasConfig = config.CheckCmdSqlConfig();
if (!hasConfig)
{
System.Console.WriteLine("初次使用,使用默认配置文件");
}
config.LoadConfig();
var stopwatch = Stopwatch.StartNew();
var result = await FindLatestSqlFileAsync(path, config);
var tempPath = Path.Combine(@"C:\Users", Environment.UserName, @"AppData\Local\Temp");
stopwatch.Stop();
if (result == null)
{
Console.WriteLine("\nNo .sql files found.");
Console.WriteLine($"\nScanned in {stopwatch.ElapsedMilliseconds}ms");
return;
}
Console.WriteLine($"\nFound latest SQL file:");
Console.WriteLine($" Path: {result.Path}");
Console.WriteLine($" Modified: {result.LastModifiedTime:yyyy-MM-dd HH:mm:ss}");
string latestSrcSqlFilePath = result.Path;
List<string> bottoms = ReverseReadLines(latestSrcSqlFilePath);
string latestDstSqlFilePath = Path.Combine(tempPath, Path.GetTempFileName());
bool dryRun = args.Contains("--dry-run") || args.Contains("-n");
bool runSqlCmd = args.Contains("--run") || args.Contains("-r");
string? server = GetArgValue(args, "--server", "-s");
string? database = GetArgValue(args, "--database", "-d");
string? username = GetArgValue(args, "--username", "-u");
string? password = GetArgValue(args, "--password", "-p");
bool useWindowsAuth = !(args.Contains("--sql-auth") || args.Contains("--auth-sql"));
int timeout = ParseIntArg(args, "--timeout", "-t", "60");
File.WriteAllText(latestDstSqlFilePath, string.Join(Environment.NewLine, bottoms), System.Text.Encoding.UTF8);
Console.WriteLine($"\nScanned in {stopwatch.ElapsedMilliseconds}ms");
Console.WriteLine($"Generated temp SQL file: {latestDstSqlFilePath}");
if (runSqlCmd)
{
Console.WriteLine("\n--- EXECUTING SQLCMD ---");
var executor = new SqlCmdExecutor
{
Server = server,
Database = database,
Username = username,
Password = password,
UseWindowsAuth = useWindowsAuth,
TimeoutSeconds = timeout,
DryRun = dryRun,
};
string resultFilePath = Path.Combine(tempPath, Path.GetTempFileName().Replace(".tmp", ".txt"));
var (success, output, error, _) = executor.Execute(latestDstSqlFilePath, resultFilePath);
Console.WriteLine($"\n✅ Execution {(success ? "SUCCEEDED" : "FAILED")} ({(success ? "0" : "1")} exit code)");
Console.WriteLine($"⏱️ Duration: {stopwatch.ElapsedMilliseconds}ms");
Console.WriteLine($"\n📄 Results saved to: {resultFilePath}");
try
{
Process.Start(@"C:\Program Files\Microsoft VS Code\Code.exe", resultFilePath);
Console.WriteLine("✅ VSCode opened with results file");
}
catch (Exception ex)
{
Console.WriteLine($"⚠️ Failed to open VSCode: {ex.Message}");
Console.WriteLine("💡 Try running 'code .' from command line first to ensure VSCode is in PATH");
}
if (success)
{
Console.WriteLine("\n🎉 SQL executed successfully.");
}
else
{
Console.WriteLine("\n⚠️ Check connection, permissions, and SQL syntax.");
Environment.Exit(1);
}
}
else
{
Console.WriteLine($"\n💡 Tip: Run with --run to execute, or --dry-run to preview command.");
}
Console.WriteLine($"\nScanned in {stopwatch.ElapsedMilliseconds}ms");
}
public static List<string> ReverseReadLines(string filePath)
{
List<string> resultLines = new List<string>();
List<byte> currentLineBuffer = new List<byte>();
int consecutiveEmptyLines = 0;
bool foundFirstContent = false;
using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read))
{
long position = fs.Length;
while (position > 0)
{
position--;
fs.Position = position;
int byteValue = fs.ReadByte();
if (byteValue == -1)
continue;
char c = (char)byteValue;
if (c == '\n')
{
currentLineBuffer.Reverse();
string line = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
currentLineBuffer.Clear();
if (!foundFirstContent)
{
if (!string.IsNullOrWhiteSpace(line))
{
foundFirstContent = true;
resultLines.Add(line);
}
}
else
{
if (string.IsNullOrWhiteSpace(line))
{
consecutiveEmptyLines++;
if (consecutiveEmptyLines >= 3)
{
break;
}
}
else
{
resultLines.Add(line);
consecutiveEmptyLines = 0;
}
}
}
else
{
currentLineBuffer.Add((byte)byteValue);
}
}
if (currentLineBuffer.Count > 0 && (foundFirstContent && consecutiveEmptyLines < 3))
{
currentLineBuffer.Reverse();
string firstLine = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
if (!string.IsNullOrWhiteSpace(firstLine))
{
resultLines.Add(firstLine);
}
}
else if (currentLineBuffer.Count > 0 && !foundFirstContent)
{
currentLineBuffer.Reverse();
string onlyLine = Encoding.UTF8.GetString(currentLineBuffer.ToArray()).TrimEnd('\r');
if (!string.IsNullOrWhiteSpace(onlyLine))
{
resultLines.Add(onlyLine);
}
}
}
resultLines.Reverse();
return resultLines;
}
public static string? GetArgValue(string[] args, params string[] keys)
{
for (int i = 0; i < args.Length - 1; i++)
{
if (keys.Contains(args[i], StringComparer.OrdinalIgnoreCase))
return args[i + 1];
}
return null;
}
public static int ParseIntArg(string[] args, params string[] keys)
{
var val = GetArgValue(args, keys);
return int.TryParse(val, out int n) ? n : 60;
}
private static async Task<SqlFileInfo?> FindLatestSqlFileAsync(string rootPath, Config config)
{
var latestFile = new ConcurrentBag<SqlFileInfo>();
var directories = new ConcurrentStack<string>();
directories.Push(rootPath);
var filesProcessed = new ConcurrentCounter();
var directoriesScanned = new ConcurrentCounter();
await Task.Run(() =>
{
Parallel.ForEach(
Partitioner.Create(1, int.MaxValue),
range =>
{
var localLatest = (DateTimeOffset?)null;
SqlFileInfo? localLatestFile = null;
while (directories.TryPop(out string? dir))
{
try
{
string[] subDirs = Array.Empty<string>();
string[] files = Array.Empty<string>();
try
{
subDirs = Directory.GetDirectories(dir);
files = Directory.GetFiles(dir, "*.sql");
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (PathTooLongException)
{
continue;
}
foreach (var file in files)
{
try
{
var fileInfo = new FileInfo(file);
if (localLatest == null || fileInfo.LastWriteTimeUtc > localLatest.Value)
{
localLatest = fileInfo.LastWriteTimeUtc;
localLatestFile = new SqlFileInfo(file, fileInfo.LastWriteTimeUtc);
}
}
catch { }
}
foreach (var subDir in subDirs)
{
if (!config.ShouldExcludeDirectory(subDir))
{
directories.Push(subDir);
}
}
directoriesScanned.Increment(1);
filesProcessed.Increment(files.Length);
}
catch { }
}
if (localLatestFile != null)
{
latestFile.Add(localLatestFile);
}
}
);
});
return latestFile.OrderByDescending(f => f.LastModifiedTime).FirstOrDefault();
}
}
public class SqlFileInfo
{
public string Path { get; }
public DateTimeOffset LastModifiedTime { get; }
public SqlFileInfo(string path, DateTimeOffset lastModifiedTime)
{
Path = path;
LastModifiedTime = lastModifiedTime;
}
}
public class ConcurrentCounter
{
private long _count = 0;
public void Increment(long value = 1)
{
Interlocked.Add(ref _count, value);
}
public long Value => Interlocked.Read(ref _count);
}
CodingTookit\src\SqlcmdRunner\Config.cs
using Microsoft.Extensions.Configuration;
public class Config
{
private readonly string _srcPath;
private readonly string _configPath;
private IConfigurationRoot _configurationRoot = null!;
public List<string> ExcludeEqualDirs { get; set; } = new();
public List<string> ExcludeStartDirs { get; set; } = new();
public List<string> ExcludeEndDirs { get; set; } = new();
public Config(string srcPath)
{
_srcPath = srcPath;
_configPath = Path.Combine(srcPath, ".vscode", "cmdSql.yaml");
}
public bool CheckCmdSqlConfig()
{
string configDir = Path.GetDirectoryName(_configPath) ?? ".vscode";
if (!Directory.Exists(configDir))
{
Directory.CreateDirectory(configDir);
}
if (!File.Exists(_configPath))
{
File.WriteAllText(_configPath, GenerateCmdSqlConfigYaml(), System.Text.Encoding.UTF8);
return false;
}
return true;
}
public void LoadConfig()
{
if (!File.Exists(_configPath))
return;
try
{
_configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_configPath, optional: true, reloadOnChange: true).Build();
ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
}
catch (Exception ex)
{
Console.WriteLine($"Warning: Could not load config file: {ex.Message}");
ExcludeEqualDirs.Clear();
ExcludeStartDirs.Clear();
ExcludeEndDirs.Clear();
}
}
public bool ShouldExcludeDirectory(string dirPath)
{
string dirName = Path.GetFileName(dirPath);
if (ExcludeEqualDirs.Contains(dirName))
return true;
if (ExcludeStartDirs.Any(prefix => dirName.StartsWith(prefix)))
return true;
if (ExcludeEndDirs.Any(suffix => dirName.EndsWith(suffix)))
return true;
return false;
}
private List<string> GetConfigList(string sectionName)
{
return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).Where(v => !string.IsNullOrEmpty(v)).ToList();
}
public static string GenerateCmdSqlConfigYaml()
{
return @"ExcludeEqualDirs:
- ""res""
- ""docs""
- ""note""
- ""config""
- ""Publish""
- "".idea""
- "".vs""
- "".vscode""
- "".git""
- ""zz_pro""
- ""zz_res""
- ""zz_zz""
- ""bin""
- ""zz_config""
- ""zz_note""
- ""zz_cache""
- ""node_modules""
- ""obj""
- ""zz_zz_publish""
- ""zz_zz_pro""
- ""Migrations""
- ""log""
- ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []";
}
}
CodingTookit\scripts\sql.bat
@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\LatestSqlFinder\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\LatestSqlFinder\bin\Release\net9.0\win-x64\publish\LatestSqlFinder.exe "%scriptPath%"
D: && cd D:\CodingTookit\src\SqlServerRunner\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\SqlServerRunner\bin\Release\net9.0\win-x64\publish\SqlServerRunner.exe "%scriptPath%"
CodingTookit\src\Warp\Warp.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
<StartupObject></StartupObject>
</PropertyGroup>
</Project>
CodingTookit\src\CopyFileV2\CopyFileV2.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
<PackageReference Include="YamlDotNet" Version="15.1.2" />
</ItemGroup>
</Project>
CodingTookit\scripts\backup.bat
@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\CopyFileV2\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\CopyFileV2\bin\Release\net9.0\win-x64\publish\Code2mdV2.exe "%scriptPath%"
CodingTookit\publish.bat
dotnet publish .\src\Code2md\Code2md.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
dotnet publish .\src\CopyFileV2\CopyFileV2.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
dotnet publish .\src\Code2md\Code2md.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true /p:AssemblyName=test
CodingTookit\src\Md2code\Md2code.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
<PackageReference Include="YamlDotNet" Version="15.1.2" />
</ItemGroup>
</Project>
CodingTookit\src\Code2md\Code2md.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net10.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
<PackageReference Include="YamlDotNet" Version="15.1.2" />
</ItemGroup>
</Project>
CodingTookit\scripts\code2md.bat
@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\Code2md.exe "%scriptPath%"
CodingTookit\src\SqlServerRunner\Program.cs
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
class Program
{
[DllImport("user32.dll")]
private static extern bool SetForegroundWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr FindWindow(string? lpClassName, string lpWindowName);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();
private const int SW_RESTORE = 9;
static void Main(string[] args)
{
const string windowTitle = "Microsoft SQL Server Management Studio";
const string processName = "ssms";
IntPtr previousActiveWindow = GetForegroundWindow();
IntPtr hWnd = FindWindow(null, windowTitle);
if (hWnd == IntPtr.Zero)
{
Process[] processes = Process.GetProcessesByName(processName);
if (processes.Length > 0)
{
hWnd = processes[0].MainWindowHandle;
processes[0].Dispose();
}
}
if (hWnd == IntPtr.Zero)
{
Console.WriteLine("Error: Microsoft SQL Server Management Studio is not running.");
return;
}
if (IsIconic(hWnd))
{
ShowWindow(hWnd, SW_RESTORE);
}
if (!SetForegroundWindow(hWnd))
{
Console.WriteLine("Error: Failed to activate the window.");
return;
}
Thread.Sleep(500);
SendF5Key();
Thread.Sleep(500);
if (previousActiveWindow != IntPtr.Zero)
{
SetForegroundWindow(previousActiveWindow);
}
Console.WriteLine("F5 key sent to SQL Server Management Studio successfully.");
}
private static void SendF5Key()
{
const byte VK_F5 = 0x74;
const uint KEYEVENTF_KEYUP = 0x2;
keybd_event(VK_F5, 0, 0, IntPtr.Zero);
keybd_event(VK_F5, 0, KEYEVENTF_KEYUP, IntPtr.Zero);
}
[DllImport("user32.dll")]
private static extern void keybd_event(byte bVk, byte bScan, uint dwFlags, IntPtr dwExtraInfo);
}
CodingTookit\src\SqlcmdRunner\SqlCmdExecutor.cs
using System.Diagnostics;
using System.Text;
public class SqlCmdExecutor
{
public string? Server { get; set; }
public string? Database { get; set; }
public string? Username { get; set; }
public string? Password { get; set; }
public bool UseWindowsAuth { get; set; } = true;
public int TimeoutSeconds { get; set; } = 60;
public bool DryRun { get; set; } = false;
public (bool success, string output, string error, string? outputFilePath) Execute(string sqlFilePath, string? outputFilePath = null)
{
var args = BuildSqlCmdArgs(sqlFilePath, outputFilePath);
var cmdPath = GetSqlCmdPath();
System.Console.WriteLine($"cmdPath: {cmdPath}");
if (DryRun)
{
Console.WriteLine($"[DRY RUN] Would execute:");
Console.WriteLine($" \"{cmdPath}\" {args}");
Console.WriteLine($" on file: {sqlFilePath}");
return (true, "[dry run skipped]", "", outputFilePath);
}
try
{
using var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = cmdPath,
Arguments = args,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardError = true,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden,
StandardOutputEncoding = Encoding.Default,
StandardErrorEncoding = Encoding.Default,
},
};
var stopwatch = Stopwatch.StartNew();
process.Start();
bool exited = process.WaitForExit(TimeoutSeconds * 1000);
stopwatch.Stop();
string output = process.StandardOutput.ReadToEnd();
string error = process.StandardError.ReadToEnd();
if (!exited)
{
process.Kill();
return (false, "", $"ERROR: Command timed out after {TimeoutSeconds}s", outputFilePath);
}
bool success = process.ExitCode == 0;
if (!success)
{
error = $"EXIT CODE {process.ExitCode}: {error.Trim()}";
}
return (success, output, error, outputFilePath);
}
catch (Exception ex)
{
return (false, "", $"EXCEPTION: {ex.GetType().Name}: {ex.Message}", outputFilePath);
}
}
private string BuildSqlCmdArgs(string sqlFilePath, string? outputFilePath = null)
{
var args = new List<string>();
if (!string.IsNullOrEmpty(Server))
args.Add($"-S \"{Server}\"");
if (!string.IsNullOrEmpty(Database))
args.Add($"-d \"{Database}\"");
if (UseWindowsAuth)
{
args.Add("-E"); // Windows Authentication
}
else
{
if (!string.IsNullOrEmpty(Username))
args.Add($"-U \"{Username}\"");
if (!string.IsNullOrEmpty(Password))
args.Add($"-P \"{Password}\"");
}
args.Add($"-i \"{sqlFilePath}\"");
args.Add($"-I"); // quoted identifiers (safer for mixed-case names)
args.Add($"-r1"); // send errors to stderr (consistent with above)
args.Add($"-t {TimeoutSeconds}"); // timeout in seconds
args.Add("-h -1"); // no column headers
args.Add("-s \"|\""); // pipe delimiter (if output parsing needed later)
args.Add("-f 65001"); // 使用UTF-8编码
if (!string.IsNullOrEmpty(outputFilePath))
{
args.Add($"-o \"{outputFilePath}\"");
}
return string.Join(" ", args);
}
private string GetSqlCmdPath()
{
var path = Environment.GetEnvironmentVariable("PATH") ?? "";
foreach (var dir in path.Split(Path.PathSeparator))
{
var candidate = Path.Combine(dir.Trim(), "sqlcmd.exe");
if (File.Exists(candidate))
return candidate;
}
var programFiles = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles);
var sqlCmdInProgramFiles = Path.Combine(programFiles, @"Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\sqlcmd.exe");
if (File.Exists(sqlCmdInProgramFiles))
return sqlCmdInProgramFiles;
var programFilesX86 = Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86);
var sqlCmdInX86 = Path.Combine(programFilesX86, @"Microsoft SQL Server\Client SDK\ODBC\170\Tools\Binn\sqlcmd.exe");
if (File.Exists(sqlCmdInX86))
return sqlCmdInX86;
throw new InvalidOperationException("sqlcmd.exe not found. Please install SQL Server Command Line Utilities or add it to PATH.");
}
}
CodingTookit\.claude\settings.local.json
{
"permissions": {
"allow": [
"Bash(cat:*)",
"Bash(dotnet build:*)",
"Bash(cmd /c:*)",
"Bash(dotnet run:*)",
"Bash(powershell:*)",
"Bash(D:/CodingTookit/run.bat:*)",
"Bash(cmd.exe:*)",
"Bash(powershell.exe:*)"
]
}
}
CodingTookit\src\SqlcmdRunner\SqlcmdRunner.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.0" />
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.1.0" />
<PackageReference Include="YamlDotNet" Version="15.1.2" />
</ItemGroup>
</Project>
CodingTookit\scripts\md2code.bat
@echo off
chcp 65001
set "scriptPath=%cd%"
D:
D:\CodingTookit\src\Md2code\bin\Release\net9.0\win-x64\Md2code.exe "%scriptPath%" %*
CodingTookit\src\Md2code\Config.cs
using Microsoft.Extensions.Configuration;
public class Config
{
private readonly string _srcPath;
private readonly string _configPath;
private IConfigurationRoot _configurationRoot = null!;
public List<string> ExcludeEqualDirs { get; set; } = new();
public List<string> ExcludeStartDirs { get; set; } = new();
public List<string> ExcludeEndDirs { get; set; } = new();
public Config(string srcPath)
{
_srcPath = srcPath;
_configPath = Path.Combine(srcPath, ".vscode", "md2code.yaml");
}
public bool CheckMd2CodeConfig()
{
string configDir = Path.GetDirectoryName(_configPath) ?? ".vscode";
if (!Directory.Exists(configDir))
{
Directory.CreateDirectory(configDir);
}
if (!File.Exists(_configPath))
{
File.WriteAllText(_configPath, GenerateCmdSqlConfigYaml(), System.Text.Encoding.UTF8);
return false;
}
return true;
}
public void LoadConfig()
{
if (!File.Exists(_configPath))
return;
try
{
_configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_configPath, optional: true, reloadOnChange: true).Build();
ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
}
catch (Exception ex)
{
Console.WriteLine($"Warning: Could not load config file: {ex.Message}");
ExcludeEqualDirs.Clear();
ExcludeStartDirs.Clear();
ExcludeEndDirs.Clear();
}
}
public bool ShouldExcludeDirectory(string dirPath)
{
string dirName = Path.GetFileName(dirPath);
if (ExcludeEqualDirs.Contains(dirName))
return true;
if (ExcludeStartDirs.Any(prefix => dirName.StartsWith(prefix)))
return true;
if (ExcludeEndDirs.Any(suffix => dirName.EndsWith(suffix)))
return true;
return false;
}
private List<string> GetConfigList(string sectionName)
{
return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).Where(v => !string.IsNullOrEmpty(v)).ToList();
}
public static string GenerateCmdSqlConfigYaml()
{
return @"ExcludeEqualDirs:
- ""res""
- ""docs""
- ""note""
- ""config""
- ""Publish""
- "".idea""
- "".vs""
- "".vscode""
- "".git""
- ""zz_pro""
- ""zz_res""
- ""zz_zz""
- ""bin""
- ""zz_config""
- ""zz_note""
- ""zz_cache""
- ""node_modules""
- ""obj""
- ""zz_zz_publish""
- ""zz_zz_pro""
- ""Migrations""
- ""log""
- ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []";
}
}
CodingTookit\src\Md2code\MdFileInfo.cs
public class MdFileInfo
{
public string Path { get; }
public DateTimeOffset LastModifiedTime { get; }
public MdFileInfo(string path, DateTimeOffset lastModifiedTime)
{
Path = path;
LastModifiedTime = lastModifiedTime;
}
}
CodingTookit\src\Md2code\ConcurrentCounter.cs
public class ConcurrentCounter
{
private long _count = 0;
public void Increment(long value = 1)
{
Interlocked.Add(ref _count, value);
}
public long Value => Interlocked.Read(ref _count);
}
CodingTookit\src\Code2md\Project.cs
using System.Text;
public class Project
{
private readonly string _srcPath;
private readonly Config _config;
private readonly DateTime _now = DateTime.Now;
private string _suffix = string.Empty;
public Project(string srcPath)
{
_srcPath = srcPath;
_config = new Config(srcPath);
}
public async Task Run()
{
Console.WriteLine("============== Run Code2md START==============");
bool hasConfig = _config.CheckCode2mdConfig();
if (!hasConfig)
{
return;
}
Console.WriteLine("请输入文件名后缀:");
Console.InputEncoding = Encoding.Unicode;
Console.OutputEncoding = Encoding.Unicode;
_suffix = Console.ReadLine()?.Trim() ?? string.Empty;
_config.LoadConfig();
List<string> rootDirPaths = this.GetRootDirPaths();
List<string> deepDirs = await GetDeepDirPaths(rootDirPaths);
List<string> allDirPaths = rootDirPaths.Concat(deepDirs).ToList();
allDirPaths.Add(_srcPath);
List<string> allFilePaths = await GetAllFiles(allDirPaths);
List<string> sortedFilePaths = allFilePaths.Select(path => new { Path = path, LastWriteTime = File.GetLastWriteTime(path) }).OrderByDescending(file => file.LastWriteTime).Select(file => file.Path).ToList();
this.CodeToOneMarkdown(sortedFilePaths);
Console.WriteLine("============== Run Code2md END ==============");
}
private void CodeToOneMarkdown(List<string> filePaths)
{
var mdFileName = $"zz_project_{_now:yyyyMMdd_HHmmss}_{_suffix}.md";
var mdFolderPath = Path.Combine(_srcPath, "zz_zz");
if (!Directory.Exists(mdFolderPath))
{
Directory.CreateDirectory(mdFolderPath);
}
string mdFilePath = Path.Combine(mdFolderPath, mdFileName);
using StreamWriter sw = new StreamWriter(mdFilePath, false, Encoding.UTF8);
string basePath = Path.GetDirectoryName(_srcPath) ?? string.Empty;
string projectName = Path.GetFileName(_srcPath);
sw.WriteLine($"\n# {projectName}\n");
List<string> codeFiles = filePaths.Where(file => !file.EndsWith(".md")).ToList();
foreach (var file in codeFiles)
{
string fileExtension = Path.GetExtension(file).ToLowerInvariant().Trim();
if (!_config.CodeToMarkDownExtension.Contains(fileExtension))
{
Console.WriteLine($"skip code2md no suffix: {file}");
continue;
}
string relativePath = Path.GetRelativePath(basePath, file);
sw.WriteLine($"\n## `{relativePath}`\n");
string? markdownCodeBlockName = _config.CodeSuffixMap.GetValueOrDefault(fileExtension);
if (string.IsNullOrEmpty(markdownCodeBlockName))
{
markdownCodeBlockName = fileExtension.Replace(".", "").Trim();
}
sw.WriteLine($"\n```{markdownCodeBlockName}\n");
try
{
using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: false);
using var reader = new StreamReader(fs, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 8192);
string? line;
while ((line = reader.ReadLine()) != null)
{
if (fileExtension.Equals(".cs"))
{
if (line.Trim().StartsWith("//"))
{
continue;
}
if (string.IsNullOrEmpty(line.Trim()))
{
continue;
}
}
sw.WriteLine(line);
}
}
catch (UnauthorizedAccessException)
{
Console.WriteLine($"Unauthorized access to file: {file}");
sw.WriteLine($"<!-- Unauthorized access to file: {file} -->\n```");
continue;
}
catch (IOException ex)
{
Console.WriteLine($"IO error reading file {file}: {ex.Message}");
sw.WriteLine($"<!-- IO error reading file: {file} - {ex.Message} -->\n```");
continue;
}
catch (System.Exception ex)
{
Console.WriteLine($"Error reading file {file}: {ex.Message}");
sw.WriteLine($"<!-- Error reading file: {file} - {ex.Message} -->\n```");
continue;
}
sw.WriteLine("\n```");
}
List<string> mdFiles = filePaths.Where(file => file.EndsWith(".md")).ToList();
foreach (var file in mdFiles)
{
string relativePath = Path.GetRelativePath(basePath, file);
var firstInFlag = true;
sw.Write($"\n# `{relativePath}`");
try
{
using var fs = new FileStream(file, FileMode.Open, FileAccess.Read, FileShare.Read, bufferSize: 4096, useAsync: false);
using var reader = new StreamReader(fs, Encoding.UTF8, detectEncodingFromByteOrderMarks: true, bufferSize: 8192);
string? line;
while ((line = reader.ReadLine()) != null)
{
if (string.IsNullOrEmpty(line.Trim()))
{
continue;
}
if (line.Trim().StartsWith("# "))
{
sw.Write($"_`{line}`\n\n");
continue;
}
if (firstInFlag)
{
sw.WriteLine("\n");
firstInFlag = false;
}
sw.WriteLine(line);
}
}
catch (UnauthorizedAccessException)
{
Console.WriteLine($"Unauthorized access to file: {file}");
sw.WriteLine($"<!-- Unauthorized access to file: {file} -->\n```");
continue;
}
catch (IOException ex)
{
Console.WriteLine($"IO error reading file {file}: {ex.Message}");
sw.WriteLine($"<!-- IO error reading file: {file} - {ex.Message} -->\n```");
continue;
}
catch (System.Exception ex)
{
Console.WriteLine($"Error reading file {file}: {ex.Message}");
sw.WriteLine($"<!-- Error reading file: {file} - {ex.Message} -->\n```");
continue;
}
}
Console.WriteLine($"=========代码转成一个Markdown文件成功!!!=========");
}
private async Task<List<string>> GetAllFiles(List<string> allDirPaths)
{
List<Task<List<string>>> tasks = new List<Task<List<string>>>();
foreach (var allDirPath in allDirPaths)
{
tasks.Add(Task.Run(() => GetFilteringTopDirFiles(allDirPath)));
}
await Task.WhenAll(tasks);
var files = new List<string>();
foreach (var task in tasks)
{
files.AddRange(task.Result);
}
return files;
}
public List<string> GetFilteringTopDirFiles(string folderPath)
{
return Directory.GetFiles(folderPath, "*", SearchOption.TopDirectoryOnly).Where(file => ShouldIncludeFile(Path.GetFileName(file))).ToList();
}
public bool ShouldIncludeFile(string fileName)
{
return !_config.GetExcludeFileFlag(fileName) || _config.GetIncludeFileFlag(fileName);
}
private List<string> GetRootDirPaths()
{
return Directory
.GetDirectories(_srcPath, "*", SearchOption.TopDirectoryOnly)
.Where(dirPath =>
{
string folderName = Path.GetFileName(dirPath);
return !_config.GetExcludeDirFlag(folderName) || _config.GetIncludeDirFlag(folderName);
})
.ToList();
}
private async Task<List<string>> GetDeepDirPaths(List<string> rootDirPaths)
{
var tasks = rootDirPaths.Select(rootDirPath => Task.Run(() => GetFilteringAllDirTask(rootDirPath))).ToArray();
await Task.WhenAll(tasks);
return tasks.SelectMany(task => task.Result).ToList();
}
private List<string> GetFilteringAllDirTask(string rootDirPath)
{
var deepDirs = new List<string>();
GetFilteringAllDirs(rootDirPath, deepDirs);
return deepDirs;
}
public void GetFilteringAllDirs(string folderPath, List<string> allFolders)
{
try
{
var validSubdirs = GetFilteringTopDirFolders(folderPath);
foreach (var dir in validSubdirs)
{
allFolders.Add(dir);
GetFilteringAllDirs(dir, allFolders);
}
}
catch (Exception ex)
{
Console.WriteLine($"Error while traversing folder: {ex.Message}");
}
}
public List<string> GetFilteringTopDirFolders(string folderPath)
{
return Directory.GetDirectories(folderPath, "*", SearchOption.TopDirectoryOnly).Where(dir => ShouldIncludeDir(Path.GetFileName(dir))).ToList();
}
public bool ShouldIncludeDir(string folderName)
{
return !GetExcludeDirFlag(folderName) || GetIncludeDirFlag(folderName);
}
private bool GetExcludeDirFlag(string folderName)
{
return _config.ExcludeEqualDirs.Any(folder => folderName.Equals(folder)) || _config.ExcludeStartDirs.Any(folder => folderName.StartsWith(folder)) || _config.ExcludeEndDirs.Any(folder => folderName.EndsWith(folder));
}
private bool GetIncludeDirFlag(string folderName)
{
return _config.IncludeEqualDirs.Any(folder => folderName.Equals(folder)) || _config.IncludeStartDirs.Any(folder => folderName.StartsWith(folder)) || _config.IncludeEndDirs.Any(folder => folderName.EndsWith(folder));
}
}
CodingTookit\src\Code2md\Program.cs
if (args.Length == 0)
{
Console.WriteLine("请传入文件夹路径");
return;
}
if (!Directory.Exists(args[0]))
{
Console.WriteLine($"传入的文件夹不存在 : {args[0]}");
return;
}
Project project = new Project(args[0].Trim());
await project.Run();
CodingTookit\src\LatestSqlFinder\Config.cs
using Microsoft.Extensions.Configuration;
public class Config
{
private readonly string _srcPath;
private readonly string _configPath;
private IConfigurationRoot _configurationRoot = null!;
public List<string> ExcludeEqualDirs { get; set; } = new();
public List<string> ExcludeStartDirs { get; set; } = new();
public List<string> ExcludeEndDirs { get; set; } = new();
public Config(string srcPath)
{
_srcPath = srcPath;
_configPath = Path.Combine(srcPath, ".vscode", "cmdSql.yaml");
}
public bool CheckCmdSqlConfig()
{
string configDir = Path.GetDirectoryName(_configPath) ?? ".vscode";
if (!Directory.Exists(configDir))
{
Directory.CreateDirectory(configDir);
}
if (!File.Exists(_configPath))
{
File.WriteAllText(_configPath, GenerateCmdSqlConfigYaml(), System.Text.Encoding.UTF8);
return false;
}
return true;
}
public void LoadConfig()
{
if (!File.Exists(_configPath))
return;
try
{
_configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_configPath, optional: true, reloadOnChange: true).Build();
ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
}
catch (Exception ex)
{
Console.WriteLine($"Warning: Could not load config file: {ex.Message}");
ExcludeEqualDirs.Clear();
ExcludeStartDirs.Clear();
ExcludeEndDirs.Clear();
}
}
public bool ShouldExcludeDirectory(string dirPath)
{
string dirName = Path.GetFileName(dirPath);
if (ExcludeEqualDirs.Contains(dirName))
return true;
if (ExcludeStartDirs.Any(prefix => dirName.StartsWith(prefix)))
return true;
if (ExcludeEndDirs.Any(suffix => dirName.EndsWith(suffix)))
return true;
return false;
}
private List<string> GetConfigList(string sectionName)
{
return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).Where(v => !string.IsNullOrEmpty(v)).ToList();
}
public static string GenerateCmdSqlConfigYaml()
{
return @"ExcludeEqualDirs:
- ""res""
- ""docs""
- ""note""
- ""config""
- ""Publish""
- "".idea""
- "".vs""
- "".vscode""
- "".git""
- ""zz_pro""
- ""zz_res""
- ""zz_zz""
- ""bin""
- ""zz_config""
- ""zz_note""
- ""zz_cache""
- ""node_modules""
- ""obj""
- ""zz_zz_publish""
- ""zz_zz_pro""
- ""Migrations""
- ""log""
- ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []";
}
}
CodingTookit\src\Code2md\Config.cs
using Microsoft.Extensions.Configuration;
public class Config
{
private readonly string _srcPath;
private readonly string _code2mdConfigFolder;
private readonly string _code2mdConfigPath;
private IConfigurationRoot _configurationRoot = null!;
public List<string> ExcludeEqualDirs { get; set; } = null!;
public List<string> ExcludeStartDirs { get; set; } = null!;
public List<string> ExcludeEndDirs { get; set; } = null!;
public List<string> IncludeEqualDirs { get; set; } = null!;
public List<string> IncludeStartDirs { get; set; } = null!;
public List<string> IncludeEndDirs { get; set; } = null!;
public List<string> ExcludeEqualFiles { get; set; } = null!;
public List<string> ExcludeStartFiles { get; set; } = null!;
public List<string> ExcludeEndFiles { get; set; } = null!;
public List<string> IncludeEqualFiles { get; set; } = null!;
public List<string> IncludeStartFiles { get; set; } = null!;
public List<string> IncludeEndFiles { get; set; } = null!;
public List<string> CodeToMarkDownExtension { get; set; } = null!;
public Dictionary<string, string> CodeSuffixMap { get; set; } = null!;
public Config(string srcPath)
{
_srcPath = srcPath;
_code2mdConfigFolder = Path.Combine(_srcPath, ".vscode");
_code2mdConfigPath = Path.Combine(_srcPath, ".vscode", "code2md.yaml");
}
public bool CheckCode2mdConfig()
{
if (!Directory.Exists(_code2mdConfigFolder))
{
Directory.CreateDirectory(_code2mdConfigFolder);
}
if (!Path.Exists(_code2mdConfigPath))
{
Console.WriteLine($"无配置文件 : {_code2mdConfigPath} , 已生成配置文件,然后返回");
File.WriteAllText(_code2mdConfigPath, GenerateCode2mdConfigYaml(), System.Text.Encoding.UTF8);
return false;
}
return true;
}
public void LoadConfig()
{
_configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_code2mdConfigPath, optional: true, reloadOnChange: true).Build();
ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
IncludeEqualDirs = GetConfigList("IncludeEqualDirs");
IncludeStartDirs = GetConfigList("IncludeStartDirs");
IncludeEndDirs = GetConfigList("IncludeEndDirs");
ExcludeEqualFiles = GetConfigList("ExcludeEqualFiles");
ExcludeStartFiles = GetConfigList("ExcludeStartFiles");
ExcludeEndFiles = GetConfigList("ExcludeEndFiles");
IncludeEqualFiles = GetConfigList("IncludeEqualFiles");
IncludeStartFiles = GetConfigList("IncludeStartFiles");
IncludeEndFiles = GetConfigList("IncludeEndFiles");
CodeToMarkDownExtension = GetConfigList("CodeToMarkDownExtension");
CodeSuffixMap = GetConfigMap("CodeSuffixDic");
}
public bool GetExcludeDirFlag(string folderName)
{
return ExcludeEqualDirs.Any(folder => folderName.Equals(folder)) || ExcludeStartDirs.Any(folder => folderName.StartsWith(folder)) || ExcludeEndDirs.Any(folder => folderName.EndsWith(folder));
}
public bool GetIncludeDirFlag(string folderName)
{
return IncludeEqualDirs.Any(folder => folderName.Equals(folder)) || IncludeStartDirs.Any(folder => folderName.StartsWith(folder)) || IncludeEndDirs.Any(folder => folderName.EndsWith(folder));
}
public bool GetExcludeFileFlag(string fileName)
{
return ExcludeEqualFiles.Any(folder => fileName.Equals(folder)) || ExcludeStartFiles.Any(folder => fileName.StartsWith(folder)) || ExcludeEndFiles.Any(folder => fileName.EndsWith(folder));
}
public bool GetIncludeFileFlag(string fileName)
{
return IncludeEqualFiles.Any(folder => fileName.Equals(folder)) || IncludeStartFiles.Any(folder => fileName.StartsWith(folder)) || IncludeEndFiles.Any(folder => fileName.EndsWith(folder));
}
private List<string> GetConfigList(string sectionName)
{
return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).ToList();
}
private Dictionary<string, string> GetConfigMap(string sectionName)
{
return _configurationRoot.GetSection(sectionName).GetChildren().ToDictionary(e => e.Key, e => e.Value ?? string.Empty);
}
public static string GenerateCode2mdConfigYaml()
{
return @"DstBackFolder: """"
ExcludeEqualDirs:
- ""res""
- ""docs""
- ""note""
- ""config""
- ""Publish""
- "".idea""
- "".vs""
- "".vscode""
- "".git""
- ""zz_pro""
- ""zz_res""
- ""zz_zz""
- ""bin""
- ""zz_config""
- ""zz_note""
- ""zz_cache""
- ""node_modules""
- ""obj""
- ""zz_zz_publish""
- ""zz_zz_pro""
- ""Migrations""
- ""log""
- ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []
IncludeEqualDirs: []
IncludeStartDirs: []
IncludeEndDirs: []
ExcludeEqualFiles:
- ""zz.bat""
- ""AssemblyInfo.cs""
- ""out.txt""
ExcludeStartFiles:
- ""temp""
ExcludeEndFiles:
- "".xlsx""
- "".doc""
- "".docx""
- "".ppt""
- "".pptx""
- "".pdf""
- "".png""
- "".jpg""
- "".jpeg""
- "".gif""
- "".mp4""
- "".mp3""
IncludeEqualFiles: []
IncludeStartFiles: []
IncludeEndFiles: []
CodeSuffixDic:
"".cs"": ""cs""
"".csproj"": ""csproj""
"".http"": ""http""
"".bat"": ""sh""
"".ps1"": ""sh""
"".py"": ""py""
"".js"": ""js""
"".ts"": ""ts""
"".cpp"": ""cpp""
"".c"": ""c""
"".json"": ""json""
"".sln"": ""xml""
"".config"": ""config""
"".xaml"": ""xml""
CodeToMarkDownExtension:
- "".txt""
- "".log""
- "".ini""
- "".conf""
- "".cfg""
- "".toml""
- "".yml""
- "".yaml""
- "".json""
- "".xml""
- "".properties""
- "".c""
- "".cpp""
- "".h""
- "".hpp""
- "".cs""
- "".java""
- "".js""
- "".ts""
- "".py""
- "".rb""
- "".php""
- "".go""
- "".rs""
- "".swift""
- "".m""
- "".mm""
- "".scala""
- "".groovy""
- "".pl""
- "".pm""
- "".sh""
- "".bat""
- "".cmd""
- "".ps1""
- "".html""
- "".htm""
- "".css""
- "".markdown""
- "".rst""
- "".sql""
- "".graphql""
- "".sln""
- "".csproj""
- "".vbproj""
- "".fsproj""
- "".gradle""
- "".pom.xml""
- "".gemspec""
- "".npmrc""
- "".yarnrc""
- "".package.json""
- "".cabal""
- "".opam""
- "".pubspec.yaml""
- "".rst""
- "".tex""
- "".gitignore""
- "".editorconfig""
- "".dockerfile""
- "".env""
- "".class""
- "".asm""
- "".ada""
- "".pas""
- "".bas""
- "".xaml""
- "".axaml""
- "".manifest""
- "".config""
- "".qwenignore""";
}
}
CodingTookit\src\CopyFileV2\Config.cs
using Microsoft.Extensions.Configuration;
public class Config
{
private readonly string _srcPath;
private readonly string _code2mdConfigFolder;
private readonly string _code2mdConfigPath;
private IConfigurationRoot _configurationRoot = null!;
public List<string> ExcludeEqualDirs { get; set; } = null!;
public List<string> ExcludeStartDirs { get; set; } = null!;
public List<string> ExcludeEndDirs { get; set; } = null!;
public List<string> IncludeEqualDirs { get; set; } = null!;
public List<string> IncludeStartDirs { get; set; } = null!;
public List<string> IncludeEndDirs { get; set; } = null!;
public List<string> ExcludeEqualFiles { get; set; } = null!;
public List<string> ExcludeStartFiles { get; set; } = null!;
public List<string> ExcludeEndFiles { get; set; } = null!;
public List<string> IncludeEqualFiles { get; set; } = null!;
public List<string> IncludeStartFiles { get; set; } = null!;
public List<string> IncludeEndFiles { get; set; } = null!;
public List<string> CodeToMarkDownExtension { get; set; } = null!;
public Dictionary<string, string> CodeSuffixMap { get; set; } = null!;
public string DstBackFolder { get; set; } = null!;
public Config(string srcPath)
{
_srcPath = srcPath;
_code2mdConfigFolder = Path.Combine(_srcPath, ".vscode");
_code2mdConfigPath = Path.Combine(_srcPath, ".vscode", "code2md.yaml");
}
public bool CheckCode2mdConfig()
{
if (!Directory.Exists(_code2mdConfigFolder))
{
Directory.CreateDirectory(_code2mdConfigFolder);
}
if (!Path.Exists(_code2mdConfigPath))
{
Console.WriteLine($"无配置文件 : {_code2mdConfigPath} , 已生成配置文件,然后返回");
File.WriteAllText(_code2mdConfigPath, GenerateCode2mdConfigYaml(), System.Text.Encoding.UTF8);
return false;
}
return true;
}
public void LoadConfig()
{
_configurationRoot = new ConfigurationBuilder().SetBasePath(_srcPath).AddYamlFile(_code2mdConfigPath, optional: true, reloadOnChange: true).Build();
ExcludeEqualDirs = GetConfigList("ExcludeEqualDirs");
ExcludeStartDirs = GetConfigList("ExcludeStartDirs");
ExcludeEndDirs = GetConfigList("ExcludeEndDirs");
IncludeEqualDirs = GetConfigList("IncludeEqualDirs");
IncludeStartDirs = GetConfigList("IncludeStartDirs");
IncludeEndDirs = GetConfigList("IncludeEndDirs");
ExcludeEqualFiles = GetConfigList("ExcludeEqualFiles");
ExcludeStartFiles = GetConfigList("ExcludeStartFiles");
ExcludeEndFiles = GetConfigList("ExcludeEndFiles");
IncludeEqualFiles = GetConfigList("IncludeEqualFiles");
IncludeStartFiles = GetConfigList("IncludeStartFiles");
IncludeEndFiles = GetConfigList("IncludeEndFiles");
CodeToMarkDownExtension = GetConfigList("CodeToMarkDownExtension");
CodeSuffixMap = GetConfigMap("CodeSuffixDic");
var dstBackFolder = GetConfigValue("DstBackFolder");
if (string.IsNullOrEmpty(dstBackFolder))
{
string? v = Path.GetDirectoryName(_srcPath);
if (string.IsNullOrEmpty(v))
{
throw new Exception($"无法获取当前项目的父文件夹 : {_srcPath}");
}
Console.WriteLine($"使用默认的备份文件夹 : {v}");
DstBackFolder = v;
}
else
{
DstBackFolder = dstBackFolder;
}
Directory.CreateDirectory(DstBackFolder);
}
private string? GetConfigValue(string sectionName)
{
return _configurationRoot.GetSection(sectionName).Value;
}
public bool GetExcludeDirFlag(string folderName)
{
return ExcludeEqualDirs.Any(folder => folderName.Equals(folder)) || ExcludeStartDirs.Any(folder => folderName.StartsWith(folder)) || ExcludeEndDirs.Any(folder => folderName.EndsWith(folder));
}
public bool GetIncludeDirFlag(string folderName)
{
return IncludeEqualDirs.Any(folder => folderName.Equals(folder)) || IncludeStartDirs.Any(folder => folderName.StartsWith(folder)) || IncludeEndDirs.Any(folder => folderName.EndsWith(folder));
}
public bool GetExcludeFileFlag(string fileName)
{
return ExcludeEqualFiles.Any(folder => fileName.Equals(folder)) || ExcludeStartFiles.Any(folder => fileName.StartsWith(folder)) || ExcludeEndFiles.Any(folder => fileName.EndsWith(folder));
}
public bool GetIncludeFileFlag(string fileName)
{
return IncludeEqualFiles.Any(folder => fileName.Equals(folder)) || IncludeStartFiles.Any(folder => fileName.StartsWith(folder)) || IncludeEndFiles.Any(folder => fileName.EndsWith(folder));
}
private List<string> GetConfigList(string sectionName)
{
return _configurationRoot.GetSection(sectionName).GetChildren().Select(child => child.Value ?? string.Empty).ToList();
}
private Dictionary<string, string> GetConfigMap(string sectionName)
{
return _configurationRoot.GetSection(sectionName).GetChildren().ToDictionary(e => e.Key, e => e.Value ?? string.Empty);
}
public static string GenerateCode2mdConfigYaml()
{
return @"DstBackFolder: """"
ExcludeEqualDirs:
- ""res""
- ""docs""
- ""note""
- ""config""
- ""Publish""
- "".idea""
- "".vs""
- "".vscode""
- "".git""
- ""zz_pro""
- ""zz_res""
- ""zz_zz""
- ""bin""
- ""zz_config""
- ""zz_note""
- ""zz_cache""
- ""node_modules""
- ""obj""
- ""zz_zz_publish""
- ""zz_zz_pro""
- ""Migrations""
- ""log""
- ""logs""
ExcludeStartDirs: []
ExcludeEndDirs: []
IncludeEqualDirs: []
IncludeStartDirs: []
IncludeEndDirs: []
ExcludeEqualFiles:
- ""zz.bat""
- ""AssemblyInfo.cs""
- ""out.txt""
ExcludeStartFiles:
- ""temp""
ExcludeEndFiles:
- "".xlsx""
- "".doc""
- "".docx""
- "".ppt""
- "".pptx""
- "".pdf""
- "".png""
- "".jpg""
- "".jpeg""
- "".gif""
- "".mp4""
- "".mp3""
IncludeEqualFiles: []
IncludeStartFiles: []
IncludeEndFiles: []
CodeSuffixDic:
"".cs"": ""cs""
"".csproj"": ""csproj""
"".http"": ""http""
"".bat"": ""sh""
"".ps1"": ""sh""
"".py"": ""py""
"".js"": ""js""
"".ts"": ""ts""
"".cpp"": ""cpp""
"".c"": ""c""
"".json"": ""json""
"".sln"": ""xml""
"".config"": ""config""
"".xaml"": ""xml""
CodeToMarkDownExtension:
- "".txt""
- "".log""
- "".ini""
- "".conf""
- "".cfg""
- "".toml""
- "".yml""
- "".yaml""
- "".json""
- "".xml""
- "".properties""
- "".c""
- "".cpp""
- "".h""
- "".hpp""
- "".cs""
- "".java""
- "".js""
- "".ts""
- "".py""
- "".rb""
- "".php""
- "".go""
- "".rs""
- "".swift""
- "".m""
- "".mm""
- "".scala""
- "".groovy""
- "".pl""
- "".pm""
- "".sh""
- "".bat""
- "".cmd""
- "".ps1""
- "".html""
- "".htm""
- "".css""
- "".markdown""
- "".rst""
- "".sql""
- "".graphql""
- "".sln""
- "".csproj""
- "".vbproj""
- "".fsproj""
- "".gradle""
- "".pom.xml""
- "".gemspec""
- "".npmrc""
- "".yarnrc""
- "".package.json""
- "".cabal""
- "".opam""
- "".pubspec.yaml""
- "".rst""
- "".tex""
- "".gitignore""
- "".editorconfig""
- "".dockerfile""
- "".env""
- "".class""
- "".asm""
- "".ada""
- "".pas""
- "".bas""
- "".xaml""
- "".axaml""
- "".manifest""
- "".config""
- "".qwenignore""";
}
}
CodingTookit\src\SqlServerRunner\SqlServerRunner.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
CodingTookit\src\CopyFileV2\Program.cs
using System.Text;
if (args.Length == 0)
{
Console.WriteLine("请传入文件夹路径");
return;
}
if (!Directory.Exists(args[0]))
{
Console.WriteLine($"传入的文件夹不存在 : {args[0]}");
return;
}
string srcPath = args[0];
Console.WriteLine($"============== CopyFile START ==================");
Config config = new Config(srcPath);
bool hasConfig = config.CheckCode2mdConfig();
if (!hasConfig)
{
Console.WriteLine("已生成被配置文件,配置后重新运行");
return;
}
config.LoadConfig();
Console.WriteLine("请输入文件名后缀:");
Console.InputEncoding = Encoding.Unicode;
Console.OutputEncoding = Encoding.Unicode;
string suffix = Console.ReadLine()?.Trim() ?? string.Empty;
var collector = new Collector(srcPath, config, suffix);
await collector.BackupProject();
Console.WriteLine($"============== CopyFile END ==============");
CodingTookit\src\CopyFileV2\Collector.cs
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
public class Collector
{
private ConcurrentQueue<string> _directoryQueue = new ConcurrentQueue<string>();
private ConcurrentQueue<string> _fileQueue = new ConcurrentQueue<string>();
private ManualResetEvent _directoryTraversalFinished = new ManualResetEvent(false);
private ManualResetEvent _allFileProducersFinished = new ManualResetEvent(false);
private int _numDirectoryConsumers;
private int _numFileConsumers;
private int[] _completedDirectoryConsumers = new int[1];
private DateTime _startTime;
private DateTime _endTime;
private TimeSpan _totalTime;
private readonly string _srcPath;
private readonly Config _config;
private readonly string _suffix = string.Empty;
public Collector(string srcPath, Config config, string suffix)
{
_srcPath = srcPath;
_config = config;
_suffix = suffix;
}
public DateTime StartTime => _startTime;
public DateTime EndTime => _endTime;
public TimeSpan TotalTime => _totalTime;
private string _backupFolderName = null!;
public async Task BackupProject()
{
_startTime = DateTime.Now;
_backupFolderName = Path.GetFileName(_srcPath) + $"_{_startTime:yyyyMMdd_HHmmss}_{_suffix}";
InitializeProcessing();
var directoryProducerTask = Task.Run(() => DirectoryProducer(_directoryQueue, _directoryTraversalFinished));
var directoryConsumerTasks = new Task[_numDirectoryConsumers];
for (int i = 0; i < _numDirectoryConsumers; i++)
{
directoryConsumerTasks[i] = Task.Run(() => DirectoryConsumer(_directoryQueue, _fileQueue, _directoryTraversalFinished, _completedDirectoryConsumers, _numDirectoryConsumers, _allFileProducersFinished));
}
var fileConsumerTasks = new Task[_numFileConsumers];
for (int i = 0; i < _numFileConsumers; i++)
{
fileConsumerTasks[i] = Task.Run(() => FileConsumer(_fileQueue, _allFileProducersFinished));
}
await directoryProducerTask;
_directoryTraversalFinished.Set(); // 通知目录遍历已完成
await Task.WhenAll(directoryConsumerTasks);
await Task.WhenAll(fileConsumerTasks);
_endTime = DateTime.Now;
_totalTime = _endTime - _startTime;
}
private void InitializeProcessing()
{
_directoryQueue = new ConcurrentQueue<string>();
_fileQueue = new ConcurrentQueue<string>();
_directoryTraversalFinished.Reset();
_allFileProducersFinished.Reset();
_completedDirectoryConsumers[0] = 0;
_numDirectoryConsumers = Math.Max(1, Environment.ProcessorCount / 4); // 1/4用于目录消费者
_numFileConsumers = Math.Max(1, (3 * Environment.ProcessorCount) / 4); // 3/4用于文件消费者
}
private void DirectoryProducer(ConcurrentQueue<string> directoryQueue, ManualResetEvent directoryTraversalFinished)
{
try
{
var stack = new Stack<string>();
stack.Push(_srcPath);
directoryQueue.Enqueue(_srcPath);
while (stack.Count > 0)
{
string currentDir = stack.Pop();
string[] subDirs;
try
{
subDirs = Directory.GetDirectories(currentDir, "*.*", SearchOption.TopDirectoryOnly);
}
catch (UnauthorizedAccessException)
{
continue;
}
foreach (string dir in subDirs)
{
string dirName = Path.GetFileName(dir);
if (_config.GetExcludeDirFlag(dirName) && !_config.GetIncludeDirFlag(dirName))
{
continue;
}
stack.Push(dir);
directoryQueue.Enqueue(dir);
}
}
}
finally
{
directoryTraversalFinished.Set();
}
}
public List<string> GetAllLevelDirectories()
{
var result = new List<string>();
var stack = new Stack<string>();
stack.Push(_srcPath);
while (stack.Count > 0)
{
string currentDir = stack.Pop();
string[] subDirs;
try
{
subDirs = Directory.GetDirectories(currentDir, "*.*", SearchOption.TopDirectoryOnly);
}
catch (UnauthorizedAccessException)
{
continue;
}
foreach (string dir in subDirs)
{
string dirName = Path.GetFileName(dir);
if (_config.GetExcludeDirFlag(dirName) && !_config.GetIncludeDirFlag(dirName))
{
continue;
}
result.Add(dir);
stack.Push(dir);
}
}
return result;
}
public static List<string> GetAllDirectories(string rootPath, HashSet<string> excludeFolders)
{
ArgumentNullException.ThrowIfNull(rootPath);
ArgumentNullException.ThrowIfNull(excludeFolders);
var result = new List<string>();
var stack = new Stack<string>();
stack.Push(rootPath);
while (stack.Count > 0)
{
string currentDir = stack.Pop();
string[] subDirs;
try
{
subDirs = Directory.GetDirectories(currentDir, "*", SearchOption.TopDirectoryOnly);
}
catch (UnauthorizedAccessException)
{
continue;
}
catch (DirectoryNotFoundException)
{
continue;
}
foreach (string dir in subDirs)
{
string dirName = GetDirectoryName(dir);
if (!excludeFolders.Contains(dirName))
{
result.Add(dir);
stack.Push(dir);
}
}
}
return result;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static string GetDirectoryName(string path)
{
int separatorIndex = path.LastIndexOf(Path.DirectorySeparatorChar);
return separatorIndex >= 0 ? path[(separatorIndex + 1)..] : path;
}
private void DirectoryConsumer(ConcurrentQueue<string> directoryQueue, ConcurrentQueue<string> fileQueue, ManualResetEvent directoryTraversalFinished, int[] completedDirectoryConsumers, int totalDirectoryConsumers, ManualResetEvent allFileProducersFinished)
{
bool keepProcessing = true;
while (keepProcessing)
{
if (directoryQueue.TryDequeue(out string? dirPath))
{
try
{
var files = Directory.GetFiles(dirPath, "*", SearchOption.TopDirectoryOnly);
foreach (var file in files)
{
string fileName = Path.GetFileName(file);
if (_config.GetExcludeFileFlag(fileName) && !_config.GetIncludeFileFlag(fileName))
{
continue;
}
fileQueue.Enqueue(file);
}
}
catch (UnauthorizedAccessException)
{
continue;
}
}
else
{
if (directoryTraversalFinished.WaitOne(0) && directoryQueue.IsEmpty)
{
keepProcessing = false;
}
else
{
Thread.Sleep(10);
}
}
}
if (Interlocked.Increment(ref completedDirectoryConsumers[0]) == totalDirectoryConsumers)
{
allFileProducersFinished.Set();
}
}
private void FileConsumer(ConcurrentQueue<string> fileQueue, ManualResetEvent allFileProducersFinished)
{
bool keepProcessing = true;
while (keepProcessing)
{
if (fileQueue.TryDequeue(out string? filePath))
{
string relativePath = Path.GetRelativePath(_srcPath, filePath);
string dstCodePath = Path.Combine(_config.DstBackFolder, _backupFolderName, relativePath);
string? dirPath = Path.GetDirectoryName(dstCodePath);
if (!string.IsNullOrEmpty(dirPath))
{
Directory.CreateDirectory(dirPath);
}
CopyFile(filePath, dstCodePath);
}
else
{
if (allFileProducersFinished.WaitOne(0) && fileQueue.IsEmpty)
{
keepProcessing = false;
}
else
{
Thread.Sleep(10);
}
}
}
}
private static void CopyFile(string srcPath, string dstPath, int maxRetries = 3)
{
int retries = 0;
while (true)
{
try
{
File.Copy(srcPath, dstPath, false);
System.Console.WriteLine(srcPath + "=>" + dstPath);
if (!File.Exists(dstPath))
{
throw new IOException("文件复制后不存在于目标位置");
}
break;
}
catch (Exception ex)
{
retries++;
if (retries > maxRetries)
{
Console.WriteLine($"文件移动失败 ({srcPath} : {ex.Message}");
throw;
}
Thread.Sleep(500 * retries);
}
}
}
}
CodingTookit\old\CopyFile\Program.cs
using System.Collections.Concurrent;
using System.Diagnostics;
public class Program
{
private static string SourceDirectory = string.Empty;
private static string DstFolderPath = string.Empty;
private static string SourceDirectoryBakPath = string.Empty;
private static string DirectorySuffix = string.Empty;
private static readonly DateTime Now = DateTime.Now;
private static readonly List<string> ExcludedEqualDirectories = new List<string> { "bin", "obj", "npm_modules", ".git", "Publish" };
private static readonly BlockingCollection<CopyFileTask> BackupCollection = new BlockingCollection<CopyFileTask>();
private static readonly ConcurrentDictionary<string, object> DirectoryLocks = new ConcurrentDictionary<string, object>();
private static readonly CancellationTokenSource CancellationTokenSource = new CancellationTokenSource();
static void Main(string[] args)
{
try
{
Console.WriteLine("正在扫描文件...");
System.Console.WriteLine("输入文件夹后缀:");
DirectorySuffix = System.Console.ReadLine() ?? string.Empty;
if (args.Length == 0)
{
System.Console.WriteLine("请传入文件夹路径");
return;
}
SourceDirectory = args[0];
if (!Directory.Exists(SourceDirectory))
{
Console.WriteLine($"错误: 源目录 {SourceDirectory} 不存在。");
return;
}
System.Console.WriteLine("请输入目标文件夹:");
DstFolderPath = System.Console.ReadLine() ?? string.Empty;
if (DstFolderPath == string.Empty)
return;
SourceDirectoryBakPath = Path.GetFileName(SourceDirectory) + $"_{Now:yyyyMMdd_HHmmss}_{DirectorySuffix}";
Stopwatch stopwatch = new Stopwatch();
stopwatch.Start();
var producerTask = Task.Run(() =>
{
try
{
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 };
Parallel.ForEach(
Directory.EnumerateDirectories(SourceDirectory),
options,
(dirPath) =>
{
ScanDirectory(dirPath);
}
);
GetFiles(SourceDirectory);
}
finally
{
BackupCollection.CompleteAdding();
}
});
Console.WriteLine("扫描已启动,开始并行处理文件...");
const int maxThreads = 8;
var backupTasks = new Task[maxThreads];
for (int i = 0; i < maxThreads; i++)
{
backupTasks[i] = Task.Run(() => CodeBackup(CancellationTokenSource.Token));
}
Task.WaitAll(backupTasks);
stopwatch.Stop();
Console.WriteLine($"处理完成,共耗时 {stopwatch.Elapsed.TotalSeconds} s");
}
catch (Exception ex)
{
Console.WriteLine($"\n发生致命错误: {ex.Message}");
}
finally
{
CancellationTokenSource.Cancel();
}
Console.WriteLine("============备份完成============");
}
private static bool FilterFolder(string dirPath)
{
var dirName = Path.GetFileName(dirPath);
var excludedSet = new HashSet<string>(ExcludedEqualDirectories, StringComparer.OrdinalIgnoreCase);
return !excludedSet.Contains(dirName);
}
private static void ScanDirectory(string currentPath)
{
if (!FilterFolder(currentPath))
return;
try
{
GetFiles(currentPath);
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 2 };
Parallel.ForEach(
Directory.EnumerateDirectories(currentPath),
options,
(subDirectory) =>
{
ScanDirectory(subDirectory); // 递归调用
}
);
}
catch (IOException ex)
{
Console.WriteLine($"IOException ex: {ex.Message}");
}
catch (UnauthorizedAccessException ex)
{ /* 忽略无权限目录 */
System.Console.WriteLine($"UnauthorizedAccessException ex: {ex.Message} ");
}
catch (Exception ex)
{
Console.WriteLine($"\n扫描目录时出错 ({currentPath}): {ex.Message}");
}
}
private static void GetFiles(string sourcePath)
{
var files = Directory.GetFiles(sourcePath, "*", SearchOption.TopDirectoryOnly);
foreach (string filePath in files)
{
string relativePath = Path.GetRelativePath(SourceDirectory, filePath);
string dstCodePath = Path.Combine(DstFolderPath, SourceDirectoryBakPath, relativePath);
EnsureDirectoryExists(Path.GetDirectoryName(dstCodePath)!);
var task = new CopyFileTask { CodePath = filePath, DstCodePath = dstCodePath };
BackupCollection.Add(task);
}
}
private static void CodeBackup(CancellationToken cancellationToken)
{
try
{
foreach (var copyFileTask in BackupCollection.GetConsumingEnumerable(cancellationToken))
{
try
{
CopyFile(copyFileTask);
}
catch (Exception ex)
{
Console.WriteLine($"\n处理文件时出错 ({copyFileTask.CodePath}): {ex.Message}");
}
}
}
catch (OperationCanceledException)
{
System.Console.WriteLine("\n文件处理已取消。");
}
}
private static void CopyFile(CopyFileTask code2mdTask, int maxRetries = 3)
{
int retries = 0;
while (true)
{
try
{
string codePath = code2mdTask.CodePath;
string dstCodePath = code2mdTask.DstCodePath;
File.Copy(codePath, dstCodePath, false);
System.Console.WriteLine(codePath + "=>" + dstCodePath);
if (!File.Exists(dstCodePath))
{
throw new IOException("文件复制后不存在于目标位置");
}
break;
}
catch (Exception ex)
{
retries++;
if (retries > maxRetries)
{
Console.WriteLine($"文件移动失败 ({code2mdTask.CodePath} : {ex.Message}");
throw;
}
Thread.Sleep(500 * retries);
}
}
}
private static void EnsureDirectoryExists(string directoryPath)
{
if (Directory.Exists(directoryPath))
return;
object dirLock = DirectoryLocks.GetOrAdd(directoryPath, _ => new object());
if (!Directory.Exists(directoryPath))
{
if (Directory.Exists(directoryPath))
return;
lock (dirLock)
{
Directory.CreateDirectory(directoryPath);
}
}
}
}
public class CopyFileTask
{
public required string CodePath { get; set; }
public required string DstCodePath { get; set; }
}
CodingTookit\.csharpierrc.json
{
"printWidth": 300,
"useTabs": false,
"tabWidth": 4,
"endOfLine": "auto"
}
CodingTookit\old\CopyFile\CopyFile.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net9.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
CodingTookit\README.md_# CodingTookit
Code2md
说明
convert code project to one markdown file.
发布
dotnet publish .\src\Code2md\Code2md.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
dotnet publish .\src\Code2md\Code2md.csproj -c Release -r linux-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
部署脚本
Windows
@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\Code2md.exe "%scriptPath%"
@echo off
set "scriptPath=%cd%"
D: && cd D:\Code2Md\Code2md\bin\Debug\net9.0\ && D:\Code2Md\Code2md\bin\Debug\net9.0\Code2md.exe "%scriptPath%"
Linux
#!/bin/bash
_`# 1. 获取当前工作目录(对应bat的%cd%)`
scriptPath=$PWD
_`# 2. 替换为你Linux下Code2md程序的实际路径(关键!需修改)`
_`# 原bat路径:D:\Code2Md\Publish\Code2md\V2.0.0\Code2md.exe`
_`# 示例Linux路径(请替换为你实际的发布路径):`
program_path="D:\CodingTookit\src\Code2md\bin\Release\net9.0\linux-x64\publish\Code2md"
_`# 3. 执行程序,传递当前目录作为参数`
if [ -f "$program_path" ]; then
_` # 执行程序并传递参数`
"$program_path" "$scriptPath"
else
_` # 程序文件不存在时提示`
echo "错误:未找到Code2md程序,请检查路径是否正确!"
echo "当前配置的程序路径:$program_path"
exit 1
fi
CopyFileV2
说明
copy code project to dst folder.
发布
dotnet publish .\src\CopyFileV2\CopyFileV2.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
部署脚本
Windows
@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\CopyFileV2\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\CopyFileV2\bin\Release\net9.0\win-x64\publish\Code2mdV2.exe "%scriptPath%"
Linux
LatestSqlFinder
说明
find latest sql file.
发布
dotnet publish .\src\LatestSqlFinder\LatestSqlFinder.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
部署脚本
Windows
@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\LatestSqlFinder\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\LatestSqlFinder\bin\Release\net9.0\win-x64\publish\LatestSqlFinder.exe "%scriptPath%"
SqlServerRunner
说明
active sql server management studio
发布
dotnet publish .\src\SqlServerRunner\SqlServerRunner.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
部署脚本
Windows
@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\SqlServerRunner\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\SqlServerRunner\bin\Release\net9.0\win-x64\publish\SqlServerRunner.exe "%scriptPath%"
Md2code
说明
convert markdown to code project.
发布
dotnet publish .\src\Md2code\Md2code.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
dotnet publish .\src\Md2code\Md2code.csproj -c Release -r linux-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
部署脚本
Windows
@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\Code2md\bin\Release\net9.0\win-x64\publish\Code2md.exe "%scriptPath%"
@echo off
set "scriptPath=%cd%"
D: && cd D:\Code2Md\Code2md\bin\Debug\net9.0\ && D:\Code2Md\Code2md\bin\Debug\net9.0\Code2md.exe "%scriptPath%"
Linux
#!/bin/bash
_`# 1. 获取当前工作目录(对应bat的%cd%)`
scriptPath=$PWD
_`# 2. 替换为你Linux下Code2md程序的实际路径(关键!需修改)`
_`# 原bat路径:D:\Code2Md\Publish\Code2md\V2.0.0\Code2md.exe`
_`# 示例Linux路径(请替换为你实际的发布路径):`
program_path="D:\CodingTookit\src\Code2md\bin\Release\net9.0\linux-x64\publish\Code2md"
_`# 3. 执行程序,传递当前目录作为参数`
if [ -f "$program_path" ]; then
_` # 执行程序并传递参数`
"$program_path" "$scriptPath"
else
_` # 程序文件不存在时提示`
echo "错误:未找到Code2md程序,请检查路径是否正确!"
echo "当前配置的程序路径:$program_path"
exit 1
fi
Wrap
说明
copy content
发布
dotnet publish .\src\Warp\Warp.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true
_`# dotnet publish .\src\Md2code\Md2code.csproj -c Release -r linux-x64 --self-contained true /p:PublishSingleFile=true /p:IncludeNativeLibrariesForSelfExtract=true`
部署脚本
Windows
@echo off
set "scriptPath=%cd%"
D: && cd D:\CodingTookit\src\Warp\bin\Release\net9.0\win-x64\publish\ && D:\CodingTookit\src\Warp\bin\Release\net9.0\win-x64\publish\Warp.exe "%scriptPath%"
CodingTookit\CLAUDE.md_# CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Project Overview
CodingTookit is a .NET developer utility toolkit with two main components:
- Code2md (
src/Code2md/): Converts code projects into a single consolidated Markdown document with syntax highlighting - CopyFileV2 (
src/CopyFileV2/): Parallel file backup tool for duplicating projects
Both tools share the same configuration system (.vscode/code2md.yaml) for filtering files/directories.
Build Commands
_`# Build projects`
dotnet build ./src/Code2md/Code2md.csproj -c Debug
dotnet build ./src/CopyFileV2/CopyFileV2.csproj -c Debug
_`# Publish self-contained executables`
dotnet publish ./src/Code2md/Code2md.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true
dotnet publish ./src/Code2md/Code2md.csproj -c Release -r linux-x64 --self-contained true /p:PublishSingleFile=true
dotnet publish ./src/CopyFileV2/CopyFileV2.csproj -c Release -r win-x64 --self-contained true /p:PublishSingleFile=true
_`# Run directly`
dotnet run --project ./src/Code2md/Code2md.csproj -- "/path/to/project"
dotnet run --project ./src/CopyFileV2/CopyFileV2.csproj -- "/path/to/project"
Configuration System
Both tools use .vscode/code2md.yaml for filtering:
DstBackFolder: Backup destination for CopyFileV2ExcludeEqualDirs/ExcludeStartDirs/ExcludeEndDirs: Directory exclusion rulesExcludeEqualFiles/ExcludeStartFiles/ExcludeEndFiles: File exclusion rulesCodeSuffixDic: Maps file extensions to markdown code block languagesCodeToMarkDownExtension: File types to include as code blocks
Key default exclusions:bin,obj,.git,.vs,.vscode,node_modules,zz_zz
Architecture
- Code2md: Entry point (
Program.cs) → Project scanner (Project.cs) → Markdown generation - CopyFileV2: Uses concurrent queues with parallel consumer threads for fast file copying
Both useMicrosoft.Extensions.Configurationwith YAML provider for config management.
浙公网安备 33010602011771号