Lua语法检测工具文档
工具概述
Lua语法检测工具是一个Unity编辑器扩展工具,用于批量检查指定目录下所有Lua脚本的语法正确性。该工具通过创建Lua虚拟机环境,尝试加载每个Lua文件来验证其语法是否合法,帮助开发者在早期发现潜在的语法错误。
功能特性
- 批量扫描指定目录下的所有Lua文件
- 使用原生Lua虚拟机进行语法验证
- 显示详细的错误信息,包括文件路径和具体错误描述
- 支持递归扫描子目录
- 提供简洁直观的GUI界面
使用说明
安装与启动
- 将脚本放置在Unity项目的Editor文件夹下
- 在Unity编辑器中,通过菜单栏选择
Tools/lua语法检测
打开工具窗口
界面说明
工具窗口包含以下主要部分:
- 路径选择:显示和修改Lua文件所在目录(默认为
Assets/_GameCenter/ClientLua/Model/Language
)
- 检测按钮:点击后开始扫描指定目录并检测所有Lua文件语法
操作步骤
- 确认或修改Lua文件目录路径
- 点击”开始检测”按钮
- 查看Unity控制台输出:
- 检测开始和结束的标记信息
- 每个文件的检测结果
- 语法错误的详细描述
输出结果解读
- 正常文件:不会产生额外输出
- 语法错误文件:输出格式为:
- 文件读取错误:输出格式为:
1 2
| [FILE ERROR] 读取文件失败: 文件相对路径 错误原因
|
技术实现
核心逻辑
- 文件扫描:递归查找指定目录下的所有.lua文件
- Lua环境初始化:创建Lua虚拟机状态
- 语法检测:对每个文件内容执行luaL_loadstring操作
- 错误处理:捕获并记录加载过程中产生的错误
- 资源清理:关闭Lua虚拟机状态
关键方法
StartCheckLua
:主检测流程控制
CheckLuaSyntax
:执行实际的语法检测
OnGUI
:提供用户界面交互
注意事项
- 工具仅检测语法正确性,不执行实际代码
- 需要确保Lua文件路径正确且可访问
- 检测结果输出到Unity控制台
- 工具不会修改任何Lua文件内容
- 必须选择Assets目录下的路径
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
| using UnityEditor; using UnityEngine; using System.IO; using LuaInterface; using System;
public class CheckLuaSyntaxWindow : EditorWindow { private static string folderPath, defaultPath = "Assets/_GameCenter/ClientLua/Model/Language";
[MenuItem("Tools/lua语法检测")] public static void ShowWindow() { GetWindow<CheckLuaSyntaxWindow>("Lua 语法检测"); }
private void OnGUI() { folderPath = string.IsNullOrEmpty(folderPath) ? defaultPath : folderPath; GUILayout.Label("选择 Lua 文件目录", EditorStyles.boldLabel); EditorGUILayout.BeginHorizontal(); EditorGUILayout.LabelField("目录路径:", folderPath); if (GUILayout.Button("...", GUILayout.Width(30))) { var path = EditorUtility.OpenFolderPanel("选择 Lua 文件目录", folderPath, ""); if (string.IsNullOrEmpty(path)) return; if (!path.Contains("Assets")) { Debug.LogError("所选文件夹不在 Assets 目录下,无法处理!"); return; } folderPath = path.Substring(path.IndexOf("Assets")); } EditorGUILayout.EndHorizontal(); if (GUILayout.Button("开始检测")) StartCheckLua(folderPath); }
private void StartCheckLua(string path) { Debug.Log($"===== 开始 Lua 语法检测 ===== {path} {Application.dataPath}");
var fullPath = Path.GetFullPath(Path.Combine(Application.dataPath, path.Replace("Assets/", ""))); if (!Directory.Exists(fullPath)) { Debug.LogError($"路径不存在: {fullPath}"); return; } var L = IntPtr.Zero; try { L = LuaDLL.lua_open(); if (L == IntPtr.Zero) { Debug.LogError("无法创建 Lua 状态"); return; } LuaDLL.luaL_openlibs(L); var luaFiles = Directory.GetFiles(fullPath, "*.lua", SearchOption.AllDirectories); foreach (var file in luaFiles) { var relativePath = "Assets" + file.Substring(Application.dataPath.Length); try { var luaCode = File.ReadAllText(file); var error = CheckLuaSyntax(luaCode, L); if (!string.IsNullOrEmpty(error)) Debug.LogError($"[ERROR] {relativePath}\n{error}"); } catch (Exception e) { Debug.LogError($"[FILE ERROR] 读取文件失败: {relativePath}\n{e.Message}"); } } } finally { if (L != IntPtr.Zero) LuaDLL.lua_close(L); } Debug.Log("===== 检测完成 ====="); }
private string CheckLuaSyntax(string code, IntPtr L) { try { LuaDLL.lua_settop(L, 0); if (LuaDLL.luaL_loadstring(L, code) == 0) { LuaDLL.lua_pop(L, 1); return null; } else { var error = LuaDLL.lua_tostring(L, -1); LuaDLL.lua_pop(L, 1); return error; } } catch (Exception e) { return e.Message; } } }
|