{"owner":"lc-soft","repo":"LCUI","hasSkills":true,"hasMcp":false,"mcpConfig":null,"found":["AGENTS.md"],"skills":{"AGENTS.md":"## 代码格式\n\n遵循 .clang-format 文件中定义的规则，修改文件后需格式化。\n\n### 缩进\n\n使用八个空格缩进。\n\n### 代码结构\n\n源文件中的代码结构应该为：\n\n1. 预处理指令\n2. 类型\n3. 全局变量\n4. 函数声明\n5. 函数定义\n\n其中“函数定义”应该按照功能类别分组、按依赖关系从基础到高级的顺序排列，例如：\n\n```c\nstatic int var1;\nstatic int var1;\n\nstatic void func1();\nstatic void func2();\n\n// object 1\n\nvoid object1_func1()\n{\n  // ..\n}\n\nvoid object1_func2() {\n    // ...\n     object1_func1();\n}\n\n\n// object 2\n\nvoid object2_func1()\n{\n  // ..\n}\n\nvoid object2_func2() {\n    // ...\n     object2_func1();\n}\n```\n\n注意！优先通过调整函数定义代码块的顺序来解决声明问题，而不是前置声明函数。\n\n### 未使用参数\n\n未使用的函数参数（包括回调签名里必须存在的 `void *arg`、事件回调的 `ui_event_t *e` 等）\n**不要写 `(void)xxx;`**。GCC、Clang、MSVC 都默认不警告未使用参数名，只有未使用局部变量\n才会警告。`(void)xxx;` 是冗余噪音，掩盖真正该处理的警告。\n\n❌ 禁止：\n```c\nstatic void on_event(ui_widget_t *w, ui_event_t *e, void *arg)\n{\n    (void)w;\n    (void)e;\n    (void)arg;\n    /* 实际逻辑 */\n}\n```\n\n✅ 允许：\n```c\nstatic void on_event(ui_widget_t *w, ui_event_t *e, void *arg)\n{\n    /* 直接用到的参数正常使用；用不到的参数名直接保留在签名里 */\n}\n```\n\n> 例外：C++ 模式下某些编译器会警告未使用参数，需要按上下文决定。LCUI 是纯 C，\n> 不适用此例外。\n\n### 事件处理器参数\n\n`ui_widget_on(widget, event, handler, listener_data)` 的第四个参数是监听器上下文，\n事件分发时通过 `e->data` 传给处理函数：\n\n```c\nstatic void on_click(ui_widget_t *w, ui_event_t *e, void *emit_arg)\n{\n        app_state_t *state = e->data;\n}\n\nui_widget_on(button, \"click\", on_click, state);\n```\n\n处理函数的第三个参数 `emit_arg` 来自 `ui_widget_emit_event(widget, event,\nemit_arg)`，不是 `ui_widget_on()` 的第四个参数。常规监听器必须从 `e->data`\n获取通过 `ui_widget_on()` 绑定的上下文；只有显式发射事件传入的上下文才使用\n处理函数的第三个参数。\n\n## 测试用例\n\n### 归属规则\n\n按下面优先级判定一个测试归属：\n\n1. case 实际 `#include` 的库头文件集合（含传递依赖）。\n2. 调用的运行时入口（`lcui_init` / `ui_init` / `pd_*_init` 等）。\n3. xmake target 上需要的 `add_deps`。\n\n仅触达单 lib（外加 yutil/ctest/标准库）的测试放 `lib/<name>/tests/`；触达两个及以上同级 lib，或依赖 `src/widgets/` 注册的 widget 类型的测试放 `tests/integration/`。\n\n### 文件与函数命名\n\n- 文件名：`test_<topic>.c`\n- 套件入口（lib 内）：`void test_<lib>_<topic>(void)`，如 `test_ui_xml_parser`、`test_pandagl_image_reader`\n- 套件入口（顶层集成）：`void test_<topic>(void)`，无前缀，如 `test_settings`\n- 套件入口必须在两个位置都注册：所属 lib 的 `tests/main.c` 与顶层 `tests/main.c` 中的 `suites[]` 表\n- 内部分组用 `static void <动词>_<group>(void)`，由 `ctest_describe` 注册\n\n### 描述文本风格\n\n- `ctest_describe(name, fn)` 的 `name` 是名词性主题，全小写空格分词，无 `test` 前缀。例：`\"widget opacity\"`、`\"flex layout\"`、`\"settings.fps_cap\"`\n- `ctest_equal_*(name, ...)` 的 `name` 用 `should ...` 行为陈述。例：`\"should default fps_cap to 120\"`、`\"should match parent border color\"`\n- 当上下文清晰（例如 layout case 中描述某 selector 对应的 box）时，可保留 jQuery 选择器风格的描述，无需强行加 should\n\n### 资源文件\n\n- 跨 lib 共享的 fixture 放 `tests/fixtures/`\n- 仅本 lib 用的 fixture 也建议复制到 `tests/fixtures/`（顶层 lcui-tests 与单 lib binary 共用同一 rundir）\n- xmake target 的 `set_rundir` 指向 `tests/fixtures/`\n- 测试代码加载资源时直接用文件名，不带目录前缀\n\n### 三种文件职责\n\n- `tests/integration/test_<topic>.c`：跨 lib 集成测试，自动断言。不调用 `lcui_main`，必要时由 `tests/previews/preview_<topic>.c` 提供可视诊断\n- `tests/scenes/<topic>_scene.{c,h}`：可视化场景搭建模块，签名 `void <topic>_scene_build(...)`。只构造 widget 树和应用样式，不做断言、不调用 `ctest_*`、不调用 `lcui_main`/`lcui_quit`。给 cases 与未来的 examples demo 共用\n- `lib/<name>/tests/test_<topic>.c`：纯 lib 测试，仅断言\n\n### 编写示例\n\n```c\n#include <ctest-custom.h>\n\nvoid test_my_case(void)\n{\n        ctest_equal_int(\"should add two numbers\", 1 + 1, 2);\n}\n```\n\n注册：\n\n```c\n/* lib/<name>/tests/main.c 或 tests/main.c */\nextern void test_my_case(void);\n\nstatic const ctest_suite_t suites[] = {\n        { \"my case\", test_my_case },\n        { NULL, NULL }\n};\n\nCTEST_MAIN(suites)\n```\n\n### 运行\n\n- 全量：`xmake test`\n- 按 pattern 过滤：`xmake test \"*/widget*\"`（匹配 target/test 名）\n- 按 group 过滤：`xmake test -g tests`\n- 单 binary 跑全部 suite：`xmake run <lib>-tests`，例如 `xmake run lcui-tests`\n- 单 binary 内细粒度过滤：`xmake run lcui-tests --grep=\"<pattern>\"`，子串匹配 suite 名\n- 不要使用 `xmake test \"lcui-tests/*\" -- --grep \"<pattern>\"`：当前参数转发不会让\n  `--grep` 在 `lcui-tests` 中生效，实际会运行整个 binary\n- 单 binary 列出 suite：`xmake run lcui-tests --list`\n- 内存检查：`xmake f --memcheck=y && xmake test`，调用 drmemory（Windows）或 valgrind（Linux）；恢复正常运行：`xmake f --memcheck=n`\n\n### 不要触碰\n\n- `lib/yutil/tests/`：使用旧 libtest 框架自管理，不并入 ctest 体系，不被 lcui-tests 收集\n\n## 重构约定\n\n### 合并重复分支\n\n当存在两个分支仅输入不同但后续处理相同（如选择 obs->root 或 ui_root），用局部变量合并公共逻辑，避免重复代码。\n\n```c\n/* before */\nif (ctx->logger) {\n    write_log(ctx->logger, msg);\n} else {\n    logger_t *logger = get_default_logger();\n    write_log(logger, msg);\n}\n\n/* after */\nlogger_t *logger = ctx->logger ? ctx->logger : get_default_logger();\nwrite_log(logger, msg);\n```\n\n### 提取公共逻辑\n\n若公共逻辑较长，可提取为独立函数，并保持调用路径一致，减少分叉实现。\n\n## LCUI CSS 引擎约束\n\n### 选择器\n\n- 仅支持：通配符 `*`、类型 `type`、类 `.cls`、ID `#id`、后代空格 `A B`\n- 不支持：子代 `>`、相邻兄弟 `+`、通用兄弟 `~`\n- 不支持：属性选择器 `[attr]` `[data-x]`\n- 不支持：功能性伪类 `:not()` `:is()` `:where()` `:has()` `:nth-child()`（解析器无 `(` 语法）\n- 不支持：伪元素 `::before` `::after`\n\n### 优先级\n\n- Rank：`GENERAL=0`，`TYPE=1`，`CLASS=10`，`PCLASS=10`，`ID=100`\n- 同 rank 用 `batch_num`（声明顺序）决胜，后声明覆盖先声明\n- 无 `!important` 机制\n- class 与 pclass rank 相同（都是 10）\n\n### 属性与值\n\n- `position`：仅 `static` / `relative` / `absolute`，无 `fixed`\n- `white-space`：仅 `normal` / `nowrap`\n- `border-style`：仅 `none` / `solid`\n- 无 `calc()` / `var()` / CSS 自定义属性\n- 无 `calc()` / `var()` / `em` / `rem` / `vh` / `vw` 单位（可用 `dp` / `px` / `pt` / `%`）\n- 无 `overflow` 属性\n\n## 指令\n\n### gen-commit\n\n用于生成符合 Angular 规范的提交信息，scope 应为 lib 目录下的任意目录名（例如：ui、css），标题长度限制在 80 字符以内，应结合本次会话内容生成，无需读取实际改动文件内容。\n"},"files":{"AGENTS.md":"## 代码格式\n\n遵循 .clang-format 文件中定义的规则，修改文件后需格式化。\n\n### 缩进\n\n使用八个空格缩进。\n\n### 代码结构\n\n源文件中的代码结构应该为：\n\n1. 预处理指令\n2. 类型\n3. 全局变量\n4. 函数声明\n5. 函数定义\n\n其中“函数定义”应该按照功能类别分组、按依赖关系从基础到高级的顺序排列，例如：\n\n```c\nstatic int var1;\nstatic int var1;\n\nstatic void func1();\nstatic void func2();\n\n// object 1\n\nvoid object1_func1()\n{\n  // ..\n}\n\nvoid object1_func2() {\n    // ...\n     object1_func1();\n}\n\n\n// object 2\n\nvoid object2_func1()\n{\n  // ..\n}\n\nvoid object2_func2() {\n    // ...\n     object2_func1();\n}\n```\n\n注意！优先通过调整函数定义代码块的顺序来解决声明问题，而不是前置声明函数。\n\n### 未使用参数\n\n未使用的函数参数（包括回调签名里必须存在的 `void *arg`、事件回调的 `ui_event_t *e` 等）\n**不要写 `(void)xxx;`**。GCC、Clang、MSVC 都默认不警告未使用参数名，只有未使用局部变量\n才会警告。`(void)xxx;` 是冗余噪音，掩盖真正该处理的警告。\n\n❌ 禁止：\n```c\nstatic void on_event(ui_widget_t *w, ui_event_t *e, void *arg)\n{\n    (void)w;\n    (void)e;\n    (void)arg;\n    /* 实际逻辑 */\n}\n```\n\n✅ 允许：\n```c\nstatic void on_event(ui_widget_t *w, ui_event_t *e, void *arg)\n{\n    /* 直接用到的参数正常使用；用不到的参数名直接保留在签名里 */\n}\n```\n\n> 例外：C++ 模式下某些编译器会警告未使用参数，需要按上下文决定。LCUI 是纯 C，\n> 不适用此例外。\n\n### 事件处理器参数\n\n`ui_widget_on(widget, event, handler, listener_data)` 的第四个参数是监听器上下文，\n事件分发时通过 `e->data` 传给处理函数：\n\n```c\nstatic void on_click(ui_widget_t *w, ui_event_t *e, void *emit_arg)\n{\n        app_state_t *state = e->data;\n}\n\nui_widget_on(button, \"click\", on_click, state);\n```\n\n处理函数的第三个参数 `emit_arg` 来自 `ui_widget_emit_event(widget, event,\nemit_arg)`，不是 `ui_widget_on()` 的第四个参数。常规监听器必须从 `e->data`\n获取通过 `ui_widget_on()` 绑定的上下文；只有显式发射事件传入的上下文才使用\n处理函数的第三个参数。\n\n## 测试用例\n\n### 归属规则\n\n按下面优先级判定一个测试归属：\n\n1. case 实际 `#include` 的库头文件集合（含传递依赖）。\n2. 调用的运行时入口（`lcui_init` / `ui_init` / `pd_*_init` 等）。\n3. xmake target 上需要的 `add_deps`。\n\n仅触达单 lib（外加 yutil/ctest/标准库）的测试放 `lib/<name>/tests/`；触达两个及以上同级 lib，或依赖 `src/widgets/` 注册的 widget 类型的测试放 `tests/integration/`。\n\n### 文件与函数命名\n\n- 文件名：`test_<topic>.c`\n- 套件入口（lib 内）：`void test_<lib>_<topic>(void)`，如 `test_ui_xml_parser`、`test_pandagl_image_reader`\n- 套件入口（顶层集成）：`void test_<topic>(void)`，无前缀，如 `test_settings`\n- 套件入口必须在两个位置都注册：所属 lib 的 `tests/main.c` 与顶层 `tests/main.c` 中的 `suites[]` 表\n- 内部分组用 `static void <动词>_<group>(void)`，由 `ctest_describe` 注册\n\n### 描述文本风格\n\n- `ctest_describe(name, fn)` 的 `name` 是名词性主题，全小写空格分词，无 `test` 前缀。例：`\"widget opacity\"`、`\"flex layout\"`、`\"settings.fps_cap\"`\n- `ctest_equal_*(name, ...)` 的 `name` 用 `should ...` 行为陈述。例：`\"should default fps_cap to 120\"`、`\"should match parent border color\"`\n- 当上下文清晰（例如 layout case 中描述某 selector 对应的 box）时，可保留 jQuery 选择器风格的描述，无需强行加 should\n\n### 资源文件\n\n- 跨 lib 共享的 fixture 放 `tests/fixtures/`\n- 仅本 lib 用的 fixture 也建议复制到 `tests/fixtures/`（顶层 lcui-tests 与单 lib binary 共用同一 rundir）\n- xmake target 的 `set_rundir` 指向 `tests/fixtures/`\n- 测试代码加载资源时直接用文件名，不带目录前缀\n\n### 三种文件职责\n\n- `tests/integration/test_<topic>.c`：跨 lib 集成测试，自动断言。不调用 `lcui_main`，必要时由 `tests/previews/preview_<topic>.c` 提供可视诊断\n- `tests/scenes/<topic>_scene.{c,h}`：可视化场景搭建模块，签名 `void <topic>_scene_build(...)`。只构造 widget 树和应用样式，不做断言、不调用 `ctest_*`、不调用 `lcui_main`/`lcui_quit`。给 cases 与未来的 examples demo 共用\n- `lib/<name>/tests/test_<topic>.c`：纯 lib 测试，仅断言\n\n### 编写示例\n\n```c\n#include <ctest-custom.h>\n\nvoid test_my_case(void)\n{\n        ctest_equal_int(\"should add two numbers\", 1 + 1, 2);\n}\n```\n\n注册：\n\n```c\n/* lib/<name>/tests/main.c 或 tests/main.c */\nextern void test_my_case(void);\n\nstatic const ctest_suite_t suites[] = {\n        { \"my case\", test_my_case },\n        { NULL, NULL }\n};\n\nCTEST_MAIN(suites)\n```\n\n### 运行\n\n- 全量：`xmake test`\n- 按 pattern 过滤：`xmake test \"*/widget*\"`（匹配 target/test 名）\n- 按 group 过滤：`xmake test -g tests`\n- 单 binary 跑全部 suite：`xmake run <lib>-tests`，例如 `xmake run lcui-tests`\n- 单 binary 内细粒度过滤：`xmake run lcui-tests --grep=\"<pattern>\"`，子串匹配 suite 名\n- 不要使用 `xmake test \"lcui-tests/*\" -- --grep \"<pattern>\"`：当前参数转发不会让\n  `--grep` 在 `lcui-tests` 中生效，实际会运行整个 binary\n- 单 binary 列出 suite：`xmake run lcui-tests --list`\n- 内存检查：`xmake f --memcheck=y && xmake test`，调用 drmemory（Windows）或 valgrind（Linux）；恢复正常运行：`xmake f --memcheck=n`\n\n### 不要触碰\n\n- `lib/yutil/tests/`：使用旧 libtest 框架自管理，不并入 ctest 体系，不被 lcui-tests 收集\n\n## 重构约定\n\n### 合并重复分支\n\n当存在两个分支仅输入不同但后续处理相同（如选择 obs->root 或 ui_root），用局部变量合并公共逻辑，避免重复代码。\n\n```c\n/* before */\nif (ctx->logger) {\n    write_log(ctx->logger, msg);\n} else {\n    logger_t *logger = get_default_logger();\n    write_log(logger, msg);\n}\n\n/* after */\nlogger_t *logger = ctx->logger ? ctx->logger : get_default_logger();\nwrite_log(logger, msg);\n```\n\n### 提取公共逻辑\n\n若公共逻辑较长，可提取为独立函数，并保持调用路径一致，减少分叉实现。\n\n## LCUI CSS 引擎约束\n\n### 选择器\n\n- 仅支持：通配符 `*`、类型 `type`、类 `.cls`、ID `#id`、后代空格 `A B`\n- 不支持：子代 `>`、相邻兄弟 `+`、通用兄弟 `~`\n- 不支持：属性选择器 `[attr]` `[data-x]`\n- 不支持：功能性伪类 `:not()` `:is()` `:where()` `:has()` `:nth-child()`（解析器无 `(` 语法）\n- 不支持：伪元素 `::before` `::after`\n\n### 优先级\n\n- Rank：`GENERAL=0`，`TYPE=1`，`CLASS=10`，`PCLASS=10`，`ID=100`\n- 同 rank 用 `batch_num`（声明顺序）决胜，后声明覆盖先声明\n- 无 `!important` 机制\n- class 与 pclass rank 相同（都是 10）\n\n### 属性与值\n\n- `position`：仅 `static` / `relative` / `absolute`，无 `fixed`\n- `white-space`：仅 `normal` / `nowrap`\n- `border-style`：仅 `none` / `solid`\n- 无 `calc()` / `var()` / CSS 自定义属性\n- 无 `calc()` / `var()` / `em` / `rem` / `vh` / `vw` 单位（可用 `dp` / `px` / `pt` / `%`）\n- 无 `overflow` 属性\n\n## 指令\n\n### gen-commit\n\n用于生成符合 Angular 规范的提交信息，scope 应为 lib 目录下的任意目录名（例如：ui、css），标题长度限制在 80 字符以内，应结合本次会话内容生成，无需读取实际改动文件内容。\n"},"items":[{"name":"AGENTS.md","path":"AGENTS.md","title":"AGENTS.md","content":"## 代码格式\n\n遵循 .clang-format 文件中定义的规则，修改文件后需格式化。\n\n### 缩进\n\n使用八个空格缩进。\n\n### 代码结构\n\n源文件中的代码结构应该为：\n\n1. 预处理指令\n2. 类型\n3. 全局变量\n4. 函数声明\n5. 函数定义\n\n其中“函数定义”应该按照功能类别分组、按依赖关系从基础到高级的顺序排列，例如：\n\n```c\nstatic int var1;\nstatic int var1;\n\nstatic void func1();\nstatic void func2();\n\n// object 1\n\nvoid object1_func1()\n{\n  // ..\n}\n\nvoid object1_func2() {\n    // ...\n     object1_func1();\n}\n\n\n// object 2\n\nvoid object2_func1()\n{\n  // ..\n}\n\nvoid object2_func2() {\n    // ...\n     object2_func1();\n}\n```\n\n注意！优先通过调整函数定义代码块的顺序来解决声明问题，而不是前置声明函数。\n\n### 未使用参数\n\n未使用的函数参数（包括回调签名里必须存在的 `void *arg`、事件回调的 `ui_event_t *e` 等）\n**不要写 `(void)xxx;`**。GCC、Clang、MSVC 都默认不警告未使用参数名，只有未使用局部变量\n才会警告。`(void)xxx;` 是冗余噪音，掩盖真正该处理的警告。\n\n❌ 禁止：\n```c\nstatic void on_event(ui_widget_t *w, ui_event_t *e, void *arg)\n{\n    (void)w;\n    (void)e;\n    (void)arg;\n    /* 实际逻辑 */\n}\n```\n\n✅ 允许：\n```c\nstatic void on_event(ui_widget_t *w, ui_event_t *e, void *arg)\n{\n    /* 直接用到的参数正常使用；用不到的参数名直接保留在签名里 */\n}\n```\n\n> 例外：C++ 模式下某些编译器会警告未使用参数，需要按上下文决定。LCUI 是纯 C，\n> 不适用此例外。\n\n### 事件处理器参数\n\n`ui_widget_on(widget, event, handler, listener_data)` 的第四个参数是监听器上下文，\n事件分发时通过 `e->data` 传给处理函数：\n\n```c\nstatic void on_click(ui_widget_t *w, ui_event_t *e, void *emit_arg)\n{\n        app_state_t *state = e->data;\n}\n\nui_widget_on(button, \"click\", on_click, state);\n```\n\n处理函数的第三个参数 `emit_arg` 来自 `ui_widget_emit_event(widget, event,\nemit_arg)`，不是 `ui_widget_on()` 的第四个参数。常规监听器必须从 `e->data`\n获取通过 `ui_widget_on()` 绑定的上下文；只有显式发射事件传入的上下文才使用\n处理函数的第三个参数。\n\n## 测试用例\n\n### 归属规则\n\n按下面优先级判定一个测试归属：\n\n1. case 实际 `#include` 的库头文件集合（含传递依赖）。\n2. 调用的运行时入口（`lcui_init` / `ui_init` / `pd_*_init` 等）。\n3. xmake target 上需要的 `add_deps`。\n\n仅触达单 lib（外加 yutil/ctest/标准库）的测试放 `lib/<name>/tests/`；触达两个及以上同级 lib，或依赖 `src/widgets/` 注册的 widget 类型的测试放 `tests/integration/`。\n\n### 文件与函数命名\n\n- 文件名：`test_<topic>.c`\n- 套件入口（lib 内）：`void test_<lib>_<topic>(void)`，如 `test_ui_xml_parser`、`test_pandagl_image_reader`\n- 套件入口（顶层集成）：`void test_<topic>(void)`，无前缀，如 `test_settings`\n- 套件入口必须在两个位置都注册：所属 lib 的 `tests/main.c` 与顶层 `tests/main.c` 中的 `suites[]` 表\n- 内部分组用 `static void <动词>_<group>(void)`，由 `ctest_describe` 注册\n\n### 描述文本风格\n\n- `ctest_describe(name, fn)` 的 `name` 是名词性主题，全小写空格分词，无 `test` 前缀。例：`\"widget opacity\"`、`\"flex layout\"`、`\"settings.fps_cap\"`\n- `ctest_equal_*(name, ...)` 的 `name` 用 `should ...` 行为陈述。例：`\"should default fps_cap to 120\"`、`\"should match parent border color\"`\n- 当上下文清晰（例如 layout case 中描述某 selector 对应的 box）时，可保留 jQuery 选择器风格的描述，无需强行加 should\n\n### 资源文件\n\n- 跨 lib 共享的 fixture 放 `tests/fixtures/`\n- 仅本 lib 用的 fixture 也建议复制到 `tests/fixtures/`（顶层 lcui-tests 与单 lib binary 共用同一 rundir）\n- xmake target 的 `set_rundir` 指向 `tests/fixtures/`\n- 测试代码加载资源时直接用文件名，不带目录前缀\n\n### 三种文件职责\n\n- `tests/integration/test_<topic>.c`：跨 lib 集成测试，自动断言。不调用 `lcui_main`，必要时由 `tests/previews/preview_<topic>.c` 提供可视诊断\n- `tests/scenes/<topic>_scene.{c,h}`：可视化场景搭建模块，签名 `void <topic>_scene_build(...)`。只构造 widget 树和应用样式，不做断言、不调用 `ctest_*`、不调用 `lcui_main`/`lcui_quit`。给 cases 与未来的 examples demo 共用\n- `lib/<name>/tests/test_<topic>.c`：纯 lib 测试，仅断言\n\n### 编写示例\n\n```c\n#include <ctest-custom.h>\n\nvoid test_my_case(void)\n{\n        ctest_equal_int(\"should add two numbers\", 1 + 1, 2);\n}\n```\n\n注册：\n\n```c\n/* lib/<name>/tests/main.c 或 tests/main.c */\nextern void test_my_case(void);\n\nstatic const ctest_suite_t suites[] = {\n        { \"my case\", test_my_case },\n        { NULL, NULL }\n};\n\nCTEST_MAIN(suites)\n```\n\n### 运行\n\n- 全量：`xmake test`\n- 按 pattern 过滤：`xmake test \"*/widget*\"`（匹配 target/test 名）\n- 按 group 过滤：`xmake test -g tests`\n- 单 binary 跑全部 suite：`xmake run <lib>-tests`，例如 `xmake run lcui-tests`\n- 单 binary 内细粒度过滤：`xmake run lcui-tests --grep=\"<pattern>\"`，子串匹配 suite 名\n- 不要使用 `xmake test \"lcui-tests/*\" -- --grep \"<pattern>\"`：当前参数转发不会让\n  `--grep` 在 `lcui-tests` 中生效，实际会运行整个 binary\n- 单 binary 列出 suite：`xmake run lcui-tests --list`\n- 内存检查：`xmake f --memcheck=y && xmake test`，调用 drmemory（Windows）或 valgrind（Linux）；恢复正常运行：`xmake f --memcheck=n`\n\n### 不要触碰\n\n- `lib/yutil/tests/`：使用旧 libtest 框架自管理，不并入 ctest 体系，不被 lcui-tests 收集\n\n## 重构约定\n\n### 合并重复分支\n\n当存在两个分支仅输入不同但后续处理相同（如选择 obs->root 或 ui_root），用局部变量合并公共逻辑，避免重复代码。\n\n```c\n/* before */\nif (ctx->logger) {\n    write_log(ctx->logger, msg);\n} else {\n    logger_t *logger = get_default_logger();\n    write_log(logger, msg);\n}\n\n/* after */\nlogger_t *logger = ctx->logger ? ctx->logger : get_default_logger();\nwrite_log(logger, msg);\n```\n\n### 提取公共逻辑\n\n若公共逻辑较长，可提取为独立函数，并保持调用路径一致，减少分叉实现。\n\n## LCUI CSS 引擎约束\n\n### 选择器\n\n- 仅支持：通配符 `*`、类型 `type`、类 `.cls`、ID `#id`、后代空格 `A B`\n- 不支持：子代 `>`、相邻兄弟 `+`、通用兄弟 `~`\n- 不支持：属性选择器 `[attr]` `[data-x]`\n- 不支持：功能性伪类 `:not()` `:is()` `:where()` `:has()` `:nth-child()`（解析器无 `(` 语法）\n- 不支持：伪元素 `::before` `::after`\n\n### 优先级\n\n- Rank：`GENERAL=0`，`TYPE=1`，`CLASS=10`，`PCLASS=10`，`ID=100`\n- 同 rank 用 `batch_num`（声明顺序）决胜，后声明覆盖先声明\n- 无 `!important` 机制\n- class 与 pclass rank 相同（都是 10）\n\n### 属性与值\n\n- `position`：仅 `static` / `relative` / `absolute`，无 `fixed`\n- `white-space`：仅 `normal` / `nowrap`\n- `border-style`：仅 `none` / `solid`\n- 无 `calc()` / `var()` / CSS 自定义属性\n- 无 `calc()` / `var()` / `em` / `rem` / `vh` / `vw` 单位（可用 `dp` / `px` / `pt` / `%`）\n- 无 `overflow` 属性\n\n## 指令\n\n### gen-commit\n\n用于生成符合 Angular 规范的提交信息，scope 应为 lib 目录下的任意目录名（例如：ui、css），标题长度限制在 80 字符以内，应结合本次会话内容生成，无需读取实际改动文件内容。\n","category":"root","tokens":1295}]}