✨ feat(vscode): 代码阅读的词可以讲源码里别处的名字(Segment.refers):FastAPI 路径里的 {user_id} 讲函数的参数,单击参数时跟着高亮,⌘ + 点击跳到参数

This commit is contained in:
cruldra committed 2026-09-27 21:18:19 +08:00
1 parent 25569fa506
commit 15790ce7c8
9 files changed
+82 -22

No files matched your search

+23 -4
View File
@@ -266,8 +266,11 @@ function routeOf(decorator: Node, routers: ReadonlyMap<string, Router>): Route |
return { decorator, router, method: method.toUpperCase(), call, path: call.positional[0] ?? call.keywords.get('path') }
}
/** 路径里的一段:`{参数}` 按变量着色,其余按字符串,带源码下标;写的不是字符串时交给翻译插件翻。 */
function pathSegments(node: Node | undefined, env: Env): Inline[] {
/**
* 路径里的一段:`{参数}` 按变量着色,其余按字符串,都带源码下标;花括号里的名字讲的是函数的同名参数(params),
* 标上 refers,高亮参数的各处出现时它也跟着亮、⌘ + 点击跳到参数。写的不是字符串时交给翻译插件翻。
*/
function pathSegments(node: Node | undefined, params: ReadonlyMap<string, Node>, env: Env): Inline[] {
if (!node)
return []
const content = stringContent(node)
@@ -276,7 +279,22 @@ function pathSegments(node: Node | undefined, env: Env): Inline[] {
const segments: Segment[] = []
let at = content.node?.startIndex ?? node.startIndex
for (const part of content.text.split(/(\{[^}]*\})/).filter(Boolean)) {
segments.push({ text: part, role: part.startsWith('{') ? 'variable' : 'string', offset: at })
if (!part.startsWith('{')) {
segments.push({ text: part, role: 'string', offset: at })
}
else {
// `{file_path:path}`:冒号前面是参数名,后面是转换器
const colon = part.indexOf(':')
const key = part.slice(1, colon < 0 ? -1 : colon)
const rest = part.slice(1 + key.length, -1)
const param = params.get(key.trim())
const pieces: Segment[] = [
{ text: '{', role: 'variable', offset: at },
{ text: key, role: 'variable', offset: at + 1, ...(param && { refers: range(param) }) },
{ text: `${rest}}`, role: 'variable', offset: at + 1 + key.length },
]
segments.push(...pieces.filter(piece => piece.text !== ''))
}
at += part.length
}
return segments
@@ -537,7 +555,8 @@ function routeCard(block: FunctionBlock, route: Route, env: Env): RuleCard {
const at = (place: Place): Placed[] => placed.filter(item => item.place === place)
const body = at('body')
const url = [...pathSegments(router.prefix, env), ...pathSegments(route.path, env)]
const params = new Map(facts.parameters.flatMap(({ name: param }) => param.type === 'identifier' ? [[param.text, param] as const] : []))
const url = [...pathSegments(router.prefix, params, env), ...pathSegments(route.path, params, env)]
const request: PropertyItem[] = [
requestItem(words.items.url, url),
requestItem(words.items.method, [{ text: route.method, role: 'keyword', ...(METHOD_COLORS[route.method] && { color: METHOD_COLORS[route.method] }) }]),