🐛 fix(vscode): Rust 库规则只经契约和同目录共用代码

This commit is contained in:
cruldra committed 2026-10-04 14:42:46 +08:00
1 parent 340c81084a
commit 13e71507d6
12 files changed
+244 -242

No files matched your search

+182
View File
@@ -0,0 +1,182 @@
import type { ClassBlock, CodeBlock, EnumBlock, FunctionBlock, ImplBlock, ImportBlock, Inline, PropertyItem, PropertyRow, TokenRole, TraitBlock } from '../contract'
import type { RustVisibility } from './rustTree'
import { bodyFunctions, docSentence, isMethod, matchArms, oneLine, returnText, signatureParams, structFields, variantPayload } from './rustTree'
/** 把类型、名字画成原文。翻译插件传入时,名字带源码下标。 */
export interface RustSay {
name: (node: import('../contract').Node, role: TokenRole) => Inline[]
source: (node: import('../contract').Node, role?: TokenRole) => Inline[]
}
const VISIBILITY: Record<RustVisibility, string> = {
public: '公开',
module: '本模块',
super: '父模块',
crate: '本 crate',
}
/** 块上的可见性:属性盖过 facts,没写是本模块。 */
export function visibilityWord(block: CodeBlock): string {
const overridden = block.attributes?.access
if (overridden && overridden in VISIBILITY)
return VISIBILITY[overridden as RustVisibility]
if ('facts' in block && 'access' in block.facts && block.facts.access === 'public')
return VISIBILITY.public
return VISIBILITY.module
}
export function importRows(block: ImportBlock, say: RustSay): PropertyRow[] {
const [source] = block.facts.sources
return [
{ label: '来源', value: source ? say.source(source, 'type') : [hint('—')] },
{
label: '导入项',
value: [hint(`${block.facts.items.length} 个`)],
columns: ['名字', '别名'],
items: block.facts.items.map((item) => {
if (item.kind === 'namespace')
return { cells: [[hint('*')], [hint('—')]] }
if (item.kind !== 'named')
return { cells: [[hint('—')], [hint('—')]] }
return {
cells: [say.name(item.name, 'type'), item.alias ? say.name(item.alias, 'type') : [hint('—')]],
defines: range(item.name),
}
}),
},
]
}
export function structRows(block: ClassBlock, say: RustSay): PropertyRow[] {
const fields = structFields(block.node)
return [
nameRow(block.facts.name, say, 'type'),
...docRow(block.facts.doc),
visibilityRow(block),
...tableRow('字段', ['字段', '类型', '可见性'], fields.map(field => ({
cells: [
say.name(field.name, 'variable'),
say.source(field.type, 'type'),
[keyword(VISIBILITY[field.visibility])],
],
defines: range(field.name),
}))),
]
}
export function enumRows(block: EnumBlock, say: RustSay): PropertyRow[] {
return [
nameRow(block.facts.name, say, 'type'),
...docRow(block.facts.doc),
...tableRow('变体', ['变体', '携带的数据'], block.facts.members.map(member => ({
cells: [say.name(member.name, 'type'), [hint(variantPayload(member.value) ?? '—')]],
defines: range(member.name),
}))),
]
}
export function functionRows(block: FunctionBlock, say: RustSay): PropertyRow[] {
const arms = matchArms(block.node)
return [
nameRow(block.facts.name, say, 'function'),
...docRow(block.facts.doc),
...(block.facts.async ? [{ label: '异步', value: [keyword('是')] }] : []),
visibilityRow(block),
...tableRow(isMethod(block.node) ? '参数' : '输入参数', ['名称', '类型'], block.facts.parameters.map(param => ({
cells: [say.name(param.name, 'variable'), param.type ? say.source(param.type, 'type') : [hint('—')]],
defines: range(param.name),
}))),
{ label: '返回', value: [plain(returnText(block.node))] },
...tableRow('分情况', ['分支', '做什么'], arms.map(arm => ({
cells: [[plain(arm.pattern)], [hint(arm.does)]],
})), '支'),
]
}
export function traitRows(block: TraitBlock, say: RustSay): PropertyRow[] {
const methods = bodyFunctions(block.node)
return [
nameRow(block.facts.name, say, 'type'),
...docRow(block.facts.doc),
...tableRow('方法', ['名称', '参数', '返回'], methods.map((method) => {
const name = method.childForFieldName('name')
return {
cells: [
name ? say.name(name, 'function') : [hint('匿名')],
[plain(signatureParams(method))],
[plain(returnText(method))],
],
...(name && { defines: range(name) }),
}
})),
]
}
export function implRows(block: ImplBlock, say: RustSay): PropertyRow[] {
const methods = block.children.filter((child): child is FunctionBlock => child.kind === 'function')
const title: Inline[] = block.facts.name
? [...say.name(block.facts.name, 'type'), plain(' 的方法')]
: [hint('实现')]
return [
{ label: '名称', value: title, ...(block.facts.name && { defines: range(block.facts.name) }) },
...docRow(block.facts.doc),
...tableRow('方法', ['名称', '参数', '返回'], methods.map((method) => {
const name = method.facts.name
return {
cells: [
name ? say.name(name, 'function') : [hint('匿名')],
[plain(signatureParams(method.node))],
[plain(returnText(method.node))],
],
...(name && { defines: range(name) }),
}
})),
]
}
function nameRow(name: import('../contract').Node | undefined, say: RustSay, role: TokenRole): PropertyRow {
return {
label: '名称',
value: name ? say.name(name, role) : [hint('匿名')],
...(name && { defines: range(name) }),
}
}
function docRow(doc: import('../contract').Node | undefined): PropertyRow[] {
const sentence = docSentence(doc)
return sentence ? [{ label: '说明', value: { markdown: sentence } }] : []
}
function visibilityRow(block: CodeBlock): PropertyRow {
return { label: '可见性', value: [keyword(visibilityWord(block))] }
}
/** 没有行就不占一行。countUnit 默认「个」,分情况用「支」。 */
function tableRow(label: string, columns: string[], items: PropertyItem[], countUnit = '个'): PropertyRow[] {
if (items.length === 0)
return []
return [{ label, value: [hint(`${items.length} ${countUnit}`)], columns, items }]
}
function hint(text: string): Inline {
return { text, role: 'hint' }
}
function plain(text: string): Inline {
return { text, role: 'plain' }
}
function keyword(text: string): Inline {
return { text, role: 'keyword' }
}
function range(node: import('../contract').Node): { startIndex: number, endIndex: number } {
return { startIndex: node.startIndex, endIndex: node.endIndex }
}
/** 名字、类型照抄源码,名字带上下标,点了能跳到定义。 */
export function plainSay(): RustSay {
return {
name: (node, role) => [{ text: node.text, role, offset: node.startIndex }],
source: (node, role = 'type') => [{ text: oneLine(node.text), role, offset: node.startIndex }],
}
}