✨ feat(vscode): Rust 的模块、常量和外部函数拆成卡片
This commit is contained in:
1 parent
e6345e3309
commit
04c4b9f710
13 files changed
+174
-46
No files matched your search
@@ -148,7 +148,7 @@
|
||||
| directive 解析指令 | `terminal` | stage 阶段 | `layers` | run 执行 | `square-terminal` |
|
||||
| copy 复制 | `copy` | setting 设置 | `sliders-horizontal` | label 标签 | `tag` |
|
||||
| health 健康检查 | `activity` | start 启动 | `play` | trait 特质 | `network` |
|
||||
| impl 实现 | `square-function` | | | | |
|
||||
| impl 实现 | `square-function` | module 模块 | `layers` | | |
|
||||
|
||||
库规则的种类用规则给的图标(`KindBadge.icon`),跟在语言的种类图标后面:SQLAlchemy 数据表 `database`、数据类 `package`、Pydantic 数据模型 `braces`(和类型块同一个图标,颜色不同)、Celery 应用 `server-cog`、定时任务 `calendar-clock`、FastAPI 接口 `globe`、FastAPI 路由器 `network`、React 组件 `atom`、副作用 `zap`、事件处理 `mouse-pointer-click`、serde 可序列化 `braces`、thiserror 错误 `triangle-alert`、axum 接口 `globe`、sqlx 查询 `database`、tauri 桌面命令 `square-function`。数据类写了 `frozen=True` 再加一把锁(`lock`,悬停「不可修改」)。实现块再由规则 `rust.impl` 换成卡片,左边因此有两个「实现」图标。
|
||||
|
||||
@@ -574,7 +574,7 @@
|
||||
```ts
|
||||
export type BlockKind =
|
||||
| 'import' | 'function' | 'class' | 'enum' | 'exception' | 'type' | 'field' | 'const' | 'variable'
|
||||
| 'trait' | 'impl' // Rust:特质、实现(属性表)
|
||||
| 'trait' | 'impl' | 'module' // Rust:特质、实现、模块(属性表)
|
||||
| 'if' | 'else' | 'loop' | 'try' | 'catch' | 'finally' | 'return' | 'statement' | 'comment'
|
||||
| 'interpreter' | 'options' | 'case' | 'command' | 'pipeline' // shell:解释器、选项(属性表),分情况、命令、管道(一行译文)
|
||||
| 'directive' | 'stage' | 'run' | 'copy' | 'setting' | 'label' | 'health' | 'start' // Dockerfile:解析指令、阶段、健康检查、启动(属性表),执行、复制、设置、标签(一行译文)
|
||||
@@ -1748,8 +1748,11 @@ shell 脚本大半是一条条命令,一条命令读成什么取决于命令
|
||||
- `enum` → enum。变体表「变体 | 携带的数据」:没带数据是「—」,`Failed(String)` 写类型,`Running { pid: u32 }` 写字段原文。
|
||||
- `fn` → function。有才显示:说明、异步(只有 `async fn` 写「是」)、可见性、输入参数表「名称 | 类型」、返回(没写是 `()`)。函数体里直接写的 `match` 收成「分情况」表「分支 | 做什么」,N 支:优先用这一支里的注释,否则是 `return` 那句或这一支的第一句,不展开成子块。
|
||||
- `trait` → trait(图标 `network`,颜色同声明关键字的蓝)。方法表「名称 | 参数 | 返回」,只列签名,不展开函数体。
|
||||
- `impl` → impl(图标 `square-function`,颜色同函数)。标题是「某类型 的方法」(`impl Trait for Type` 取 Type)。方法是子块。不看导入的规则 `rules/rustImpl.ts`(`libraries: []`,种类 `rust.impl`)把每张方法卡放进方法表那一行,点方法名展开,和 React 事件处理同一条路。方法卡的参数表叫「参数」。
|
||||
- 其余(`let`、`const`、宏调用)→ statement。`//` 注释单独成块。
|
||||
- `impl` → impl(图标 `square-function`,颜色同函数)。标题是「某类型 的方法」(`impl Trait for Type` 取 Type)。方法是子块。不看导入的规则 `rules/rustImpl.ts`(`libraries: []`,种类 `rust.impl`)把每张方法卡放进方法表那一行,点方法名展开,和 React 事件处理同一条路。方法卡的参数表叫「参数」。身体里的 `const`、`static` 不收成语句,跟文件顶层同一条路(见下)。
|
||||
- `mod 名字 { … }`(`mod_item` 有 `body`)→ module(中文「模块」,图标 `layers`,颜色同阶段)。卡片行:名称、说明(有文档注释才有)、可见性(没写也是本模块,跟结构体一样总有这一行)。身体用和文件顶层同一套规则拆成子块,排在这张卡片下面,不另做一张表把子块塞进某一行。模块自己的文档注释留在模块卡片上,身体里每项自己的文档注释留在那一项上。`mod 名字;` 没有身体,不拆,仍是一条 statement。
|
||||
- `const`(`const_item`)→ const,`static`(`static_item`)→ variable。属性表不另写一套译文,走中文模板里常量 / 变量那一套:名称、说明、访问级别(公开才有,模板里叫「公共」)、类型、值(`static` 的值叫「初始值」)。文件顶层、模块身体、impl 身体同一条路。
|
||||
- `extern "…" { … }`(`foreign_mod_item`)不单独成一块源码。里面的函数签名(`function_signature_item`,没有函数体)是函数卡片,跟普通函数一样有名称、说明、可见性、参数、返回,作为所在这一层(模块、文件顶层或 impl)的子块。
|
||||
- 其余(`let`、宏调用)→ statement。不拆函数体。`//` 注释单独成块。模块身体里宏调用后面多出来的那个空 `;`(`empty_statement`)不成块。
|
||||
|
||||
### 属性表信息(facts)从哪来
|
||||
|
||||
@@ -1765,7 +1768,7 @@ shell 脚本大半是一条条命令,一条命令读成什么取决于命令
|
||||
- Shell:解释器取 `#!` 后面的整句,第一个词是 `env` 的是按 PATH 找、程序名是它后面那个词,否则是写死的路径、程序名是路径最后一节。选项:每个开关一项,单字母换成 bash 的长名字(e → errexit、u → nounset、x → xtrace……),`-o 名字` 照写,`-` 开、`+` 关。变量:`variable_assignment` 的 name / value,声明里没给值的只有 name。函数:name 是函数名,doc 是紧贴在上面的注释;`positional` 是主体里(不进嵌套的函数)用到的 `$N` / `${N}` / `${N:-…}`,照位置排,`local x="$N"`、`x=$N` 给它起名字;`prints` 是没重定向到别处的 `echo` / `printf`(进 if、循环、分情况,不进 `$(…)`、管道、嵌套的函数);`captured` 看同一文件里有没有 `$(函数名 …)`;`returns` 是主体里的 `return` 命令。
|
||||
- Dockerfile:解析指令是每行注释 `# 名字=值` 的名字(小写)和值;阶段取 `image_spec` 的 name / tag / digest 字段、`as` 字段(image_alias),stage 看镜像名是不是前面某个阶段的名字(不分大小写),选项是 `param`、`mount_param` 节点的原文 `--名字=值`(值在语法树里没有单独的节点,按原文拆,记下值从哪开始);变量是 `env_pair` 的 name / value、`arg_instruction` 的 name / default;健康检查的 none 看有没有 NONE,检查命令是里面的 `cmd_instruction`;数组写法取 `json_string_array`,shell 写法取 `shell_command` 里各个 `shell_fragment`(`line_continuation` 不算),只有一个 `<<EOT` 的取它下面 `heredoc_block` 从第一行到最后一行。
|
||||
- Python 变量:`assignment` 的 left / type / right,说明是紧跟在后面的属性 docstring 的字符串节点(见上面代码块树规则);right 是 `dictionary` 时 entries 是它的具名子节点(注释除外):`pair` 的 key / value(value 又是 `dictionary` 时连它的 entries)、`dictionary_splat` 里的表达式。
|
||||
- Rust:函数的 name / parameters / return_type,`async` 只在写了时填;`self` 的类型节点是整个接收者(`&mut self`)。结构体、枚举、特质、实现的名称、说明、可见性见「Rust」。字段和变体携带的数据由中文直译读语法树,不另做 facts。
|
||||
- Rust:函数(含 `extern` 块里没有函数体的 `function_signature_item`)的 name / parameters / return_type,`async` 只在写了时填;`self` 的类型节点是整个接收者(`&mut self`)。结构体、枚举、特质、实现、模块的名称、说明、可见性见「Rust」(模块用 ClassFacts:name、doc、access)。`const`、`static` 的名称、类型、值是 `const_item` / `static_item` 的 name / type / value(VariableFacts 的一项 declarator),可见性同别的项:`pub` 写在 `facts.access`,其余写在块的 `access` 属性上。字段和变体携带的数据由中文直译读语法树,不另做 facts。
|
||||
|
||||
## 中文模板直译
|
||||
|
||||
@@ -1918,7 +1921,7 @@ type BlockView = BlockViewBase & ({ translation: PreviewText, table?: PreviewTab
|
||||
|
||||
带自己颜色的段(`Segment.color`,库规则按库的配色给,例如 FastAPI 的 HTTP 方法、成功的状态码):暗色、亮色两个写在元素的 style 上(`--color-dark` / `--color-light`),`.cr-colored` 按主题挑一个,盖过词性的颜色;词性照旧报(`role`)。
|
||||
|
||||
种类(种类图标的颜色 + 块底 7% + 边框 35%;亮色主题同色系;图标见「预览(代码块树)」):import 导入 #c586c0;function 函数、impl 实现 #dcdcaa;class 类、type 类型 #4ec9b0;trait 特质同声明关键字的蓝;enum 枚举 #b180d7(亮色 #652d90);exception 异常 #f14c4c(亮色 #cd3131,和尝试、捕获、最终同一色系,更红一些);field 字段、const 常量、variable 变量 #9cdcfe;if 条件、else 否则 #ce9178;loop 循环 #8f9cff;try 尝试、catch 捕获、finally 最终 #f48771;return 返回 #89d185;statement 语句 #9d9d9d;comment 注释 #6a9955(虚线框);Shell 的 interpreter 解释器同语句 #9d9d9d,options 选项 #e5c07b(亮色 #9a6a00),case 分情况同条件 #ce9178,command 命令、pipeline 管道 #d7ba7d(亮色 #7c5f12);Dockerfile 的 directive 解析指令同语句,stage 阶段 #56b6c2(亮色 #127f8c),run 执行同命令,copy 复制同导入,setting 设置同选项,label 标签同变量,health 健康检查同尝试 / 捕获,start 启动同返回(原型 DOCKER_KINDS 的颜色);库规则的种类用规则给的颜色(`badge.color` 的 dark / light,webview 写在块的 style 上按主题挑),内置 SQLAlchemy 数据表 #e8a860 / #a3590d,Celery 应用 #98c379 / #4d7f17,定时任务 #56b6c2 / #127f8c,数据类 #ef7fb0 / #b3306c,FastAPI 接口 #61afef / #1a6fb5,FastAPI 路由器 #7aa2f7 / #34548a。编辑状态:底色 `--vscode-editor-background`,边框 `--vscode-focusBorder`。
|
||||
种类(种类图标的颜色 + 块底 7% + 边框 35%;亮色主题同色系;图标见「预览(代码块树)」):import 导入 #c586c0;function 函数、impl 实现 #dcdcaa;class 类、type 类型 #4ec9b0;trait 特质同声明关键字的蓝;enum 枚举 #b180d7(亮色 #652d90);exception 异常 #f14c4c(亮色 #cd3131,和尝试、捕获、最终同一色系,更红一些);field 字段、const 常量、variable 变量 #9cdcfe;if 条件、else 否则 #ce9178;loop 循环 #8f9cff;try 尝试、catch 捕获、finally 最终 #f48771;return 返回 #89d185;statement 语句 #9d9d9d;comment 注释 #6a9955(虚线框);Shell 的 interpreter 解释器同语句 #9d9d9d,options 选项 #e5c07b(亮色 #9a6a00),case 分情况同条件 #ce9178,command 命令、pipeline 管道 #d7ba7d(亮色 #7c5f12);Dockerfile 的 directive 解析指令同语句,stage 阶段、module 模块 #56b6c2(亮色 #127f8c),run 执行同命令,copy 复制同导入,setting 设置同选项,label 标签同变量,health 健康检查同尝试 / 捕获,start 启动同返回(原型 DOCKER_KINDS 的颜色);库规则的种类用规则给的颜色(`badge.color` 的 dark / light,webview 写在块的 style 上按主题挑),内置 SQLAlchemy 数据表 #e8a860 / #a3590d,Celery 应用 #98c379 / #4d7f17,定时任务 #56b6c2 / #127f8c,数据类 #ef7fb0 / #b3306c,FastAPI 接口 #61afef / #1a6fb5,FastAPI 路由器 #7aa2f7 / #34548a。编辑状态:底色 `--vscode-editor-background`,边框 `--vscode-focusBorder`。
|
||||
|
||||
## 代码位置
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ function factAttributes(block: CodeBlock): Partial<Record<CommonAttribute, strin
|
||||
return { access: block.facts.access, abstract: flag(block.facts.abstract) }
|
||||
case 'trait':
|
||||
case 'impl':
|
||||
case 'module':
|
||||
return { access: block.facts.access }
|
||||
case 'enum':
|
||||
case 'exception':
|
||||
|
||||
@@ -144,6 +144,7 @@ function ownName(block: CodeBlock): Node | undefined {
|
||||
case 'class':
|
||||
case 'enum':
|
||||
case 'exception':
|
||||
case 'module':
|
||||
return block.facts.name
|
||||
case 'const':
|
||||
case 'variable':
|
||||
|
||||
@@ -12,7 +12,7 @@ export type { Node }
|
||||
*/
|
||||
export type BlockKind
|
||||
= | 'import' | 'function' | 'class' | 'enum' | 'exception' | 'type' | 'field' | 'const' | 'variable'
|
||||
| 'trait' | 'impl'
|
||||
| 'trait' | 'impl' | 'module'
|
||||
| 'if' | 'else' | 'loop' | 'try' | 'catch' | 'finally' | 'return' | 'statement' | 'comment'
|
||||
| 'interpreter' | 'options' | 'case' | 'command' | 'pipeline'
|
||||
| 'directive' | 'stage' | 'run' | 'copy' | 'setting' | 'label' | 'health' | 'start'
|
||||
@@ -479,6 +479,7 @@ export interface ClassBlock extends BlockShape { kind: 'class', facts: ClassFact
|
||||
export interface TraitBlock extends BlockShape { kind: 'trait', facts: ClassFacts }
|
||||
/** Rust 的 impl:标题是「某类型 的方法」,方法是子块,放进方法表的某一行。 */
|
||||
export interface ImplBlock extends BlockShape { kind: 'impl', facts: ClassFacts }
|
||||
export interface ModuleBlock extends BlockShape { kind: 'module', facts: ClassFacts }
|
||||
/** 枚举块的头部是整个枚举(成员都在属性表里讲),没有子块;库规则认出来的枚举(Python)是整个类,留下的方法等是子块。 */
|
||||
export interface EnumBlock extends BlockShape { kind: 'enum', facts: EnumFacts }
|
||||
/** 异常块的头部是整个类(类属性都在属性表里讲),留下的方法(含构造函数)等是子块。 */
|
||||
@@ -496,7 +497,7 @@ export interface StageBlock extends BlockShape { kind: 'stage', facts: StageFact
|
||||
export interface HealthBlock extends BlockShape { kind: 'health', facts: HealthFacts }
|
||||
export interface StartBlock extends BlockShape { kind: 'start', facts: StartFacts }
|
||||
export type FactBlock
|
||||
= | FunctionBlock | ClassBlock | TraitBlock | ImplBlock | EnumBlock | ExceptionBlock | ImportBlock | VariableBlock | InterpreterBlock | OptionsBlock
|
||||
= | FunctionBlock | ClassBlock | TraitBlock | ImplBlock | ModuleBlock | EnumBlock | ExceptionBlock | ImportBlock | VariableBlock | InterpreterBlock | OptionsBlock
|
||||
| DirectiveBlock | StageBlock | HealthBlock | StartBlock
|
||||
|
||||
/** 带说明(facts.doc)的块。 */
|
||||
@@ -826,6 +827,7 @@ export const KIND_ICONS: Record<BlockKind, KindIconName> = {
|
||||
class: 'box',
|
||||
trait: 'network',
|
||||
impl: 'square-function',
|
||||
module: 'layers',
|
||||
type: 'braces',
|
||||
enum: 'list-ordered',
|
||||
exception: 'triangle-alert',
|
||||
|
||||
@@ -109,4 +109,74 @@ describe('rust 语言卡片', () => {
|
||||
items: { changed: { 1: { added: true } }, removed: [] },
|
||||
})
|
||||
})
|
||||
|
||||
it('带身体的模块拆成子块,常量和外部函数是卡片', async () => {
|
||||
const source = [
|
||||
'/// 平台相关。',
|
||||
'pub mod platform {',
|
||||
' /// 读入。',
|
||||
' use std::io::Read;',
|
||||
' /// 上限。',
|
||||
' pub const LIMIT: u32 = 8;',
|
||||
' static NAME: &str = "a";',
|
||||
' pub fn open() -> u32 { LIMIT }',
|
||||
' extern "C" {',
|
||||
' /// 外部。',
|
||||
' pub fn bar(x: i32) -> i32;',
|
||||
' }',
|
||||
' let local = 1;',
|
||||
' println!("hi");',
|
||||
'}',
|
||||
'mod other;',
|
||||
'',
|
||||
'impl Agent {',
|
||||
' pub const N: u8 = 2;',
|
||||
'}',
|
||||
'',
|
||||
].join('\n')
|
||||
const list = await views(source)
|
||||
const mod = list.find(block => block.kind === 'module')
|
||||
expect(mod?.kind).toBe('module')
|
||||
expect(list.some(block => block.kind === 'statement' && block.code.includes('const LIMIT'))).toBe(false)
|
||||
expect(list.filter(block => block.kind === 'statement').map(block => block.code)).toEqual(['mod other;'])
|
||||
expect(mod?.children.map(block => block.kind)).toEqual(['import', 'const', 'variable', 'function', 'function', 'statement', 'statement'])
|
||||
expect(viewLines(mod ? [mod] : [])).toEqual([
|
||||
'module 1',
|
||||
' 名称: platform',
|
||||
' 说明: 平台相关。',
|
||||
' 可见性: 公开',
|
||||
' import 3',
|
||||
' 来源: std::io',
|
||||
' 导入项: 1 个',
|
||||
' Read | —',
|
||||
' const 5',
|
||||
' 名称: LIMIT',
|
||||
' 说明: 上限。',
|
||||
' 访问级别: 公共',
|
||||
' 类型: u32',
|
||||
' 值: 8',
|
||||
' variable 7',
|
||||
' 名称: NAME',
|
||||
' 类型: &str',
|
||||
' 初始值: "a"',
|
||||
' function 8',
|
||||
' 名称: open',
|
||||
' 可见性: 公开',
|
||||
' 返回: u32',
|
||||
' function 10',
|
||||
' 名称: bar',
|
||||
' 说明: 外部。',
|
||||
' 可见性: 公开',
|
||||
' 输入参数: 1 个',
|
||||
' x | i32',
|
||||
' 返回: i32',
|
||||
' statement 13: 令 local = 1;',
|
||||
' statement 14: println!("hi")',
|
||||
])
|
||||
const impl = list.find(block => block.kind === 'rust.impl')
|
||||
const inner = impl?.children.find(block => block.kind === 'const')
|
||||
expect(inner?.kind).toBe('const')
|
||||
expect(viewLines(inner ? [inner] : []).join('\n')).toContain('名称: N')
|
||||
expect(viewLines(inner ? [inner] : []).join('\n')).toMatch(/类型: u8|值: 2/)
|
||||
})
|
||||
})
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { Access, 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, ModuleBlock, Node, ParameterFacts, TokenRole, TraitBlock, VariableBlock } from '../contract'
|
||||
import * as path from 'node:path'
|
||||
import { leadingAttributes, visibilityFacts } from '../rules/rustTree'
|
||||
import { compoundShape, extendHeader, headerSpan, leafBlock, leafShape, named } from './shared'
|
||||
@@ -15,26 +15,35 @@ export function createRustAdapter(wasmDir: string): LanguageAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
/** extern 块本身不成一块源码,里面的签名跟所在这一层的别的项走同一条路。 */
|
||||
function unwrapExtern(item: Node): Node[] {
|
||||
if (item.type !== 'foreign_mod_item')
|
||||
return [item]
|
||||
const body = item.childForFieldName('body')
|
||||
return body ? named(body).flatMap(unwrapExtern) : []
|
||||
}
|
||||
|
||||
function topBlocks(items: Node[]): CodeBlock[] {
|
||||
const list = items.flatMap(unwrapExtern)
|
||||
const blocks: CodeBlock[] = []
|
||||
let index = 0
|
||||
while (index < items.length) {
|
||||
const item = items[index]
|
||||
while (index < list.length) {
|
||||
const item = list[index]
|
||||
if (isDoc(item)) {
|
||||
const docs = [item]
|
||||
let next = index + 1
|
||||
while (next < items.length && isDoc(items[next]) && items[next].startPosition.row <= docs[docs.length - 1].endPosition.row + 1)
|
||||
docs.push(items[next++])
|
||||
while (next < items.length && items[next].type === 'attribute_item')
|
||||
while (next < list.length && isDoc(list[next]) && list[next].startPosition.row <= docs[docs.length - 1].endPosition.row + 1)
|
||||
docs.push(list[next++])
|
||||
while (next < list.length && list[next].type === 'attribute_item')
|
||||
next++
|
||||
const target = items[next]
|
||||
if (target && target.type !== 'line_comment' && target.type !== 'block_comment') {
|
||||
const target = list[next]
|
||||
if (target && target.type !== 'line_comment' && target.type !== 'block_comment' && target.type !== 'empty_statement') {
|
||||
blocks.push(withPreamble(itemBlock(target), docs))
|
||||
index = next + 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (item.type === 'attribute_item') {
|
||||
if (item.type === 'attribute_item' || item.type === 'empty_statement') {
|
||||
index++
|
||||
continue
|
||||
}
|
||||
@@ -59,13 +68,50 @@ function itemBlock(item: Node): CodeBlock {
|
||||
return implBlock(item)
|
||||
case 'trait_item':
|
||||
return traitBlock(item)
|
||||
case 'mod_item':
|
||||
return moduleBlock(item)
|
||||
case 'const_item':
|
||||
return valueBlock(item, 'const')
|
||||
case 'static_item':
|
||||
return valueBlock(item, 'variable')
|
||||
case 'function_item':
|
||||
case 'function_signature_item':
|
||||
return functionBlock(item)
|
||||
default:
|
||||
return leafBlock('statement', item)
|
||||
}
|
||||
}
|
||||
|
||||
/** 没有身体的 `mod 名字;` 不拆。有身体的模块,身体和文件顶层同一套规则。 */
|
||||
function moduleBlock(node: Node): CodeBlock {
|
||||
const body = node.childForFieldName('body')
|
||||
if (!body)
|
||||
return leafBlock('statement', node)
|
||||
const { access, attributes } = visibilityFacts(node)
|
||||
return {
|
||||
kind: 'module',
|
||||
...compoundShape(node, body.startIndex, named(body), items => topBlocks(items)),
|
||||
...(attributes && { attributes }),
|
||||
facts: classFacts(node, access),
|
||||
}
|
||||
}
|
||||
|
||||
/** const 是常量,static 是变量;名称、类型、值交给现成的常量 / 变量属性表。 */
|
||||
function valueBlock(node: Node, kind: 'const' | 'variable'): CodeBlock {
|
||||
const name = node.childForFieldName('name')
|
||||
if (!name)
|
||||
return leafBlock('statement', node)
|
||||
const type = node.childForFieldName('type') ?? undefined
|
||||
const value = node.childForFieldName('value') ?? undefined
|
||||
const { access, attributes } = visibilityFacts(node)
|
||||
return {
|
||||
kind,
|
||||
...leafShape(node),
|
||||
...(attributes && { attributes }),
|
||||
facts: { access, declarators: [{ name, type, value }] },
|
||||
}
|
||||
}
|
||||
|
||||
/** 文档注释和写在前面的属性算进头部。文档注释的第一句是说明。 */
|
||||
function withPreamble(block: CodeBlock, docs: Node[]): CodeBlock {
|
||||
const [doc] = docs
|
||||
@@ -79,8 +125,8 @@ function withPreamble(block: CodeBlock, docs: Node[]): CodeBlock {
|
||||
return next
|
||||
}
|
||||
|
||||
function isDocumentedKind(block: CodeBlock): block is FunctionBlock | ClassBlock | TraitBlock | ImplBlock | EnumBlock {
|
||||
return block.kind === 'function' || block.kind === 'class' || block.kind === 'trait' || block.kind === 'impl' || block.kind === 'enum'
|
||||
function isDocumentedKind(block: CodeBlock): block is FunctionBlock | ClassBlock | TraitBlock | ImplBlock | ModuleBlock | EnumBlock | VariableBlock {
|
||||
return block.kind === 'function' || block.kind === 'class' || block.kind === 'trait' || block.kind === 'impl' || block.kind === 'module' || block.kind === 'enum' || block.kind === 'const' || block.kind === 'variable'
|
||||
}
|
||||
|
||||
function isDoc(node: Node): boolean {
|
||||
@@ -178,21 +224,7 @@ function traitBlock(node: Node): TraitBlock {
|
||||
function implBlock(node: Node): ImplBlock {
|
||||
const { access, attributes } = visibilityFacts(node)
|
||||
const body = node.childForFieldName('body')
|
||||
const children: CodeBlock[] = []
|
||||
let docs: Node[] = []
|
||||
for (const child of named(body)) {
|
||||
if (isDoc(child)) {
|
||||
docs.push(child)
|
||||
continue
|
||||
}
|
||||
if (child.type === 'attribute_item')
|
||||
continue
|
||||
if (child.type === 'function_item')
|
||||
children.push(withPreamble(functionBlock(child), docs))
|
||||
else if (child.type === 'const_item' || child.type === 'type_item')
|
||||
children.push(leafBlock('statement', child))
|
||||
docs = []
|
||||
}
|
||||
const children = body ? topBlocks(named(body)) : []
|
||||
return {
|
||||
kind: 'impl',
|
||||
...compoundShape(node, body?.startIndex ?? node.endIndex, [], () => children),
|
||||
|
||||
@@ -211,6 +211,7 @@ function ownDoc(block: CodeBlock): Node | undefined {
|
||||
case 'class':
|
||||
case 'trait':
|
||||
case 'impl':
|
||||
case 'module':
|
||||
case 'enum':
|
||||
case 'exception':
|
||||
case 'const':
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import type { ClassBlock, CodeBlock, EnumBlock, FunctionBlock, ImplBlock, ImportBlock, Inline, PropertyItem, PropertyRow, TokenRole, TraitBlock } from '../contract'
|
||||
import type { ClassBlock, CodeBlock, EnumBlock, FunctionBlock, ImplBlock, ImportBlock, Inline, ModuleBlock, PropertyItem, PropertyRow, TokenRole, TraitBlock } from '../contract'
|
||||
import type { RustVisibility } from './rustTree'
|
||||
import { bodyFunctions, docSentence, isMethod, matchArms, oneLine, returnText, signatureParams, structFields, variantPayload } from './rustTree'
|
||||
|
||||
@@ -64,6 +64,14 @@ export function structRows(block: ClassBlock, say: RustSay): PropertyRow[] {
|
||||
]
|
||||
}
|
||||
|
||||
export function moduleRows(block: ModuleBlock, say: RustSay): PropertyRow[] {
|
||||
return [
|
||||
nameRow(block.facts.name, say, 'variable'),
|
||||
...docRow(block.facts.doc),
|
||||
visibilityRow(block),
|
||||
]
|
||||
}
|
||||
|
||||
export function enumRows(block: EnumBlock, say: RustSay): PropertyRow[] {
|
||||
return [
|
||||
nameRow(block.facts.name, say, 'type'),
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
import type { FactBlock, Node, PropertyRow, SourceDocument, Translator } from '../contract'
|
||||
import { enumRows, functionRows, implRows, importRows, plainSay, structRows, traitRows } from '../rules/rustRows'
|
||||
import { enumRows, functionRows, implRows, importRows, moduleRows, plainSay, structRows, traitRows } from '../rules/rustRows'
|
||||
import { createZhTemplateTranslator, KIND_ZH, ZH_ATTRIBUTE_NAMES } from './zhTemplate'
|
||||
|
||||
const say = plainSay()
|
||||
|
||||
/**
|
||||
* Rust 的中文直译。属性表的用词按代码阅读的 Rust 原型:结构体、可见性、变体、分情况。
|
||||
* 关键字和注释仍走中文直译那一套。
|
||||
*/
|
||||
export const rustZhTranslator: Translator = {
|
||||
...createZhTemplateTranslator({
|
||||
const template = createZhTemplateTranslator({
|
||||
id: 'rust.zh-template',
|
||||
label: '中文直译',
|
||||
languageIds: ['rust'],
|
||||
@@ -60,7 +55,14 @@ export const rustZhTranslator: Translator = {
|
||||
stringNodes: ['string_literal'],
|
||||
commentText,
|
||||
nodeTemplates: {},
|
||||
}),
|
||||
})
|
||||
|
||||
/**
|
||||
* Rust 的中文直译。属性表的用词按代码阅读的 Rust 原型:结构体、可见性、变体、分情况。
|
||||
* 关键字和注释仍走中文直译那一套。常量和变量的行不另写一套,走模板里现成的那套。
|
||||
*/
|
||||
export const rustZhTranslator: Translator = {
|
||||
...template,
|
||||
attributeNames: {
|
||||
attributes: { ...ZH_ATTRIBUTE_NAMES.attributes, access: '可见性' },
|
||||
values: {
|
||||
@@ -78,7 +80,7 @@ export const rustZhTranslator: Translator = {
|
||||
describe,
|
||||
}
|
||||
|
||||
function describe(block: FactBlock, _document: SourceDocument): PropertyRow[] {
|
||||
function describe(block: FactBlock, document: SourceDocument): PropertyRow[] {
|
||||
switch (block.kind) {
|
||||
case 'import':
|
||||
return importRows(block, say)
|
||||
@@ -92,6 +94,11 @@ function describe(block: FactBlock, _document: SourceDocument): PropertyRow[] {
|
||||
return traitRows(block, say)
|
||||
case 'impl':
|
||||
return implRows(block, say)
|
||||
case 'module':
|
||||
return moduleRows(block, say)
|
||||
case 'const':
|
||||
case 'variable':
|
||||
return template.describe(block, document)
|
||||
default:
|
||||
return []
|
||||
}
|
||||
|
||||
@@ -214,6 +214,7 @@ export const KIND_ZH: Record<BlockKind, string> = {
|
||||
class: '类',
|
||||
trait: '特质',
|
||||
impl: '实现',
|
||||
module: '模块',
|
||||
enum: '枚举',
|
||||
exception: '异常',
|
||||
type: '类型',
|
||||
@@ -708,6 +709,7 @@ export function createZhTemplateTranslator(table: ZhTable): Translator {
|
||||
case 'class':
|
||||
case 'trait':
|
||||
case 'impl':
|
||||
case 'module':
|
||||
return classRows(block.facts, phrases)
|
||||
case 'enum':
|
||||
return enumRows(block.facts, phrases)
|
||||
|
||||
@@ -74,7 +74,7 @@ body.vscode-high-contrast-light {
|
||||
[data-kind="exception"] { --kind: var(--cr-kind-exception); }
|
||||
:is([data-kind="field"], [data-kind="const"], [data-kind="variable"], [data-kind="label"]) { --kind: var(--cr-kind-data); }
|
||||
:is([data-kind="if"], [data-kind="else"], [data-kind="case"]) { --kind: var(--cr-kind-branch); }
|
||||
[data-kind="stage"] { --kind: var(--cr-kind-stage); }
|
||||
:is([data-kind="stage"], [data-kind="module"]) { --kind: var(--cr-kind-stage); }
|
||||
[data-kind="loop"] { --kind: var(--cr-kind-loop); }
|
||||
:is([data-kind="try"], [data-kind="catch"], [data-kind="finally"], [data-kind="health"]) { --kind: var(--cr-kind-error); }
|
||||
:is([data-kind="return"], [data-kind="start"]) { --kind: var(--cr-kind-return); }
|
||||
|
||||
@@ -23,6 +23,7 @@ describe('块的种类图标', () => {
|
||||
class: 'box',
|
||||
trait: 'network',
|
||||
impl: 'square-function',
|
||||
module: 'layers',
|
||||
type: 'braces',
|
||||
enum: 'list-ordered',
|
||||
exception: 'triangle-alert',
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
export type BlockKind
|
||||
= | 'import' | 'function' | 'class' | 'enum' | 'exception' | 'type' | 'field' | 'const' | 'variable'
|
||||
| 'trait' | 'impl'
|
||||
| 'trait' | 'impl' | 'module'
|
||||
| 'if' | 'else' | 'loop' | 'try' | 'catch' | 'finally' | 'return' | 'statement' | 'comment'
|
||||
| 'interpreter' | 'options' | 'case' | 'command' | 'pipeline'
|
||||
| 'directive' | 'stage' | 'run' | 'copy' | 'setting' | 'label' | 'health' | 'start'
|
||||
|
||||
Reference in new issue
Block a user