csharp
复制代码
using UnityEngine;
using UnityEditor;
using System.IO;
using System.Text;
public class SimpleDebugLogCommenter : EditorWindow
{
private string targetFolderPath = "Assets/Scripts";
private bool includeSubdirectories = true;
private bool backupFiles = true;
private int processedFilesCount = 0;
private int commentedLogsCount = 0;
[MenuItem("Tools/Simple Debug Log Commenter")]
public static void ShowWindow()
{
GetWindow<SimpleDebugLogCommenter>("Simple Debug Log Commenter");
}
private void OnGUI()
{
GUILayout.Label("Debug.Log 注释工具 (简单版)", EditorStyles.boldLabel);
EditorGUILayout.Space();
// 目标文件夹选择
EditorGUILayout.BeginHorizontal();
targetFolderPath = EditorGUILayout.TextField("目标文件夹", targetFolderPath);
if (GUILayout.Button("选择", GUILayout.Width(60)))
{
string path = EditorUtility.OpenFolderPanel("选择文件夹", "Assets", "");
if (!string.IsNullOrEmpty(path) && path.StartsWith(Application.dataPath))
{
targetFolderPath = "Assets" + path.Substring(Application.dataPath.Length);
}
}
EditorGUILayout.EndHorizontal();
includeSubdirectories = EditorGUILayout.Toggle("包含子文件夹", includeSubdirectories);
backupFiles = EditorGUILayout.Toggle("备份原始文件", backupFiles);
EditorGUILayout.Space();
if (processedFilesCount > 0)
{
EditorGUILayout.HelpBox(
$"上次操作: 处理了 {processedFilesCount} 个文件,注释了 {commentedLogsCount} 个 Debug 语句",
MessageType.Info
);
}
EditorGUILayout.Space();
EditorGUI.BeginDisabledGroup(!Directory.Exists(targetFolderPath));
if (GUILayout.Button("注释 Debug 语句", GUILayout.Height(30)))
{
ProcessFiles();
}
EditorGUI.EndDisabledGroup();
EditorGUILayout.Space();
EditorGUILayout.HelpBox(
"简单版本,使用更可靠的方法处理Debug语句。",
MessageType.Warning
);
}
private void ProcessFiles()
{
if (!Directory.Exists(targetFolderPath))
{
EditorUtility.DisplayDialog("错误", "目标文件夹不存在!", "确定");
return;
}
if (!EditorUtility.DisplayDialog("确认操作",
$"将处理 {targetFolderPath} 下所有脚本中的 Debug 语句。\n继续吗?", "继续", "取消"))
{
return;
}
processedFilesCount = 0;
commentedLogsCount = 0;
SearchOption searchOption = includeSubdirectories ?
SearchOption.AllDirectories : SearchOption.TopDirectoryOnly;
string[] files = Directory.GetFiles(targetFolderPath, "*.cs", searchOption);
EditorUtility.DisplayProgressBar("正在处理", "扫描文件...", 0);
try
{
for (int i = 0; i < files.Length; i++)
{
string file = files[i];
float progress = (float)i / files.Length;
EditorUtility.DisplayProgressBar(
"处理文件中...",
$"{Path.GetFileName(file)} ({i + 1}/{files.Length})",
progress
);
int commentedCount = ProcessSingleFile(file);
if (commentedCount > 0)
{
processedFilesCount++;
commentedLogsCount += commentedCount;
}
}
EditorUtility.ClearProgressBar();
AssetDatabase.Refresh();
EditorUtility.DisplayDialog("完成",
$"处理完成!\n处理文件: {processedFilesCount}\n注释语句: {commentedLogsCount}",
"确定"
);
Repaint();
}
catch (System.Exception e)
{
EditorUtility.ClearProgressBar();
EditorUtility.DisplayDialog("错误", $"处理过程中发生错误:\n{e.Message}", "确定");
Debug.LogError($"DebugLogCommenter 错误: {e}");
}
}
private int ProcessSingleFile(string filePath)
{
if (!File.Exists(filePath))
return 0;
string originalContent = File.ReadAllText(filePath, Encoding.UTF8);
// 备份文件
if (backupFiles)
{
string backupPath = filePath + ".backup";
File.WriteAllText(backupPath, originalContent, Encoding.UTF8);
}
// 处理内容 - 使用简单但可靠的方法
string processedContent = ProcessContentSimple(originalContent);
// 如果没有变化,不写文件
if (processedContent == originalContent)
return 0;
// 统计注释的数量
int commentedCount = CountDebugStatements(originalContent) - CountDebugStatements(processedContent);
File.WriteAllText(filePath, processedContent, Encoding.UTF8);
return commentedCount;
}
private string ProcessContentSimple(string content)
{
StringBuilder result = new StringBuilder();
string[] lines = content.Split('\n');
for (int lineIndex = 0; lineIndex < lines.Length; lineIndex++)
{
string line = lines[lineIndex];
string processedLine = ProcessLineSimple(line);
// 检查是否有多行Debug语句
if (ContainsDebugStart(line) && !IsLineCommented(line))
{
// 检查括号是否匹配
int openParenCount = CountChar(line, '(');
int closeParenCount = CountChar(line, ')');
if (openParenCount > closeParenCount)
{
// 有多行Debug语句,需要特殊处理
StringBuilder multiLineStatement = new StringBuilder();
multiLineStatement.Append(line);
int currentLine = lineIndex;
int parenthesesBalance = openParenCount - closeParenCount;
while (parenthesesBalance > 0 && currentLine + 1 < lines.Length)
{
currentLine++;
string nextLine = lines[currentLine];
multiLineStatement.Append("\n").Append(nextLine);
openParenCount = CountChar(nextLine, '(');
closeParenCount = CountChar(nextLine, ')');
parenthesesBalance += openParenCount - closeParenCount;
// 如果这一行有分号且括号平衡,说明语句结束
if (parenthesesBalance == 0 && nextLine.Contains(";"))
{
// 处理这个多行语句
string fullStatement = multiLineStatement.ToString();
if (!IsAlreadyCommentedInMultiLine(fullStatement))
{
// 找到第一个Debug的位置
int debugIndex = fullStatement.IndexOf("Debug.");
if (debugIndex >= 0)
{
string beforeDebug = fullStatement.Substring(0, debugIndex);
string debugPart = fullStatement.Substring(debugIndex);
processedLine = beforeDebug + "// " + debugPart;
}
else
{
processedLine = "// " + fullStatement;
}
}
else
{
processedLine = fullStatement;
}
lineIndex = currentLine; // 跳过已处理的行
break;
}
}
}
else
{
// 单行Debug语句
result.Append(processedLine);
}
}
else
{
result.Append(processedLine);
}
if (lineIndex < lines.Length - 1)
{
result.Append("\n");
}
}
return result.ToString();
}
private string ProcessLineSimple(string line)
{
// 如果行已经被注释,直接返回
if (IsLineCommented(line))
return line;
// 检查是否包含Debug语句
if (!ContainsDebugStatement(line))
return line;
// 找到Debug的位置
int debugIndex = FindDebugIndex(line);
if (debugIndex < 0)
return line;
// 检查从行开始到Debug位置之间是否有注释符号
string beforeDebug = line.Substring(0, debugIndex);
if (beforeDebug.Contains("//") || beforeDebug.Contains("/*"))
return line;
// 注释这一行(从Debug开始的位置)
return line.Insert(debugIndex, "// ");
}
private bool IsLineCommented(string line)
{
string trimmedLine = line.Trim();
return trimmedLine.StartsWith("//") || trimmedLine.StartsWith("/*") || trimmedLine.Contains("*/");
}
private bool ContainsDebugStatement(string line)
{
string lineWithoutStrings = RemoveStringLiterals(line);
return lineWithoutStrings.Contains("Debug.Log") ||
lineWithoutStrings.Contains("Debug.LogWarning") ||
lineWithoutStrings.Contains("Debug.LogError");
}
private bool ContainsDebugStart(string line)
{
string lineWithoutStrings = RemoveStringLiterals(line);
return lineWithoutStrings.Contains("Debug.Log(") ||
lineWithoutStrings.Contains("Debug.LogWarning(") ||
lineWithoutStrings.Contains("Debug.LogError(");
}
private int FindDebugIndex(string line)
{
// 先移除字符串内容,避免在字符串内找到Debug
string lineWithoutStrings = RemoveStringLiterals(line);
// 查找Debug的位置
int index = lineWithoutStrings.IndexOf("Debug.Log");
if (index < 0) index = lineWithoutStrings.IndexOf("Debug.LogWarning");
if (index < 0) index = lineWithoutStrings.IndexOf("Debug.LogError");
if (index >= 0)
{
// 将索引映射回原始行的位置
// 我们需要找到在原始行中对应的位置
int originalIndex = MapIndexToOriginalLine(line, lineWithoutStrings, index);
return originalIndex;
}
return -1;
}
private int MapIndexToOriginalLine(string originalLine, string lineWithoutStrings, int indexInStripped)
{
// 这个方法将去除字符串后的索引映射回原始行的索引
int originalIndex = 0;
int strippedIndex = 0;
bool inString = false;
bool escaped = false;
char stringChar = '\0';
while (originalIndex < originalLine.Length && strippedIndex <= indexInStripped)
{
char c = originalLine[originalIndex];
if (escaped)
{
escaped = false;
}
else if (c == '\\')
{
escaped = true;
}
else if (!inString && (c == '"' || c == '\''))
{
inString = true;
stringChar = c;
}
else if (inString && c == stringChar)
{
inString = false;
}
if (!inString)
{
strippedIndex++;
}
if (strippedIndex > indexInStripped)
{
return originalIndex;
}
originalIndex++;
}
return originalIndex;
}
private string RemoveStringLiterals(string line)
{
StringBuilder result = new StringBuilder();
bool inString = false;
bool escaped = false;
char stringChar = '\0';
for (int i = 0; i < line.Length; i++)
{
char c = line[i];
if (escaped)
{
escaped = false;
if (!inString) result.Append(c);
}
else if (c == '\\')
{
escaped = true;
if (!inString) result.Append(c);
}
else if (!inString && (c == '"' || c == '\''))
{
inString = true;
stringChar = c;
// 不添加引号到结果中
}
else if (inString && c == stringChar)
{
inString = false;
// 不添加引号到结果中
}
else if (!inString)
{
result.Append(c);
}
// 如果在字符串中,不添加到结果
}
return result.ToString();
}
private int CountChar(string text, char charToCount)
{
int count = 0;
bool inString = false;
bool escaped = false;
char stringChar = '\0';
for (int i = 0; i < text.Length; i++)
{
char c = text[i];
if (escaped)
{
escaped = false;
continue;
}
if (c == '\\')
{
escaped = true;
continue;
}
if (!inString && (c == '"' || c == '\''))
{
inString = true;
stringChar = c;
}
else if (inString && c == stringChar)
{
inString = false;
}
if (!inString && c == charToCount)
{
count++;
}
}
return count;
}
private bool IsAlreadyCommentedInMultiLine(string text)
{
string[] lines = text.Split('\n');
foreach (string line in lines)
{
string trimmed = line.Trim();
if (trimmed.StartsWith("//") || trimmed.StartsWith("/*"))
{
return true;
}
}
return false;
}
private int CountDebugStatements(string content)
{
int count = 0;
string[] lines = content.Split('\n');
foreach (string line in lines)
{
string lineWithoutStrings = RemoveStringLiterals(line);
if ((lineWithoutStrings.Contains("Debug.Log(") ||
lineWithoutStrings.Contains("Debug.LogWarning(") ||
lineWithoutStrings.Contains("Debug.LogError(")) &&
!IsLineCommented(line))
{
count++;
}
}
return count;
}
}