✨ feat(vscode): Rust 的 #![…] 内部属性做成「编译属性」卡片

This commit is contained in:
cruldra committed 2026-10-08 07:17:25 +08:00
1 parent 2f610e9cb8
commit 04a11eb0b2
14 files changed
+386 -20

No files matched your search

+68 -2
View File
@@ -3,6 +3,7 @@ import { describe, expect, it } from 'vitest'
import { toBlockViews } from '../blockView'
import { blockMarks } from '../diff/viewDiff'
import { rustImplRule } from '../rules/rustImpl'
import { isCrateRoot } from '../rules/rustTree'
import { readFixture, viewLines, WASM_DIR, withBlocks } from '../testSupport'
import { rustZhTranslator } from '../translators/rustZh'
import { createRustAdapter } from './rust'
@@ -10,9 +11,9 @@ import { createRustAdapter } from './rust'
const adapter = createRustAdapter(WASM_DIR)
const sample = readFixture('rustLang.rs')
function views(source: string): Promise<BlockView[]> {
function views(source: string, fileName?: string): Promise<BlockView[]> {
return withBlocks(adapter, 'rust', source, blocks =>
toBlockViews(blocks, { source, language: adapter, markers: [] }, rustZhTranslator, {
toBlockViews(blocks, { source, language: adapter, markers: [], ...(fileName && { fileName }) }, rustZhTranslator, {
rules: [rustImplRule],
report: () => {},
}))
@@ -270,3 +271,68 @@ describe('rust 注释', () => {
expect(markdown(impl?.children.find(block => block.kind === 'comment'))).toBe('三\n\n四')
})
})
describe('rust 编译属性', () => {
it('tauri 的 main.rs 开头的 cfg_attr:属性、生效条件、作用范围、说明', async () => {
const source = [
'// Prevents additional console window on Windows in release, DO NOT REMOVE!!',
'#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]',
'',
'fn main() {}',
'',
].join('\n')
const list = await views(source, '/repo/apps/desktop/src-tauri/src/main.rs')
expect(list.map(block => block.kind)).toEqual(['comment', 'attribute', 'function'])
expect(viewLines([card(list, 'attribute')])).toEqual([
'attribute 2',
' 属性: windows_subsystem = "windows"',
' 生效条件: 非 调试构建',
' 作用范围: 整个 crate',
' 说明: 在 Windows 上编译为图形界面程序(windows 子系统),启动时不弹出控制台窗口',
])
const attribute = card(list, 'attribute')
const value = 'properties' in attribute ? attribute.properties[0]?.value : undefined
expect(Array.isArray(value) && value.map(piece => 'role' in piece && piece.role)).toEqual(['variable', 'plain', 'plain', 'plain', 'string', 'string', 'string'])
})
it('allow 列出各个 lint,别的文件顶层是本模块', async () => {
const list = await views('#![allow(dead_code, unused_imports)]\n', '/repo/src/credentials.rs')
expect(viewLines(list)).toEqual([
'attribute 1',
' 属性: allow(dead_code, unused_imports)',
' 作用范围: 本模块',
' 说明: 编译检查(lint)级别设为放行:dead_code、unused_imports',
])
})
it('认不得的属性没有说明,不知道文件名时作用范围是所在模块', async () => {
expect(viewLines(await views('#![rustfmt::skip]\n'))).toEqual([
'attribute 1',
' 属性: rustfmt::skip',
' 作用范围: 所在模块',
])
})
it('cfg_attr 写了几个属性是一张表;all、any 套着的条件加括号;mod 身体里是本模块', async () => {
const source = [
'mod platform {',
' #![cfg_attr(all(unix, not(any(test, feature = "mock"))), allow(clippy::foo), deny(warnings))]',
'}',
'',
].join('\n')
const mod = card(await views(source, '/repo/src/main.rs'), 'module')
expect(viewLines(mod.children)).toEqual([
'attribute 2',
' 属性: 2 个',
' allow(clippy::foo) | 编译检查(lint)级别设为放行:clippy::foo',
' deny(warnings) | 编译检查(lint)级别设为报错:warnings',
' 生效条件: unix 并且 非 (测试构建 或者 启用特性 mock)',
' 作用范围: 本模块',
])
})
it('crate 根文件:main.rs、lib.rs、src/bin 下的、包根 tests / examples / benches 里直接放的', () => {
expect(['/p/src/main.rs', '/p/src/lib.rs', '/p/src/bin/tool.rs', '/p/tests/api.rs', 'C:\\p\\examples\\demo.rs'].map(isCrateRoot)).toEqual([true, true, true, true, true])
expect(['/p/src/credentials.rs', '/p/src/tests/helpers.rs', '/p/src/bin/tool/args.rs'].map(isCrateRoot)).toEqual([false, false, false])
})
})