Skip to content

Commit ee2e5b1

Browse files
VaclavEliasikpil
authored andcommitted
feat: Add comment converter project and processing logic
- Created the project file `Box2D.NET.CommentConverter.csproj` targeting .NET 9.0 - Added a new `Program.cs` file that processes C# files in a specified directory. - Implemented functionality to read files, extract comment lines, and convert single-line comments (//) to XML-style comments (///) wrapped in summary tags.
1 parent b4bea92 commit ee2e5b1

File tree

2 files changed

+164
-0
lines changed

2 files changed

+164
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
3+
<PropertyGroup>
4+
<OutputType>Exe</OutputType>
5+
<TargetFramework>net9.0</TargetFramework>
6+
<ImplicitUsings>enable</ImplicitUsings>
7+
<Nullable>enable</Nullable>
8+
</PropertyGroup>
9+
10+
</Project>
Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
const string DoubleSlashCommentPrefix = "// ";
2+
const string TripleSlashCommentPrefix = "/// ";
3+
const string SummaryStart = "/// <summary>";
4+
const string SummaryEnd = "/// </summary>";
5+
const string FileFilter = "*.cs";
6+
7+
var folderPath = @"..\..\..\..\..\src\Box2D.NET\";
8+
9+
// Tests: B2BodySim, B2World, B2WorldId
10+
var files = Directory.GetFiles(folderPath, FileFilter, SearchOption.AllDirectories)
11+
//.Where(w => w.Contains("B2WorldId"))
12+
//.Take(50)
13+
.ToList();
14+
15+
Console.WriteLine($"Found {files.Count} C# files in the folder: {folderPath}");
16+
17+
foreach (var filePath in files)
18+
{
19+
await ProcessFileAsync(filePath);
20+
}
21+
22+
Console.WriteLine("*** Processing completed ***");
23+
24+
async Task ProcessFileAsync(string filePath)
25+
{
26+
Console.WriteLine($"\nProcessing file: {filePath}");
27+
28+
var content = await File.ReadAllTextAsync(filePath);
29+
var lines = content.Split(["\r\n", "\n"], StringSplitOptions.None).ToList();
30+
var commentLineIndexes = ExtractCommentLineIndexes(lines);
31+
32+
RemovePreNamespaceComments(lines, commentLineIndexes);
33+
34+
if (commentLineIndexes.Count == 0)
35+
{
36+
Console.WriteLine("No comment lines found in the file.");
37+
return;
38+
}
39+
40+
var commentBlocks = ExtractCommentBlocks(lines, commentLineIndexes);
41+
42+
if (commentBlocks.Count == 0)
43+
{
44+
Console.WriteLine("No comment blocks found.");
45+
return;
46+
}
47+
48+
ConvertCommentsToTripleSlash(lines, commentBlocks);
49+
50+
WrapCommentsWithSummaryTags(lines, commentBlocks);
51+
52+
//File.WriteAllText(filePath.Replace(".cs", ".xmlcomments.cs"), string.Join(Environment.NewLine, lines));
53+
File.WriteAllText(filePath, string.Join(Environment.NewLine, lines));
54+
55+
Console.WriteLine($"Output written to: {filePath}");
56+
}
57+
58+
static void RemovePreNamespaceComments(List<string> lines, List<int> commentLineIndexes)
59+
{
60+
var namespaceLineIndex = lines.FindIndex(line => line.TrimStart().StartsWith("namespace "));
61+
62+
commentLineIndexes.RemoveAll(index => index < namespaceLineIndex);
63+
}
64+
65+
static List<CommentBlock> ExtractCommentBlocks(List<string> lines, List<int> commentLineIndexes)
66+
{
67+
var commentBlocks = new List<CommentBlock>();
68+
var startIndex = commentLineIndexes[0];
69+
var endIndex = commentLineIndexes[0];
70+
71+
if (commentLineIndexes.Count == 1)
72+
{
73+
AddBlockIfFollowedByPublic(startIndex, endIndex);
74+
75+
return commentBlocks;
76+
}
77+
78+
for (int i = 1; i < commentLineIndexes.Count; i++)
79+
{
80+
var nextIndex = commentLineIndexes[i];
81+
82+
if (nextIndex - endIndex != 1)
83+
{
84+
AddBlockIfFollowedByPublic(startIndex, endIndex);
85+
startIndex = nextIndex;
86+
}
87+
88+
endIndex = nextIndex;
89+
90+
if (i == commentLineIndexes.Count - 1)
91+
{
92+
AddBlockIfFollowedByPublic(startIndex, endIndex);
93+
}
94+
}
95+
96+
return commentBlocks;
97+
98+
void AddBlockIfFollowedByPublic(int startIndex, int endIndex)
99+
{
100+
if (endIndex + 1 < lines.Count && lines[endIndex + 1].Contains("public"))
101+
{
102+
commentBlocks.Add(new CommentBlock(startIndex, endIndex));
103+
}
104+
}
105+
}
106+
107+
static List<int> ExtractCommentLineIndexes(List<string> lines)
108+
{
109+
HashSet<string> commentStarts = [DoubleSlashCommentPrefix, TripleSlashCommentPrefix];
110+
111+
return lines
112+
.Select((line, index) => (line, index))
113+
.Where(item => commentStarts.Any(commentStart =>
114+
item.line.TrimStart().StartsWith(commentStart)))
115+
.Select(item => item.index)
116+
.ToList();
117+
}
118+
119+
static void ConvertCommentsToTripleSlash(List<string> lines, List<CommentBlock> commentBlocks)
120+
{
121+
foreach (var block in commentBlocks)
122+
{
123+
Console.WriteLine($"Comment block from {block.StartIndex + 1} to {block.EndIndex + 1} (length: {block.Length})");
124+
125+
for (int i = 0; i < block.Length; i++)
126+
{
127+
int lineIndex = block.StartIndex + i;
128+
129+
if (!lines[lineIndex].TrimStart().StartsWith(TripleSlashCommentPrefix))
130+
{
131+
lines[lineIndex] = lines[lineIndex].Replace(DoubleSlashCommentPrefix, "/// ");
132+
}
133+
}
134+
}
135+
}
136+
137+
void WrapCommentsWithSummaryTags(List<string> lines, List<CommentBlock> commentBlocks)
138+
{
139+
for (int i = commentBlocks.Count - 1; i >= 0; i--)
140+
{
141+
var block = commentBlocks[i];
142+
var indentation = GetIndentation(lines[block.StartIndex]);
143+
144+
lines.Insert(block.EndIndex + 1, $"{indentation}{SummaryEnd}");
145+
lines.Insert(block.StartIndex, $"{indentation}{SummaryStart}");
146+
}
147+
148+
string GetIndentation(string line) => new(' ', line.Length - line.TrimStart().Length);
149+
}
150+
151+
record class CommentBlock(int StartIndex, int EndIndex)
152+
{
153+
public int Length => EndIndex - StartIndex + 1;
154+
}

0 commit comments

Comments
 (0)