From 13e71507d65da12feb3c5315460146536b26da6d Mon Sep 17 00:00:00 2001 From: cruldra Date: Sun, 4 Oct 2026 14:42:46 +0800 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20fix(vscode):=20Rust=20=E5=BA=93?= =?UTF-8?q?=E8=A7=84=E5=88=99=E5=8F=AA=E7=BB=8F=E5=A5=91=E7=BA=A6=E5=92=8C?= =?UTF-8?q?=E5=90=8C=E7=9B=AE=E5=BD=95=E5=85=B1=E7=94=A8=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/superpowers/specs/code-reader/spec.md | 5 +- vscode/src/codeReader/languages/rust.ts | 221 +----------------- vscode/src/codeReader/rules/axum.ts | 3 +- vscode/src/codeReader/rules/rustImpl.ts | 2 +- vscode/src/codeReader/{ => rules}/rustRows.ts | 16 +- vscode/src/codeReader/rules/rustTree.ts | 220 +++++++++++++++++ vscode/src/codeReader/rules/serde.ts | 7 +- vscode/src/codeReader/rules/sqlx.ts | 3 +- vscode/src/codeReader/rules/tauri.ts | 2 +- vscode/src/codeReader/rules/thiserror.ts | 3 +- vscode/src/codeReader/translators/rustZh.ts | 2 +- .../src/codeReader/kindIcons.test.tsx | 2 + 12 files changed, 244 insertions(+), 242 deletions(-) rename vscode/src/codeReader/{ => rules}/rustRows.ts (92%) create mode 100644 vscode/src/codeReader/rules/rustTree.ts diff --git a/docs/superpowers/specs/code-reader/spec.md b/docs/superpowers/specs/code-reader/spec.md index 17800f6..d4da1ab 100644 --- a/docs/superpowers/specs/code-reader/spec.md +++ b/docs/superpowers/specs/code-reader/spec.md @@ -1957,8 +1957,9 @@ vscode/src/codeReader/ languages/shared.ts 语言插件共用的建树工具;异常类(withExceptions:按整份文件认异常类,类块换成异常块,并类属性、取构造参数) languages/typescript.ts (call:调用的结构,new 是新建;TYPESCRIPT_EXCEPTIONS:认异常类的父类名、类字段、constructor) languages/python.ts (iteration:推导式的结构;call:调用的结构;PYTHON_EXCEPTIONS:自带的异常类、类属性、__init__) - languages/rust.ts Rust:代码块树、可见性、文档注释第一句、字段 / 变体 / match - rustRows.ts Rust 属性表的行(中文直译和库规则共用) + languages/rust.ts Rust:代码块树 + rules/rustTree.ts Rust 库规则读语法树的办法(可见性、属性、字段、变体、match) + rules/rustRows.ts Rust 属性表的行(中文直译和库规则共用) rules/rustImpl.ts impl 的方法放进方法表那一行 rules/serde.ts serde:可序列化的结构体 rules/thiserror.ts thiserror:错误枚举 diff --git a/vscode/src/codeReader/languages/rust.ts b/vscode/src/codeReader/languages/rust.ts index dc5dc52..61c3887 100644 --- a/vscode/src/codeReader/languages/rust.ts +++ b/vscode/src/codeReader/languages/rust.ts @@ -1,193 +1,10 @@ -import type { Access, BlockAttributes, ClassBlock, ClassFacts, CodeBlock, EnumBlock, FunctionBlock, ImplBlock, ImportBlock, ImportItem, LanguageAdapter, Node, ParameterFacts, TokenRole, TraitBlock } from '../contract' +import type { Access, ClassBlock, ClassFacts, CodeBlock, EnumBlock, FunctionBlock, ImplBlock, ImportBlock, ImportItem, LanguageAdapter, Node, ParameterFacts, TokenRole, TraitBlock } from '../contract' import * as path from 'node:path' +import { leadingAttributes, visibilityFacts } from '../rules/rustTree' import { compoundShape, extendHeader, headerSpan, leafBlock, leafShape, named } from './shared' -/** 可见性:pub 是公开,没写是本模块,pub(super) 是父模块,pub(crate) 是本 crate。 */ -export type RustVisibility = 'public' | 'module' | 'super' | 'crate' - const STORAGE = new Set(['pub', 'async', 'const', 'static', 'mut', 'let']) -/** 一条说明的第一句,句号留着。 */ -export function firstSentence(text: string): string { - const trimmed = text.trim() - const sentence = trimmed.match(/^[\s\S]*?[。!?.!?]/) - return (sentence ? sentence[0] : trimmed.split('\n')[0] ?? '').trim() -} - -/** 文档注释去掉记号后的第一句;普通注释是整段去掉记号。 */ -export function commentPlain(node: Node): string { - const doc = node.childForFieldName('doc') - const raw = doc ? doc.text : node.text.replace(/^\/\/[/!]?\s?/, '').replace(/^\/\*[*!]?\s?/, '').replace(/\s*\*\/$/, '') - return raw.replace(/\n/g, ' ').trim() -} - -/** 说明行用的第一句。没有文字时没有。 */ -export function docSentence(node: Node | undefined): string | undefined { - if (!node) - return undefined - const sentence = firstSentence(commentPlain(node)) - return sentence || undefined -} - -/** 空白收成一个空格,方便属性表里的类型、签名。 */ -export function oneLine(text: string): string { - return text.replace(/\s+/g, ' ').trim() -} - -/** 节点上的可见性。pub(in …) 不在这四档里,按本 crate 算(只本包能用)。 */ -export function rustVisibility(node: Node): RustVisibility { - const vis = named(node).find(child => child.type === 'visibility_modifier') - if (!vis) - return 'module' - const words = new Set(vis.children.map(child => child?.type)) - if (words.has('super')) - return 'super' - if (words.has('crate') || words.has('in')) - return 'crate' - return 'public' -} - -/** 公开写在 facts.access 上;其余写在块的 access 属性上,盖过 facts。 */ -export function visibilityFacts(node: Node): { access?: Access, attributes?: BlockAttributes } { - const visibility = rustVisibility(node) - return visibility === 'public' ? { access: 'public' } : { attributes: { access: visibility } } -} - -/** 参数表括号里的原文,空白收成一行。 */ -export function signatureParams(fn: Node): string { - const params = fn.childForFieldName('parameters') - if (!params) - return '' - return oneLine(params.text.replace(/^\(/, '').replace(/\)$/, '')) -} - -/** 返回类型原文;没写是 ()。 */ -export function returnText(fn: Node): string { - const returned = fn.childForFieldName('return_type') - return returned ? oneLine(returned.text) : '()' -} - -/** 函数体里直接写的 match,每一支的模式和「做什么」。 */ -export function matchArms(fn: Node): { pattern: string, does: string }[] { - const body = fn.childForFieldName('body') - if (!body) - return [] - const arms: { pattern: string, does: string }[] = [] - for (const statement of named(body)) { - const expr = statement.type === 'expression_statement' ? named(statement)[0] : statement - if (expr?.type !== 'match_expression') - continue - const block = expr.childForFieldName('body') - for (const arm of named(block).filter(child => child.type === 'match_arm')) { - const pattern = arm.childForFieldName('pattern') - if (pattern) - arms.push({ pattern: oneLine(pattern.text), does: armDoes(arm) }) - } - } - return arms -} - -/** 变体携带的数据:没带是空的,元组变体是类型,结构变体是字段原文。body 是变体的 body。 */ -export function variantPayload(body: Node | undefined): string | undefined { - if (!body) - return undefined - if (body.type === 'ordered_field_declaration_list') { - const types = named(body).filter(child => child.type !== 'attribute_item').map(child => oneLine(child.text)) - return types.join(', ') || undefined - } - return oneLine(body.text) -} - -/** 写在这条前面、紧挨着的属性(#[…]),从外往里。 */ -export function leadingAttributes(node: Node): Node[] { - const attrs: Node[] = [] - let prev = node.previousNamedSibling - while (prev?.type === 'attribute_item') { - attrs.unshift(prev) - prev = prev.previousNamedSibling - } - return attrs -} - -/** 属性的名字:get、serde、axum::post、tauri::command。 */ -export function attributeName(attributeItem: Node): string | undefined { - const attribute = named(attributeItem).find(child => child.type === 'attribute') - const head = attribute ? named(attribute)[0] : undefined - return head?.text -} - -/** 这条自己的属性,含写在它前面的。 */ -export function itemAttributes(node: Node): Node[] { - return [...leadingAttributes(node), ...named(node).filter(child => child.type === 'attribute_item')] -} - -/** derive(...) 里列出的名字。 */ -export function deriveNames(node: Node): string[] { - const names: string[] = [] - for (const item of itemAttributes(node)) { - if (attributeName(item) !== 'derive') - continue - const attribute = named(item).find(child => child.type === 'attribute') - const tree = attribute?.children.find(child => child?.type === 'token_tree') - if (!tree) - continue - for (const name of named(tree)) { - if (name.type === 'identifier') - names.push(name.text) - else if (name.type === 'scoped_identifier') - names.push(name.childForFieldName('name')?.text ?? name.text) - } - } - return names -} - -/** 字符串字面量里的原文,不含引号。 */ -export function stringContent(node: Node | undefined): string | undefined { - if (!node) - return undefined - if (node.type === 'string_content') - return node.text - const content = node.children.find(child => child?.type === 'string_content') - return content?.text -} - -/** 宏调用的名字和括号里的具名实参。 */ -export function macroInvocation(node: Node): { name: string, args: Node[] } | undefined { - if (node.type !== 'macro_invocation') - return undefined - const macro = node.childForFieldName('macro') - const args = node.children.find(child => child?.type === 'token_tree') - if (!macro || !args) - return undefined - return { name: macro.text, args: named(args) } -} - -/** 函数写在 impl 或 trait 里面,参数表叫「参数」而不是「输入参数」。 */ -export function isMethod(node: Node): boolean { - const parent = node.parent - return parent?.type === 'declaration_list' && (parent.parent?.type === 'impl_item' || parent.parent?.type === 'trait_item') -} - -/** 结构体的字段:名字、类型、可见性。元组结构体没有名字,不进这张表。 */ -export function structFields(node: Node): { name: Node, type: Node, visibility: RustVisibility }[] { - const body = node.childForFieldName('body') - if (body?.type !== 'field_declaration_list') - return [] - return named(body).flatMap((field) => { - if (field.type !== 'field_declaration') - return [] - const name = field.childForFieldName('name') - const type = field.childForFieldName('type') - return name && type ? [{ name, type, visibility: rustVisibility(field) }] : [] - }) -} - -/** trait 或 impl 主体里的函数(含只写签名的)。 */ -export function bodyFunctions(node: Node): Node[] { - const body = node.childForFieldName('body') - return named(body).filter(child => child.type === 'function_item' || child.type === 'function_signature_item') -} - export function createRustAdapter(wasmDir: string): LanguageAdapter { return { id: 'rust', @@ -440,40 +257,6 @@ function isAsync(node: Node): boolean { return modifiers?.children.some(child => child?.type === 'async') ?? false } -function armDoes(arm: Node): string { - const comment = firstComment(arm) - if (comment) - return firstSentence(commentPlain(comment)) || '—' - const value = arm.childForFieldName('value') - if (!value) - return '—' - if (value.type === 'return_expression') { - const returned = named(value)[0] - return returned ? `返回 ${oneLine(returned.text)}` : '返回' - } - if (value.type === 'block') { - const inner = firstComment(value) - if (inner) - return firstSentence(commentPlain(inner)) || '—' - const statement = named(value)[0] - return statement ? oneLine(statement.text) : '—' - } - return oneLine(value.text) -} - -function firstComment(node: Node): Node | undefined { - if (node.type === 'line_comment' || node.type === 'block_comment') - return node - for (const child of node.children) { - if (!child) - continue - const found = firstComment(child) - if (found) - return found - } - return undefined -} - function rustTokenRole(leaf: Node): TokenRole { if (leaf.type === 'line_comment' || leaf.type === 'block_comment' || inside(leaf, 'line_comment') || inside(leaf, 'block_comment')) return 'comment' diff --git a/vscode/src/codeReader/rules/axum.ts b/vscode/src/codeReader/rules/axum.ts index b3cd558..ecb230d 100644 --- a/vscode/src/codeReader/rules/axum.ts +++ b/vscode/src/codeReader/rules/axum.ts @@ -1,6 +1,5 @@ import type { FunctionBlock, Inline, KindBadge, LibraryRule, Node, PropertyItem, PropertyRow, RuleCard, ThemeColor } from '../contract' -import { attributeName, docSentence, oneLine, returnText, stringContent } from '../languages/rust' -import { named } from '../languages/shared' +import { attributeName, docSentence, named, oneLine, returnText, stringContent } from './rustTree' /** 和 FastAPI 接口同一个蓝。 */ const COLOR: ThemeColor = { dark: '#61afef', light: '#1a6fb5' } diff --git a/vscode/src/codeReader/rules/rustImpl.ts b/vscode/src/codeReader/rules/rustImpl.ts index 8d6dfeb..3eda7fd 100644 --- a/vscode/src/codeReader/rules/rustImpl.ts +++ b/vscode/src/codeReader/rules/rustImpl.ts @@ -1,5 +1,5 @@ import type { ImplBlock, KindBadge, LibraryRule, RuleCard, ThemeColor } from '../contract' -import { implRows, plainSay } from '../rustRows' +import { implRows, plainSay } from './rustRows' /** 和函数卡同一个黄,实现块看起来仍是函数那一挂。 */ const COLOR: ThemeColor = { dark: '#dcdcaa', light: '#795e26' } diff --git a/vscode/src/codeReader/rustRows.ts b/vscode/src/codeReader/rules/rustRows.ts similarity index 92% rename from vscode/src/codeReader/rustRows.ts rename to vscode/src/codeReader/rules/rustRows.ts index 23900d0..40e8c07 100644 --- a/vscode/src/codeReader/rustRows.ts +++ b/vscode/src/codeReader/rules/rustRows.ts @@ -1,11 +1,11 @@ -import type { ClassBlock, CodeBlock, EnumBlock, FunctionBlock, ImplBlock, ImportBlock, Inline, PropertyItem, PropertyRow, TokenRole, TraitBlock } from './contract' -import type { RustVisibility } from './languages/rust' -import { bodyFunctions, docSentence, isMethod, matchArms, oneLine, returnText, signatureParams, structFields, variantPayload } from './languages/rust' +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[] + name: (node: import('../contract').Node, role: TokenRole) => Inline[] + source: (node: import('../contract').Node, role?: TokenRole) => Inline[] } const VISIBILITY: Record = { @@ -134,7 +134,7 @@ export function implRows(block: ImplBlock, say: RustSay): PropertyRow[] { ] } -function nameRow(name: import('./contract').Node | undefined, say: RustSay, role: TokenRole): PropertyRow { +function nameRow(name: import('../contract').Node | undefined, say: RustSay, role: TokenRole): PropertyRow { return { label: '名称', value: name ? say.name(name, role) : [hint('匿名')], @@ -142,7 +142,7 @@ function nameRow(name: import('./contract').Node | undefined, say: RustSay, role } } -function docRow(doc: import('./contract').Node | undefined): PropertyRow[] { +function docRow(doc: import('../contract').Node | undefined): PropertyRow[] { const sentence = docSentence(doc) return sentence ? [{ label: '说明', value: { markdown: sentence } }] : [] } @@ -170,7 +170,7 @@ function keyword(text: string): Inline { return { text, role: 'keyword' } } -function range(node: import('./contract').Node): { startIndex: number, endIndex: number } { +function range(node: import('../contract').Node): { startIndex: number, endIndex: number } { return { startIndex: node.startIndex, endIndex: node.endIndex } } /** 名字、类型照抄源码,名字带上下标,点了能跳到定义。 */ diff --git a/vscode/src/codeReader/rules/rustTree.ts b/vscode/src/codeReader/rules/rustTree.ts new file mode 100644 index 0000000..eb110cc --- /dev/null +++ b/vscode/src/codeReader/rules/rustTree.ts @@ -0,0 +1,220 @@ +import type { Access, BlockAttributes, Node } from '../contract' + +/** 具名子节点,空的跳过。 */ +export function named(node: Node | null | undefined): Node[] { + return node?.namedChildren.filter((child): child is Node => child !== null) ?? [] +} + +export type RustVisibility = 'public' | 'module' | 'super' | 'crate' +export function firstSentence(text: string): string { + const trimmed = text.trim() + const sentence = trimmed.match(/^[\s\S]*?[。!?.!?]/) + return (sentence ? sentence[0] : trimmed.split('\n')[0] ?? '').trim() +} + +/** 文档注释去掉记号后的第一句;普通注释是整段去掉记号。 */ +export function commentPlain(node: Node): string { + const doc = node.childForFieldName('doc') + const raw = doc ? doc.text : node.text.replace(/^\/\/[/!]?\s?/, '').replace(/^\/\*[*!]?\s?/, '').replace(/\s*\*\/$/, '') + return raw.replace(/\n/g, ' ').trim() +} + +/** 说明行用的第一句。没有文字时没有。 */ +export function docSentence(node: Node | undefined): string | undefined { + if (!node) + return undefined + const sentence = firstSentence(commentPlain(node)) + return sentence || undefined +} + +/** 空白收成一个空格,方便属性表里的类型、签名。 */ +export function oneLine(text: string): string { + return text.replace(/\s+/g, ' ').trim() +} + +/** 节点上的可见性。pub(in …) 不在这四档里,按本 crate 算(只本包能用)。 */ +export function rustVisibility(node: Node): RustVisibility { + const vis = named(node).find(child => child.type === 'visibility_modifier') + if (!vis) + return 'module' + const words = new Set(vis.children.map(child => child?.type)) + if (words.has('super')) + return 'super' + if (words.has('crate') || words.has('in')) + return 'crate' + return 'public' +} + +/** 公开写在 facts.access 上;其余写在块的 access 属性上,盖过 facts。 */ +export function visibilityFacts(node: Node): { access?: Access, attributes?: BlockAttributes } { + const visibility = rustVisibility(node) + return visibility === 'public' ? { access: 'public' } : { attributes: { access: visibility } } +} + +/** 参数表括号里的原文,空白收成一行。 */ +export function signatureParams(fn: Node): string { + const params = fn.childForFieldName('parameters') + if (!params) + return '' + return oneLine(params.text.replace(/^\(/, '').replace(/\)$/, '')) +} + +/** 返回类型原文;没写是 ()。 */ +export function returnText(fn: Node): string { + const returned = fn.childForFieldName('return_type') + return returned ? oneLine(returned.text) : '()' +} + +/** 函数体里直接写的 match,每一支的模式和「做什么」。 */ +export function matchArms(fn: Node): { pattern: string, does: string }[] { + const body = fn.childForFieldName('body') + if (!body) + return [] + const arms: { pattern: string, does: string }[] = [] + for (const statement of named(body)) { + const expr = statement.type === 'expression_statement' ? named(statement)[0] : statement + if (expr?.type !== 'match_expression') + continue + const block = expr.childForFieldName('body') + for (const arm of named(block).filter(child => child.type === 'match_arm')) { + const pattern = arm.childForFieldName('pattern') + if (pattern) + arms.push({ pattern: oneLine(pattern.text), does: armDoes(arm) }) + } + } + return arms +} + +/** 变体携带的数据:没带是空的,元组变体是类型,结构变体是字段原文。body 是变体的 body。 */ +export function variantPayload(body: Node | undefined): string | undefined { + if (!body) + return undefined + if (body.type === 'ordered_field_declaration_list') { + const types = named(body).filter(child => child.type !== 'attribute_item').map(child => oneLine(child.text)) + return types.join(', ') || undefined + } + return oneLine(body.text) +} + +/** 写在这条前面、紧挨着的属性(#[…]),从外往里。 */ +export function leadingAttributes(node: Node): Node[] { + const attrs: Node[] = [] + let prev = node.previousNamedSibling + while (prev?.type === 'attribute_item') { + attrs.unshift(prev) + prev = prev.previousNamedSibling + } + return attrs +} + +/** 属性的名字:get、serde、axum::post、tauri::command。 */ +export function attributeName(attributeItem: Node): string | undefined { + const attribute = named(attributeItem).find(child => child.type === 'attribute') + const head = attribute ? named(attribute)[0] : undefined + return head?.text +} + +/** 这条自己的属性,含写在它前面的。 */ +export function itemAttributes(node: Node): Node[] { + return [...leadingAttributes(node), ...named(node).filter(child => child.type === 'attribute_item')] +} + +/** derive(...) 里列出的名字。 */ +export function deriveNames(node: Node): string[] { + const names: string[] = [] + for (const item of itemAttributes(node)) { + if (attributeName(item) !== 'derive') + continue + const attribute = named(item).find(child => child.type === 'attribute') + const tree = attribute?.children.find(child => child?.type === 'token_tree') + if (!tree) + continue + for (const name of named(tree)) { + if (name.type === 'identifier') + names.push(name.text) + else if (name.type === 'scoped_identifier') + names.push(name.childForFieldName('name')?.text ?? name.text) + } + } + return names +} + +/** 字符串字面量里的原文,不含引号。 */ +export function stringContent(node: Node | undefined): string | undefined { + if (!node) + return undefined + if (node.type === 'string_content') + return node.text + const content = node.children.find(child => child?.type === 'string_content') + return content?.text +} + +/** 宏调用的名字和括号里的具名实参。 */ +export function macroInvocation(node: Node): { name: string, args: Node[] } | undefined { + if (node.type !== 'macro_invocation') + return undefined + const macro = node.childForFieldName('macro') + const args = node.children.find(child => child?.type === 'token_tree') + if (!macro || !args) + return undefined + return { name: macro.text, args: named(args) } +} + +/** 函数写在 impl 或 trait 里面,参数表叫「参数」而不是「输入参数」。 */ +export function isMethod(node: Node): boolean { + const parent = node.parent + return parent?.type === 'declaration_list' && (parent.parent?.type === 'impl_item' || parent.parent?.type === 'trait_item') +} + +/** 结构体的字段:名字、类型、可见性。元组结构体没有名字,不进这张表。 */ +export function structFields(node: Node): { name: Node, type: Node, visibility: RustVisibility }[] { + const body = node.childForFieldName('body') + if (body?.type !== 'field_declaration_list') + return [] + return named(body).flatMap((field) => { + if (field.type !== 'field_declaration') + return [] + const name = field.childForFieldName('name') + const type = field.childForFieldName('type') + return name && type ? [{ name, type, visibility: rustVisibility(field) }] : [] + }) +} + +/** trait 或 impl 主体里的函数(含只写签名的)。 */ +export function bodyFunctions(node: Node): Node[] { + const body = node.childForFieldName('body') + return named(body).filter(child => child.type === 'function_item' || child.type === 'function_signature_item') +} +function armDoes(arm: Node): string { + const comment = firstComment(arm) + if (comment) + return firstSentence(commentPlain(comment)) || '—' + const value = arm.childForFieldName('value') + if (!value) + return '—' + if (value.type === 'return_expression') { + const returned = named(value)[0] + return returned ? `返回 ${oneLine(returned.text)}` : '返回' + } + if (value.type === 'block') { + const inner = firstComment(value) + if (inner) + return firstSentence(commentPlain(inner)) || '—' + const statement = named(value)[0] + return statement ? oneLine(statement.text) : '—' + } + return oneLine(value.text) +} + +function firstComment(node: Node): Node | undefined { + if (node.type === 'line_comment' || node.type === 'block_comment') + return node + for (const child of node.children) { + if (!child) + continue + const found = firstComment(child) + if (found) + return found + } + return undefined +} diff --git a/vscode/src/codeReader/rules/serde.ts b/vscode/src/codeReader/rules/serde.ts index 17460bf..9140e0d 100644 --- a/vscode/src/codeReader/rules/serde.ts +++ b/vscode/src/codeReader/rules/serde.ts @@ -1,8 +1,7 @@ import type { ClassBlock, Inline, KindBadge, LibraryRule, Node, PropertyRow, RuleCard, SegmentGroup, ThemeColor, TokenRole } from '../contract' -import type { rustVisibility } from '../languages/rust' -import { attributeName, deriveNames, docSentence, itemAttributes, leadingAttributes, oneLine, stringContent, structFields } from '../languages/rust' -import { named } from '../languages/shared' -import { visibilityWord } from '../rustRows' +import type { rustVisibility } from './rustTree' +import { visibilityWord } from './rustRows' +import { attributeName, deriveNames, docSentence, itemAttributes, leadingAttributes, named, oneLine, stringContent, structFields } from './rustTree' /** 和结构体同一个青,序列化只是名称后的标签,不另换边框色。 */ const COLOR: ThemeColor = { dark: '#4ec9b0', light: '#267f99' } diff --git a/vscode/src/codeReader/rules/sqlx.ts b/vscode/src/codeReader/rules/sqlx.ts index 9d93287..b53e1f5 100644 --- a/vscode/src/codeReader/rules/sqlx.ts +++ b/vscode/src/codeReader/rules/sqlx.ts @@ -1,6 +1,5 @@ import type { CodeBlock, Inline, KindBadge, LibraryRule, Node, PropertyRow, RuleCard, ThemeColor } from '../contract' -import { commentPlain, firstSentence, macroInvocation, oneLine, stringContent } from '../languages/rust' -import { named } from '../languages/shared' +import { commentPlain, firstSentence, macroInvocation, named, oneLine, stringContent } from './rustTree' /** 查询卡用字符串那种橙。 */ const COLOR: ThemeColor = { dark: '#ce9178', light: '#a31515' } diff --git a/vscode/src/codeReader/rules/tauri.ts b/vscode/src/codeReader/rules/tauri.ts index 7b2363f..ec188f7 100644 --- a/vscode/src/codeReader/rules/tauri.ts +++ b/vscode/src/codeReader/rules/tauri.ts @@ -1,5 +1,5 @@ import type { FunctionBlock, Inline, KindBadge, LibraryRule, Node, PropertyRow, RuleCard, SegmentGroup, ThemeColor } from '../contract' -import { attributeName, docSentence, oneLine, returnText } from '../languages/rust' +import { attributeName, docSentence, oneLine, returnText } from './rustTree' /** 桌面命令的边框用这个橙。 */ const COLOR: ThemeColor = { dark: '#e5c07b', light: '#9a6a00' } diff --git a/vscode/src/codeReader/rules/thiserror.ts b/vscode/src/codeReader/rules/thiserror.ts index 7d41961..44d90f6 100644 --- a/vscode/src/codeReader/rules/thiserror.ts +++ b/vscode/src/codeReader/rules/thiserror.ts @@ -1,6 +1,5 @@ import type { EnumBlock, Inline, KindBadge, LibraryRule, Node, PropertyRow, RuleCard, SegmentGroup, ThemeColor } from '../contract' -import { attributeName, commentPlain, deriveNames, docSentence, firstSentence, stringContent, variantPayload } from '../languages/rust' -import { named } from '../languages/shared' +import { attributeName, commentPlain, deriveNames, docSentence, firstSentence, named, stringContent, variantPayload } from './rustTree' /** 错误卡用异常那种红。 */ const COLOR: ThemeColor = { dark: '#f14c4c', light: '#cd3131' } diff --git a/vscode/src/codeReader/translators/rustZh.ts b/vscode/src/codeReader/translators/rustZh.ts index bc0db4d..3b9ca65 100644 --- a/vscode/src/codeReader/translators/rustZh.ts +++ b/vscode/src/codeReader/translators/rustZh.ts @@ -1,5 +1,5 @@ import type { FactBlock, Node, PropertyRow, SourceDocument, Translator } from '../contract' -import { enumRows, functionRows, implRows, importRows, plainSay, structRows, traitRows } from '../rustRows' +import { enumRows, functionRows, implRows, importRows, plainSay, structRows, traitRows } from '../rules/rustRows' import { createZhTemplateTranslator, KIND_ZH, ZH_ATTRIBUTE_NAMES } from './zhTemplate' const say = plainSay() diff --git a/vscode/webview-ui/src/codeReader/kindIcons.test.tsx b/vscode/webview-ui/src/codeReader/kindIcons.test.tsx index ee4af04..54a1e99 100644 --- a/vscode/webview-ui/src/codeReader/kindIcons.test.tsx +++ b/vscode/webview-ui/src/codeReader/kindIcons.test.tsx @@ -21,6 +21,8 @@ describe('块的种类图标', () => { import: 'import', function: 'square-function', class: 'box', + trait: 'network', + impl: 'square-function', type: 'braces', enum: 'list-ordered', exception: 'triangle-alert',