test-mlua-lsp
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
Chinesemlua LSP Skill
mlua LSP 技能
프로토콜 범위 — 정직한 경계
协议范围——明确的边界
이 스킬이 에이전트에게 노출하는 / / 단발 CLI는 LSP 프로토콜 자체가 아니라 데몬의 커스텀 newline-JSON RPC다. (1-based 좌표, 세션 없음, 필드.) 내부에서 이 RPC는 진짜 LSP 서버(MSW 공식 확장의 languageServer)를 구동한다.
servemlua-batch.jscommandmsw.mlua진짜 LSP(JSON-RPC 2.0 + Content-Length + 0-based + //)가 필요하면 에디터가 쓰는 엔드포인트를 직접 붙인다 — plugin.json의 가 이미 이 경로를 사용 중이다.
initializedidOpentextDocument/*mlua-lsp server --stdiolspServers该技能向Agent暴露的 / / 单次CLI并非LSP协议本身,而是守护进程的自定义换行JSON RPC(基于1坐标索引、无会话、包含字段)。内部该RPC会启动真正的LSP服务器(MSW官方扩展的languageServer)。
servemlua-batch.jscommandmsw.mlua若需要标准LSP(JSON-RPC 2.0 + Content-Length + 0坐标索引 + //),可直接连接编辑器使用的端点——plugin.json中的已在使用该路径。
initializedidOpentextDocument/*mlua-lsp server --stdiolspServers원칙
原则
- 파일을 직접 읽지 않는다. MSW SDK는 600+ 정의 파일이라 토큰 낭비. 대신
.d.mlua/hover로 조회.complete - 추측하지 말고 먼저 확인 → ·
hover·complete로 API를 본 뒤 작성.signature - 작성 후 반드시 →
diagnose이 될 때까지 수정 루프.errors: 0 - 수정된 는 모아서 한 번에 batch diagnose — Edit/Write/MultiEdit로
.mlua를 건드렸다면, 해당 작업 단위(유저 턴 또는 연속된 수정 배치)가 끝나는 시점에 수정된 모든 파일을 단 한 번의.mlua호출로 묶어 diagnose한다. 파일마다 개별 호출 금지 — queries.jsonl에 한 줄씩 쌓아서 일괄 전송. 응답의mlua-batch.js인 파일만 수정 후 같은 방식으로 재진단. 자세한 절차는 "자동 점검 프로토콜" 참조.errors > 0 - 기본은 /
serve(persistent stdin/stdout) — 한 번의 프로세스/TCP 연결로 N개 쿼리를 상각. 단발 CLI는 1개짜리 즉석 확인에만 사용.batch - 프로젝트 단위로 데몬 1개 — 다른 프로젝트로 넘어갈 때는 호출. 유휴 30분 뒤 자동 종료(
stop로 조정).MLUA_LSP_IDLE_MINUTES
- 不直接读取文件:MSW SDK包含600+定义文件,直接读取会浪费Token。改用
.d.mlua/hover查询。complete - 不猜测,先验证 → 先通过·
hover·complete查看API再编写代码。signature - 编写后必须执行→ 循环修改直到
diagnose。errors: 0 - 修改后的文件批量诊断 —— 若通过Edit/Write/MultiEdit修改了
.mlua文件,需在该操作单元(用户轮次或连续修改批次)结束时,将所有修改文件通过一次.mlua调用批量诊断。禁止逐个文件单独调用——将查询逐行写入queries.jsonl后批量发送。仅对响应中mlua-batch.js的文件进行修改,再以相同方式重新诊断。详细流程请参考「自动检查协议」。errors > 0 - 默认使用/
serve(持久化stdin/stdout) —— 通过一次进程/TCP连接处理N个查询。单次CLI仅用于单个查询的即时验证。batch - 每个项目对应一个守护进程 —— 切换项目时需调用。闲置30分钟后自动终止(可通过
stop调整)。MLUA_LSP_IDLE_MINUTES
프로젝트 루트 (project-root)
项目根目录(project-root)
모든 명령의 첫 인자는 MSW 프로젝트 루트여야 한다.
- 와
RootDesk/MyDesk/(Environment/NativeScripts/)를 포함하는 상위 디렉토리.d.mlua - 잘못된 루트를 넘기면 hover/complete가 빈 결과를 반환하고 diagnose가 무의미해진다
- 동일 루트로 일관되게 호출해야 데몬이 워크스페이스 인덱스를 재사용
예: (내부에 · 존재)
/Users/you/msw-projects/MyGame/RootDesk/MyDesk/Environment/所有命令的第一个参数必须是MSW项目根目录。
- 包含和
RootDesk/MyDesk/(存放Environment/NativeScripts/)的上级目录.d.mlua - 传入错误根目录会导致hover/complete返回空结果,diagnose失去意义
- 需持续传入相同根目录,守护进程才能复用工作区索引
示例:(内部包含·)
/Users/you/msw-projects/MyGame/RootDesk/MyDesk/Environment/기본 호출 — 배치 (serve)
基础调用——批量模式(serve)
bash
undefinedbash
undefined파일로부터
从文件读取
node ~/.claude/skills/test-mlua-lsp/scripts/mlua-batch.js <project-root> queries.jsonl
node ~/.claude/skills/test-mlua-lsp/scripts/mlua-batch.js <project-root> queries.jsonl
stdin에서
从stdin读取
cat queries.jsonl | node ~/.claude/skills/test-mlua-lsp/scripts/mlua-batch.js <project-root>
undefinedcat queries.jsonl | node ~/.claude/skills/test-mlua-lsp/scripts/mlua-batch.js <project-root>
undefined요청 포맷 (newline-JSON, 한 줄 1쿼리)
请求格式(换行JSON,每行一个查询)
json
{"id":1,"command":"diagnose","file":"/abs/path/a.mlua"}
{"id":2,"command":"hover","file":"/abs/path/b.mlua","line":10,"col":5}
{"id":3,"command":"complete","file":"/abs/path/c.mlua","line":7,"col":12}- /
line은 1-based. 생략 시col.null - 는 선택 (숫자 또는 문자열 모두 OK — 데몬은 opaque하게 echo back). 응답 상관관계 추적에 유용.
id - 응답도 newline-JSON으로 stdout에 순서대로 출력.
json
{"id":1,"command":"diagnose","file":"/abs/path/a.mlua"}
{"id":2,"command":"hover","file":"/abs/path/b.mlua","line":10,"col":5}
{"id":3,"command":"complete","file":"/abs/path/c.mlua","line":7,"col":12}- /
line为1坐标索引。省略时为col。null - 为可选参数(数字或字符串均可——守护进程会原样返回)。有助于追踪响应对应关系。
id - 响应同样以换行JSON格式按顺序输出到stdout。
왜 batch가 기본인가
为什么以批量模式为默认
| 경로 | 1쿼리 | N쿼리 (warm) |
|---|---|---|
단발 CLI ( | ~22ms | ~22ms × N (매 호출 Node + TCP) |
| ~22ms + α | ~22ms + N × daemon-RPC (p50 <5ms) |
에이전트가 여러 심볼을 연속 조회하거나 여러 파일을 진단할 때 batch가 수 배 빠르다. v4 벤치(MineSimulator 279파일, warm 6.2s @ 22ms 평균)는 단발 CLI 기준이므로, serve 사용 시 더 단축된다.
| 调用方式 | 1个查询 | N个查询(热启动) |
|---|---|---|
单次CLI ( | ~22ms | ~22ms × N(每次调用都需启动Node + TCP连接) |
| ~22ms + α | ~22ms + N × 守护进程RPC(p50 <5ms) |
当Agent需要连续查询多个符号或诊断多个文件时,批量模式速度快数倍。v4基准测试(MineSimulator 279个文件,热启动6.2s @ 平均22ms)基于单次CLI,使用serve模式可进一步缩短时间。
단발 호출 (fallback, 1쿼리)
单次调用(降级方案,单查询)
한 지점만 확인하는 경우:
bash
node ~/.claude/skills/test-mlua-lsp/scripts/mlua-lsp.js <command> <project-root> <file> [line] [col]- 래퍼가 을 통해 실행 — 별도 설치 불필요.
npx -y @choigawoon/mlua-lsp@0.5.0 - 출력은 pretty-printed JSON.
- 데몬 실패 시 one-shot으로 자동 폴백.
--no-daemon
仅需验证单个位置时使用:
bash
node ~/.claude/skills/test-mlua-lsp/scripts/mlua-lsp.js <command> <project-root> <file> [line] [col]- 包装器通过执行——无需单独安装。
npx -y @choigawoon/mlua-lsp@0.5.0 - 输出为格式化后的JSON。
- 守护进程失败时自动降级为单次模式。
--no-daemon
명령
命令
| 명령 | 용도 | 반환 핵심 |
|---|---|---|
| 타입/문법/미존재 멤버 에러 | |
| 해당 위치의 타입·설명 | |
| | |
| 정의 위치 이동 | |
| 사용 지점 찾기 | |
| 함수 시그니처·파라미터 | |
| 데몬 상태 | |
| 데몬 live 스냅샷 (in-flight · 완료 카운트, | |
| 머신 리더블 커맨드 카탈로그 (데몬 없이도 동작) | JSON 카탈로그 |
| 데몬 종료 | — |
| newline-JSON 프록시 (batch의 하위 계층) | stdin→stdout JSONL |
diagnosestatusdumpdescribestoplinecol| 命令 | 用途 | 返回核心内容 |
|---|---|---|
| 检查类型/语法/不存在的成员错误 | |
| 查询对应位置的类型·说明 | |
| 查询 | |
| 跳转到定义位置 | |
| 查找使用位置 | |
| 查询函数签名·参数 | |
| 查询守护进程状态 | |
| 查询守护进程实时快照(进行中·已完成计数,添加 | |
| 查询机器可读命令目录(无需守护进程即可运行) | JSON目录 |
| 终止守护进程 | — |
| 换行JSON代理(批量模式的底层实现) | stdin→stdout JSONL |
diagnosestatusdumpdescribestoplinecol⚠️ Cold-daemon false positive (FP) — 글로벌 'Symbol not found' 의 함정
⚠️ 冷启动守护进程误报(FP)——全局‘Symbol not found’陷阱
증상: / / 가 다음 중 다수에 또는 (info severity) 를 반환:
diagnosehoversignaturefound: false"Symbol not found"- 로 시작하는 서비스 글로벌:
_,_SpawnService,_TimerService,_UserService,_GameLogic,_UtilLogic,_MapService,_HttpService,_DataStorageService, …_InputService - 빌트인 타입 생성자: ,
Vector2,Vector3,Quaternion,ColorVector4 - 빌트인 컴포넌트 타입: ,
TextComponent,TransformComponent, …UITransformComponent
원인: 데몬이 갓 떴거나 파싱이 미완료 — 워크스페이스 인덱스 cold 상태. 진짜 미존재 아님.
.d.mlua왜 위험한가: 이 상태에서는 해당 글로벌의 member 호출 인자 타입 검증이 우회된다. 예 — 처럼 4번째 위치에 를 넘겨도 LSP 가 통과시킴. 런타임에 가 터질 때까지 잡히지 않음. 실제 발생 이력 있음 (Vampire Survivor SpawnMonster, Vector3 자리에 Vector2 — LSP cold FP 로 묻힘).
_SpawnService:SpawnByModelId(id, name, Vector2(x,y), map)Vector2LEA-3005 InvalidArgument처치 — Warm-up & re-diagnose 절차:
-
WARMUP —편집을 시작하기 전, 또는 cold 의심 시점에 핵심 글로벌을 한 번씩 hover 로 두드린다. 한 번에 batch 로:
.mluabashcat <<EOF | node <plugin>/skills/test-mlua-lsp/scripts/mlua-batch.js <project-root> {"id":"w1","command":"hover","file":"<any project .mlua>","line":1,"col":1} {"id":"w2","command":"complete","file":"<any project .mlua>","line":1,"col":1} EOF직접 호출 대신 — 편집 대상 파일에/_SpawnService가 등장하는 줄·열로 hover 던지기. 응답이Vector3라도 데몬이 그 시점부터 인덱싱을 시작. 30초~수분 후 재시도.found:false -
RE-DIAGNOSE — warmup 후 동일 파일을 batch diagnose 재실행. cold 시 떴던 13개 "Symbol not found" 가 사라지고 진짜 진단(시그니처 미스매치 등) 만 남는다.
-
글로벌이 여전히 not-found 면 두 가지 경우:
- Case A — 루트 잘못: 가 비어있거나 없음. 데몬은 아무리 기다려도 글로벌을 못 찾는다. 정답: 올바른 워크스페이스 루트로 재시작.
<project-root>/Environment/NativeScripts/Service/ - Case B — 인덱서 sticky: 가
mlua-lsp.js status라고 보고하는데도 동일 FP 가 지속. 이는 데몬이 인덱스를 적재했다고 믿지만 실제 심볼 테이블이 비어있는 상태.workspaceLoaded: true으로 데몬 죽이고 재호출 시도. 그래도 동일하면 워크스페이스의mlua-lsp.js stop디렉토리 자체가 손상되었거나 버전 불일치. 이 경우 현재 턴에서 LSP 검증은 포기하고, 코드 리뷰(시그니처 수동 확인 —Environment/직접 grep) 로 대체. 사용자에게 "LSP 인덱서 sticky 상태 — 수동 검증으로 진행" 명시.*.d.mlua
판별 단서: 동일 워크스페이스의 기존 작동하는파일(예:.mlua) 에 diagnose 던졌을 때도 같은 글로벌이 not-found 로 나오면 sticky/workspace 문제 (편집 파일 책임 아님).UIPopup.mlua - Case A — 루트 잘못:
식별 기준 — FP 인지 진짜인지:
| 토큰 모양 | not-found 의미 |
|---|---|
| 거의 항상 cold FP — warmup |
| 거의 항상 cold FP — warmup |
대문자 시작 빌트인 컴포넌트 ( | 거의 항상 cold FP — warmup |
사용자 정의 모듈/스크립트명 ( | 진짜 — 정의 누락 또는 오타 |
메소드/멤버 ( | warmup 후에도 남아있으면 진짜 — 진짜 API 누락 |
금지 — "어차피 cold FP 일 거다" 로 진단 결과 통째 무시 후 ship. 반드시 warmup → 재진단으로 진짜 결과를 본 뒤 turn 마감.
症状: / / 返回以下内容中的多个或(信息级别):
diagnosehoversignaturefound: false"Symbol not found"- 以下划线开头的服务全局变量:
_,_SpawnService,_TimerService,_UserService,_GameLogic,_UtilLogic,_MapService,_HttpService,_DataStorageService, …_InputService - 内置类型构造函数:,
Vector2,Vector3,Quaternion,ColorVector4 - 内置组件类型:,
TextComponent,TransformComponent, …UITransformComponent
原因:守护进程刚启动或解析未完成——工作区索引处于冷状态。并非真正的符号不存在。
.d.mlua风险:该状态下,全局变量的成员调用参数类型验证会被跳过。例如——即使在的第4个位置传入,LSP也会放行。直到运行时触发才会被发现。已有实际案例(Vampire Survivor的SpawnMonster,在Vector3位置传入Vector2——被LSP冷启动误报掩盖)。
_SpawnService:SpawnByModelId(id, name, Vector2(x,y), map)Vector2LEA-3005 InvalidArgument处理——预热与重新诊断流程:
-
预热 —— 开始编辑前,或怀疑处于冷状态时,通过hover查询核心全局变量。可批量执行:
.mluabashcat <<EOF | node <plugin>/skills/test-mlua-lsp/scripts/mlua-batch.js <project-root> {"id":"w1","command":"hover","file":"<any project .mlua>","line":1,"col":1} {"id":"w2","command":"complete","file":"<any project .mlua>","line":1,"col":1} EOF也可直接在编辑目标文件中,对包含/_SpawnService的行·列执行hover。即使响应为Vector3,守护进程也会从此时开始索引。30秒~数分钟后重试。found:false -
重新诊断 —— 预热后对相同文件重新执行批量诊断。冷状态时出现的13个"Symbol not found"会消失,仅保留真正的诊断结果(如签名不匹配等)。
-
全局变量仍显示not-found时,分为两种情况:
- 情况A——根目录错误:为空或不存在。无论等待多久,守护进程都无法找到全局变量。解决方法:使用正确的工作区根目录重新启动。
<project-root>/Environment/NativeScripts/Service/ - 情况B——索引器异常:显示
mlua-lsp.js status,但相同误报持续存在。这是守护进程认为已加载索引,但实际符号表为空的状态。通过workspaceLoaded: true终止守护进程后重新调用。若仍无法解决,说明工作区的mlua-lsp.js stop目录已损坏或版本不兼容。此时当前轮次放弃LSP验证,改用代码审查(手动检查签名——直接grepEnvironment/)替代。需明确告知用户:"LSP索引器异常——将通过手动验证继续"。*.d.mlua
判断依据:对同一工作区中已正常运行的文件(如.mlua)执行diagnose时,若同样出现全局变量not-found,则为索引器/工作区问题(与编辑文件无关)。UIPopup.mlua - 情况A——根目录错误:
判断标准——是否为误报:
| 令牌形态 | not-found的含义 |
|---|---|
以下划线 | 几乎都是冷启动误报——执行预热 |
| 几乎都是冷启动误报——执行预热 |
大写开头的内置组件( | 几乎都是冷启动误报——执行预热 |
用户自定义模块/脚本名( | 真实错误——定义缺失或拼写错误 |
方法/成员( | 预热后仍存在则为真实错误——API确实缺失 |
禁止操作——以"反正都是冷启动误报"为由完全忽略诊断结果后交付。必须执行预热→重新诊断,确认真实结果后再结束轮次。
워크플로
工作流程
0. [WARMUP] 새 데몬 또는 의심 시 — 글로벌 hover 한 차례로 인덱스 깨우기
1. [PRE] batch로 hover/complete/signature 묶어서 API 확인
2. [WRITE] .mlua 작성 (여러 파일이어도 OK — 수정된 파일 경로를 머릿속에 쌓아둔다)
3. [POST] 수정된 전 파일을 한 번의 batch diagnose로 일괄 점검 → errors > 0인 파일만 수정 → 재진단 루프 → 전부 errors: 0
⚠️ diagnose 결과에 글로벌 'Symbol not found' 가 다수면 cold FP 의심 — warmup 후 재진단
4. [PLAY] (선택) msw-maker-mcp play로 실행 검증예: 한 심볼에 대해 hover + definition + references를 동시에 알고 싶을 때 세 번의 단발 호출 대신 한 번의 batch.
bash
cat <<EOF | node ~/.claude/skills/test-mlua-lsp/scripts/mlua-batch.js /path/to/MyGame
{"id":1,"command":"hover","file":"/path/to/MyGame/RootDesk/MyDesk/Player.mlua","line":12,"col":18}
{"id":2,"command":"definition","file":"/path/to/MyGame/RootDesk/MyDesk/Player.mlua","line":12,"col":18}
{"id":3,"command":"references","file":"/path/to/MyGame/RootDesk/MyDesk/Player.mlua","line":12,"col":18}
EOF0. [预热] 新守护进程启动或怀疑冷状态时——通过hover查询全局变量激活索引
1. [前置] 批量执行hover/complete/signature查询API
2. [编写] 编写.mlua代码(可同时编辑多个文件——记录修改文件的路径)
3. [后置] 将所有修改文件通过一次批量诊断检查 → 仅修改`errors > 0`的文件 → 重新诊断循环 → 直到所有文件`errors: 0`
⚠️ 若诊断结果中存在多个全局'Symbol not found',怀疑冷启动误报——预热后重新诊断
4. [测试] (可选)通过msw-maker-mcp play执行运行验证示例:若想同时查询某个符号的hover + definition + references,无需三次单次调用,可使用一次批量调用。
bash
cat <<EOF | node ~/.claude/skills/test-mlua-lsp/scripts/mlua-batch.js /path/to/MyGame
{"id":1,"command":"hover","file":"/path/to/MyGame/RootDesk/MyDesk/Player.mlua","line":12,"col":18}
{"id":2,"command":"definition","file":"/path/to/MyGame/RootDesk/MyDesk/Player.mlua","line":12,"col":18}
{"id":3,"command":"references","file":"/path/to/MyGame/RootDesk/MyDesk/Player.mlua","line":12,"col":18}
EOF자동 점검 프로토콜 — .mlua
편집 배치 끝에 반드시 수행
.mlua自动检查协议——必须在.mlua编辑批次结束时执行
이 스킬을 로드한 에이전트는 다음 절차를 기본 동작으로 간주한다. Claude Code 훅이 자동 발화하지 않으므로, 스킬 지시를 따르는 에이전트가 스스로 수행해야 한다.
- 편집 트래킹 — Edit / Write / MultiEdit로 파일을 수정할 때마다 그 절대경로를 세션 내에서 모아둔다 (중복 제거). 한 파일을 여러 번 고쳤다면 한 번만 카운트.
.mlua - 체크포인트 — 아래 중 하나에 도달하면 즉시 batch diagnose를 실행한다:
- 유저 턴에 요청된 편집 작업을 모두 마쳤을 때 (응답을 마무리하기 직전)
- 편집 파일 수가 10개를 넘어갈 때 (중간 점검)
- 유저가 "점검", "diagnose", "검수" 등을 명시적으로 요청할 때
- 실행 — 수집한 경로 집합을 newline-JSON 쿼리로 조립해 단 한 번의 호출로 전송.
mlua-batch.jsbash# 예: 수정된 파일 N개를 한 번에 printf '%s\n' "${edited_files[@]}" \ | awk '{printf "{\"id\":%d,\"command\":\"diagnose\",\"file\":\"%s\"}\n", NR, $0}' \ | node /path/to/mlua-batch.js <project-root> - 수정 루프 — 응답 중 인 파일만 골라 diagnostics를 근거로 수정 → 해당 파일들만 다시 batch diagnose. 모든 파일이
errors > 0이 될 때까지 반복.errors: 0 - 리포트 — 최종 결과를 유저에게 요약: 수정 파일 수 / clean 수 / 남은 에러 수 / (해결 불가한 경우) 원인 분석. 아무것도 수정하지 않았더라도 "편집 없음 — diagnose 생략"이라고 명시해 누락 여부를 투명하게.
금지 사항:
- 파일마다 개별 호출 — TCP handshake × N으로 수 배 느려짐.
mlua-lsp.js diagnose - 편집 직후 매번 진단 — 연속 수정 흐름을 끊고 데몬 캐시를 낭비.
- diagnose 생략 후 턴 종료 — 에이전트의 재량에 맡기지 말고 체크포인트에 도달하면 무조건 실행.
加载该技能的Agent需将以下流程作为默认行为。Claude Code钩子不会自动触发,需Agent自行遵循技能指令执行。
- 编辑追踪 —— 每次通过Edit / Write / MultiEdit修改文件时,在会话中记录其绝对路径(去重)。同一文件多次修改仅记录一次。
.mlua - 检查点 —— 到达以下任一条件时立即执行批量诊断:
- 用户轮次中请求的所有编辑操作完成时(即将完成响应前)
- 修改文件数量超过10个时(中间检查)
- 用户明确请求"检查"、"diagnose"、"审核"等操作时
- 执行 —— 将收集的路径集合组装为换行JSON查询,通过一次调用发送。
mlua-batch.jsbash# 示例:批量处理N个修改文件 printf '%s\n' "${edited_files[@]}" \ | awk '{printf "{\"id\":%d,\"command\":\"diagnose\",\"file\":\"%s\"}\n", NR, $0}' \ | node /path/to/mlua-batch.js <project-root> - 修改循环 —— 仅针对响应中的文件,根据diagnostics修改 → 仅对这些文件再次执行批量诊断。重复直到所有文件
errors > 0。errors: 0 - 报告 —— 向用户总结最终结果:修改文件数量 / 无错误文件数量 / 剩余错误数量 / (无法解决时)原因分析。即使未修改任何文件,也需明确告知"无编辑操作——跳过diagnose",确保透明度。
禁止事项:
- 对每个文件单独调用——N次TCP握手会导致速度慢数倍。
mlua-lsp.js diagnose - 每次编辑后立即执行诊断——打断连续修改流程,浪费守护进程缓存。
- 跳过diagnose后结束轮次——不要交由Agent自行决定,到达检查点必须执行。
에디터 LSP 연동 (진짜 LSP 경로)
编辑器LSP联动(标准LSP路径)
plugin.jsonlspServers.mluamlua-lsp server --stdioplugin.json中的会在打开文件时自动启动(基于npx,无需安装)。这是遵循标准LSP规范的路径——编辑器通过Content-Length帧 + 会话生命周期进行通信。该路径与本技能的Agent验证循环(自定义RPC)使用独立的LSP实例,因此可共存。
lspServers.mluamlua-lsp server --stdio참고
参考
- docs/mlua-syntax.md — mlua 문법 요약 + MSW 프로젝트 구조
- docs/mlua-syntax.md —— mlua语法总结 + MSW项目结构