优化: aichat 工具体验补强(切生成会话占位气泡治丢首响应/read_symbol符号级提示/失败引导/审批失败toast) + 修复 WorkflowDagDisplay 崩页与 aiChat i18n 缺key
This commit is contained in:
@@ -92,6 +92,56 @@ pub fn is_supported_ext(ext: &str) -> bool {
|
||||
matches!(ext, "rs" | "ts" | "tsx" | "js" | "jsx" | "vue" | "go" | "java" | "py")
|
||||
}
|
||||
|
||||
/// 判断 source 内容是否真的含可提取的函数/类/结构体定义(AC-4 read_file 符号级命中提示)。
|
||||
///
|
||||
/// read_file 读取成功后据此决定是否追加「改用 read_symbol」提示:仅当内容里真的存在
|
||||
/// DEFINITION_KINDS 定义节点才提示——比旧按扩展名判断更准,无定义的文件不瞎提示。
|
||||
/// 与 read_symbol 同语法树逻辑(grammar_for + DEFINITION_KINDS + Vue 切 <script> 段借 ts),
|
||||
/// 但不提取符号只探测存在性,开销低。**复用现有函数,不新写正则**。
|
||||
/// 无 grammar / 解析失败 / Vue 无 script / 无定义节点 → false(不提示)。
|
||||
pub(crate) fn contains_definition(source: &str, ext: &str) -> bool {
|
||||
let ext_lower = ext.to_lowercase();
|
||||
let (parse_source, parse_ext): (String, &str) = if ext_lower == "vue" {
|
||||
// Vue 逻辑在 <script> 段,切段借 ts(与 read_symbol 的 extract_vue_script 同源)
|
||||
match extract_vue_script(source) {
|
||||
Some((script, _)) => (script, "ts"),
|
||||
None => return false, // 纯 template/style 无可提取符号
|
||||
}
|
||||
} else {
|
||||
(source.to_string(), ext_lower.as_str())
|
||||
};
|
||||
|
||||
let grammar = match grammar_for(parse_ext) {
|
||||
Some(g) => g,
|
||||
None => return false, // 不支持的语言不提示
|
||||
};
|
||||
|
||||
let mut parser = Parser::new();
|
||||
if parser.set_language(&grammar).is_err() {
|
||||
return false; // grammar 加载失败(ABI 不兼容)不提示
|
||||
}
|
||||
let tree = match parser.parse(&parse_source, None) {
|
||||
Some(t) => t,
|
||||
None => return false, // 解析失败不提示
|
||||
};
|
||||
|
||||
tree_has_definition(&tree.root_node())
|
||||
}
|
||||
|
||||
/// 递归遍历语法树,判断是否含任一 DEFINITION_KINDS 定义节点(contains_definition 的遍历内核)。
|
||||
fn tree_has_definition(node: &Node<'_>) -> bool {
|
||||
if DEFINITION_KINDS.contains(&node.kind()) {
|
||||
return true;
|
||||
}
|
||||
let mut cursor = node.walk();
|
||||
for child in node.children(&mut cursor) {
|
||||
if tree_has_definition(&child) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// 提取 Vue SFC 的 `<script>` 段内容(借 TS 解析)。
|
||||
///
|
||||
/// Vue 单文件组件逻辑在 `<script setup lang="ts">` 内,template/style 不做符号提取。
|
||||
@@ -633,4 +683,52 @@ fn outer() {
|
||||
let calls = skeleton["calls"].as_array().expect("骨架应含 calls");
|
||||
assert!(!calls.is_empty(), "应提取出内部调用");
|
||||
}
|
||||
|
||||
// ============================================================
|
||||
// contains_definition — AC-4 read_file 符号级命中检测
|
||||
// ============================================================
|
||||
|
||||
#[test]
|
||||
fn test_contains_definition_hits_definitions() {
|
||||
// 含 fn/struct 定义 → true(应提示改用 read_symbol)
|
||||
assert!(contains_definition(RUST_FIXTURE, "rs"));
|
||||
assert!(contains_definition("pub fn main() {}\n", "rs"));
|
||||
assert!(contains_definition("struct Config { name: String }\n", "rs"));
|
||||
// TS/JS
|
||||
assert!(contains_definition("export function greet() { return 1; }", "ts"));
|
||||
assert!(contains_definition("const handler = () => {};", "js"));
|
||||
// Go / Java / Python
|
||||
assert!(contains_definition("package main\nfunc main() {}\n", "go"));
|
||||
assert!(contains_definition("class Foo { void bar() {} }", "java"));
|
||||
assert!(contains_definition("def foo():\n pass\n", "py"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains_definition_plain_text_false() {
|
||||
// 无定义节点的纯文本/纯注释 → false(符号级命中,不瞎提示)
|
||||
assert!(!contains_definition("just some text\nwith no definitions\n", "rs"));
|
||||
assert!(!contains_definition("// 只有注释\n/* 多行注释 */\n", "rs"));
|
||||
// 字符串字面量里有 fn 字样但不是定义
|
||||
assert!(!contains_definition("let msg = \"fn main() {}\";\nconsole.log(msg);", "js"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains_definition_unsupported_ext_or_parse_fail() {
|
||||
// Ruby 无 grammar → false
|
||||
assert!(!contains_definition("def foo()\n puts 'hi'\nend\n", "rb"));
|
||||
// 无扩展名 → false
|
||||
assert!(!contains_definition("any content", ""));
|
||||
// 大小写不敏感("RS" 等价 "rs")
|
||||
assert!(contains_definition("pub fn main() {}\n", "RS"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_contains_definition_vue() {
|
||||
// Vue 含 <script> 函数 → true
|
||||
let vue = "<template><div>{{ msg }}</div></template>\n\n<script setup lang=\"ts\">\nfunction greet() {}\n</script>\n";
|
||||
assert!(contains_definition(vue, "vue"));
|
||||
// 无 <script> 段(纯 template/style)→ false
|
||||
let no_script = "<template><div>hi</div></template>\n<style></style>";
|
||||
assert!(!contains_definition(no_script, "vue"));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user