Skip to content

Commit d09875d

Browse files
committed
init
1 parent 08bc696 commit d09875d

File tree

5 files changed

+504
-1
lines changed

5 files changed

+504
-1
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
*.userosscache
1111
*.sln.docstates
1212
*.env
13+
deploy.bat
1314

1415
# User-specific files (MonoDevelop/Xamarin Studio)
1516
*.userprefs

PreCoding.csproj

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<Version>1.0.0</Version>
5+
<AssemblyVersion>1.0.0.0</AssemblyVersion>
6+
<Authors>HEHENG Trading Company</Authors>
7+
<Company>HEHENG Trading Company</Company>
8+
<OutputType>Exe</OutputType>
9+
<TargetFramework>net8.0</TargetFramework>
10+
<ImplicitUsings>enable</ImplicitUsings>
11+
<Nullable>enable</Nullable>
12+
</PropertyGroup>
13+
14+
<ItemGroup>
15+
<PackageReference Include="TextCopy" Version="6.2.1" />
16+
</ItemGroup>
17+
18+
</Project>

PreCoding.sln

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
Microsoft Visual Studio Solution File, Format Version 12.00
2+
# Visual Studio Version 17
3+
VisualStudioVersion = 17.5.2.0
4+
MinimumVisualStudioVersion = 10.0.40219.1
5+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PreCoding", "PreCoding.csproj", "{15BA6467-5A34-19B2-C9AE-9E49C5FCCDEC}"
6+
EndProject
7+
Global
8+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
9+
Debug|Any CPU = Debug|Any CPU
10+
Release|Any CPU = Release|Any CPU
11+
EndGlobalSection
12+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
13+
{15BA6467-5A34-19B2-C9AE-9E49C5FCCDEC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
14+
{15BA6467-5A34-19B2-C9AE-9E49C5FCCDEC}.Debug|Any CPU.Build.0 = Debug|Any CPU
15+
{15BA6467-5A34-19B2-C9AE-9E49C5FCCDEC}.Release|Any CPU.ActiveCfg = Release|Any CPU
16+
{15BA6467-5A34-19B2-C9AE-9E49C5FCCDEC}.Release|Any CPU.Build.0 = Release|Any CPU
17+
EndGlobalSection
18+
GlobalSection(SolutionProperties) = preSolution
19+
HideSolutionNode = FALSE
20+
EndGlobalSection
21+
GlobalSection(ExtensibilityGlobals) = postSolution
22+
SolutionGuid = {3E5E6D11-FF01-45A1-8179-3EFEF115F0C4}
23+
EndGlobalSection
24+
EndGlobal

Program.cs

Lines changed: 342 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,342 @@
1+
using System.Diagnostics;
2+
using System.Reflection;
3+
using System.Text;
4+
using TextCopy;
5+
6+
7+
namespace PreCoding
8+
{
9+
class Program
10+
{
11+
static void Main(string[] args)
12+
{
13+
// Get the path to the running EXE
14+
var metadata = GetExeMetadata();
15+
Console.WriteLine($"PreCoding Tool [Version: {metadata.appVersion}]");
16+
Console.WriteLine($"Author: {metadata.companyName}");
17+
Console.WriteLine($"License: GPLv3");
18+
Console.WriteLine($"Build: {metadata.lastWriteTime}");
19+
Console.WriteLine($"Ensure your source code files are UTF-8 encoded.\n");
20+
21+
string targetDirectory = Directory.GetCurrentDirectory();
22+
//string targetDirectory = @"C:\Users\shawhu\ProjectC\heheng\hehengclient";
23+
24+
bool fileListMode = (args.Length > 0 && args[0].Equals("-files", StringComparison.OrdinalIgnoreCase));
25+
bool helpMode = (args.Length > 0 && args[0].Equals("-help", StringComparison.OrdinalIgnoreCase));
26+
string[] fileList = [];
27+
28+
if (helpMode)
29+
{
30+
Console.WriteLine("Usages examples:");
31+
Console.WriteLine("1. Specify file search patterns:");
32+
Console.WriteLine("precoding.exe -files file1.cs file2.json ...");
33+
Console.WriteLine();
34+
Console.WriteLine("Specify targetDir");
35+
Console.WriteLine("precoding.exe <targetDir>");
36+
Console.WriteLine();
37+
Console.WriteLine("it will search the currentDir with default search patterns");
38+
Console.WriteLine("precoding.exe");
39+
Console.WriteLine();
40+
return;
41+
}
42+
if (fileListMode)
43+
{
44+
// ADDED: File list mode, get list of files after the -files argument
45+
if (args.Length < 2)
46+
{
47+
Console.WriteLine("Usage: precoding.exe -files file1.cs file2.json ...");
48+
return;
49+
}
50+
fileList = args.Skip(1).ToArray(); // CORRECT: this gets all arguments after -files
51+
}
52+
else if (args.Length > 0)
53+
{
54+
targetDirectory = args[0];
55+
}
56+
57+
Console.WriteLine("========== File Aggregation Started ==========");
58+
if (!Directory.Exists(targetDirectory))
59+
{
60+
Console.WriteLine($"[ERROR] Target directory does not exist: {targetDirectory}");
61+
62+
return;
63+
}
64+
65+
// Folders to ignore (case-insensitive)
66+
var ignoredFolderNames = new HashSet<string>(new[] {
67+
"node_modules",
68+
"Migrations",
69+
"obj",
70+
"app-example",
71+
"staticdata",
72+
"docs"
73+
}, StringComparer.OrdinalIgnoreCase);
74+
75+
// File patterns to search
76+
string[] searchPatterns;
77+
if (fileListMode)
78+
{
79+
// CHANGED: Use exact filenames as searchPatterns
80+
searchPatterns = fileList;
81+
}
82+
else
83+
{
84+
searchPatterns = new[] {
85+
"*.cs",
86+
"*.tsx",
87+
"*.ts",
88+
"package.json",
89+
"*.csproj"
90+
};
91+
}
92+
93+
// Printout the criteria
94+
Console.WriteLine($"Mode: {(fileListMode ? "File List" : "Pattern Search")}");
95+
Console.WriteLine($"Search Targets: {string.Join(", ", searchPatterns)}");
96+
Console.WriteLine($"Ignored Folders: {string.Join(", ", ignoredFolderNames)}");
97+
98+
// Find all files, skipping hidden, ignored, and dot-prefixed folders/files
99+
var files = GetFilesSkippingFolders(targetDirectory, searchPatterns, ignoredFolderNames)
100+
.Distinct()
101+
.OrderBy(f => f)
102+
.ToList();
103+
104+
if (!files.Any())
105+
{
106+
Console.WriteLine("No matching source files found. Exiting.");
107+
Console.WriteLine("========== Aggregation Complete ==============");
108+
109+
return;
110+
}
111+
112+
StringBuilder output = new StringBuilder();
113+
StringBuilder error = new StringBuilder();
114+
string templatePath = Path.Combine(AppContext.BaseDirectory ?? Directory.GetCurrentDirectory(), "prompt_header.md");
115+
if (File.Exists(templatePath))
116+
{
117+
output.AppendLine(File.ReadAllText(templatePath));
118+
}
119+
else
120+
{
121+
output.AppendLine("## Instructions:");
122+
output.AppendLine("1. **Code-First Replies:** Always respond with a code block containing the exact code (method, function, or class) to be replaced or inserted.");
123+
output.AppendLine(" - For long files, include only the full method/function/class that is being changed.");
124+
output.AppendLine("2. **Clear Change Comments:** Clearly mark your changes using `// CHANGED`, `// ADDED`, `// REMOVED`, etc.");
125+
output.AppendLine("3. **No Redundant Suggestions:** Double-check my code and **do not suggest fixes for issues already handled**.");
126+
output.AppendLine("4. **Prefer Inline Solutions:** Use concise, inline code when possible. Avoid multiple lines for changes that can be made in one.");
127+
output.AppendLine("5. **Be Accurate, Direct, and Minimal:**");
128+
output.AppendLine(" - Do not add extra features or explanations unless requested.");
129+
output.AppendLine(" - Provide only code and necessary comments.");
130+
output.AppendLine("6. **Reference the Provided Codebase:** Use the code files and their filenames below as context for your responses.");
131+
output.AppendLine();
132+
output.AppendLine("## Below are all the source code files for reference:");
133+
}
134+
135+
foreach (var file in files)
136+
{
137+
try
138+
{
139+
string filetype = GetFileType(file);
140+
string relativePath = Path.GetRelativePath(targetDirectory, file);
141+
output.AppendLine($"### --- FILENAME: {relativePath} ---");
142+
output.AppendLine($"```{filetype}");
143+
string content = File.ReadAllText(file, Encoding.UTF8);
144+
output.AppendLine(content);
145+
output.AppendLine("```");
146+
}
147+
catch (Exception ex)
148+
{
149+
error.AppendLine($"ERROR reading {file}: {ex.Message} ---");
150+
error.AppendLine();
151+
}
152+
}
153+
154+
// Output file
155+
string outputStr = output.ToString();
156+
string outputFile = Path.Combine(targetDirectory, "AllSourceFiles.txt");
157+
File.WriteAllText(outputFile, outputStr, Encoding.UTF8);
158+
159+
// Get file size in MB
160+
FileInfo fi = new FileInfo(outputFile);
161+
double sizeInMb = fi.Length / (1024.0 * 1024.0);
162+
Console.WriteLine($"Completed! Aggregated {files.Count} files.");
163+
Console.WriteLine($"Output written to: {outputFile} [{sizeInMb:F2} MB]");
164+
if (sizeInMb <= 1)
165+
Console.WriteLine("Output copied to clipboard.");
166+
else
167+
Console.WriteLine("Output too large for clipboard; only written to file.");
168+
Console.WriteLine("========== Aggregation Complete ==============");
169+
170+
// Copy to clipboard
171+
if (sizeInMb <= 1) ClipboardService.SetText(outputStr);
172+
else Console.WriteLine($"Output file is too big, skipping automatic clipboard copying.");
173+
174+
//if error
175+
if (!string.IsNullOrWhiteSpace(error.ToString()))
176+
Console.WriteLine("[WARN] Some files could not be read:\n" + error.ToString());
177+
178+
179+
}
180+
181+
static IEnumerable<string> GetFilesSkippingFolders(
182+
string rootPath,
183+
string[] searchPatterns,
184+
HashSet<string> ignoredFolderNames
185+
)
186+
{
187+
var dirs = new Stack<DirectoryInfo>();
188+
dirs.Push(new DirectoryInfo(rootPath));
189+
190+
while (dirs.Count > 0)
191+
{
192+
DirectoryInfo currentDir = dirs.Pop();
193+
194+
// Skip hidden directories
195+
if ((currentDir.Attributes & FileAttributes.Hidden) != 0)
196+
continue;
197+
198+
// Skip ignored directories by name (e.g., node_modules)
199+
if (ignoredFolderNames.Contains(currentDir.Name))
200+
continue;
201+
202+
// Skip directories that start with a dot (.)
203+
if (currentDir.Name.StartsWith("."))
204+
continue;
205+
206+
// Get files for each pattern
207+
foreach (var pattern in searchPatterns)
208+
{
209+
FileInfo[] files = [];
210+
try
211+
{
212+
files = currentDir.GetFiles(pattern, SearchOption.TopDirectoryOnly);
213+
}
214+
catch
215+
{
216+
// Could not access this directory, skip
217+
continue;
218+
}
219+
220+
foreach (var file in files)
221+
{
222+
// Skip dot-prefixed files
223+
if (file.Name.StartsWith("."))
224+
continue;
225+
226+
yield return file.FullName;
227+
}
228+
}
229+
230+
// Push subdirectories that are not hidden, not ignored, and not dot-starting
231+
DirectoryInfo[] subDirs = [];
232+
try
233+
{
234+
subDirs = currentDir.GetDirectories();
235+
}
236+
catch
237+
{
238+
continue;
239+
}
240+
241+
foreach (var subDir in subDirs)
242+
{
243+
if ((subDir.Attributes & FileAttributes.Hidden) == 0 &&
244+
!ignoredFolderNames.Contains(subDir.Name) &&
245+
!subDir.Name.StartsWith("."))
246+
{
247+
dirs.Push(subDir);
248+
}
249+
}
250+
}
251+
}
252+
253+
static string GetFileType(string file)
254+
{
255+
var extension = Path.GetExtension(file).ToLowerInvariant();
256+
var typeMap = new Dictionary<string, string>
257+
{ { ".bat", "bat" },
258+
{ ".c", "c" },
259+
{ ".cc", "cpp" },
260+
{ ".cmd", "bat" },
261+
{ ".cpp", "cpp" },
262+
{ ".cs", "csharp" },
263+
{ ".css", "css" },
264+
{ ".dart", "dart" },
265+
{ ".diff", "diff" },
266+
{ ".env", "env" },
267+
{ ".go", "go" },
268+
{ ".graphql", "graphql" },
269+
{ ".gql", "graphql" },
270+
{ ".h", "cpp" },
271+
{ ".htm", "html" },
272+
{ ".html", "html" },
273+
{ ".ini", "ini" },
274+
{ ".java", "java" },
275+
{ ".jl", "julia" },
276+
{ ".js", "javascript" },
277+
{ ".json", "json" },
278+
{ ".kt", "kotlin" },
279+
{ ".kts", "kotlin" },
280+
{ ".latex", "latex" },
281+
{ ".lisp", "lisp" },
282+
{ ".lsp", "lisp" },
283+
{ ".lua", "lua" },
284+
{ ".md", "markdown" },
285+
{ ".mjs", "javascript" },
286+
{ ".php", "php" },
287+
{ ".pl", "perl" },
288+
{ ".pm", "perl" },
289+
{ ".properties", "properties" },
290+
{ ".ps1", "powershell" },
291+
{ ".psm1", "powershell" },
292+
{ ".py", "python" },
293+
{ ".pyw", "python" },
294+
{ ".r", "r" },
295+
{ ".rb", "ruby" },
296+
{ ".rs", "rust" },
297+
{ ".scala", "scala" },
298+
{ ".sh", "bash" },
299+
{ ".sql", "sql" },
300+
{ ".swift", "swift" },
301+
{ ".tex", "latex" },
302+
{ ".toml", "toml" },
303+
{ ".ts", "typescript" },
304+
{ ".tsx", "typescript" },
305+
{ ".txt", "plaintext" },
306+
{ ".xml", "xml" },
307+
{ ".yml", "yaml" },
308+
{ ".yaml", "yaml" }
309+
};
310+
311+
return typeMap.TryGetValue(extension, out var type) ? type : "";
312+
}
313+
314+
static (string exePath, string appVersion, string companyName, DateTime lastWriteTime) GetExeMetadata()
315+
{
316+
string exePath = Process.GetCurrentProcess().MainModule?.FileName ?? "";
317+
DateTime lastWriteTime = DateTime.MinValue;
318+
string appVersion = "Unknown";
319+
string companyName = "Unknown";
320+
321+
// Get assembly info from the file itself (EXE)
322+
if (!string.IsNullOrEmpty(exePath) && File.Exists(exePath))
323+
{
324+
try
325+
{
326+
var assembly = Assembly.LoadFrom(exePath);
327+
appVersion = assembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()?.InformationalVersion ?? "Unknown";
328+
companyName = assembly.GetCustomAttribute<AssemblyCompanyAttribute>()?.Company ?? "Unknown";
329+
}
330+
catch
331+
{
332+
// fallback: try FileVersionInfo
333+
var fvi = FileVersionInfo.GetVersionInfo(exePath);
334+
appVersion = fvi.ProductVersion ?? "Unknown";
335+
companyName = fvi.CompanyName ?? "Unknown";
336+
}
337+
lastWriteTime = File.GetLastWriteTime(exePath);
338+
}
339+
return (exePath, appVersion, companyName, lastWriteTime);
340+
}
341+
}
342+
}

0 commit comments

Comments
 (0)