✨ feat(vscode): 代码阅读支持 Shell 脚本(bash / sh / zsh):解释器、选项每个开关一行、变量展开读成中文、分情况表、函数按位置的参数 / 输出 / 返回、常用命令按命令规则读成一句、重定向、条件、遍历、管道;同一文件里的函数和变量能跳转、高亮

This commit is contained in:
cruldra committed 2026-09-28 00:44:53 +08:00
1 parent c577f38bee
commit e96694317d
12 files changed
+2559 -3

No files matched your search

@@ -1,12 +1,15 @@
import type { Memento } from 'vscode'
import type { LibraryRule } from '../contract'
import { describe, expect, it } from 'vitest'
import { shellCommandRules } from '../commands/shellCommands'
import { createBashAdapter } from '../languages/bash'
import { createPythonAdapter } from '../languages/python'
import { createTypeScriptAdapter } from '../languages/typescript'
import { CodeReaderRegistry } from '../registry'
import { fastapiRule } from '../rules/fastapi'
import { sqlalchemyRule } from '../rules/sqlalchemy'
import { runtime, WASM_DIR } from '../testSupport'
import { bashZhTranslator } from '../translators/bashZh'
import { pythonZhTranslator } from '../translators/pythonZh'
import { typescriptZhTranslator } from '../translators/typescriptZh'
import { documentMessage } from './documentMessage'
@@ -151,6 +154,20 @@ describe('预览的 document 消息', () => {
`库规则 broken 看第 ${line} 行的 ${['import', 'class', 'variable', 'field'][i]} 块时出错,这块照常显示:读不懂`))
})
it('shell:注册的命令规则读命令,筛选栏有 shell 的种类,同一文件里的名字交给宿主跳转', async () => {
const registry = new CodeReaderRegistry({ get: () => undefined, update: async () => {} } as Pick<Memento, 'get' | 'update'>)
registry.registerLanguage(createBashAdapter(WASM_DIR))
registry.registerTranslator(bashZhTranslator)
for (const rule of shellCommandRules)
registry.registerCommandRule(rule)
const source = '#!/usr/bin/env bash\nset -eu\ndest="$1"\nrm -rf "$dest"\n'
const { message, symbols } = await documentMessage(doc('shellscript', source), registry, runtime, ignore)
expect(message.blocks.map(b => b.kind)).toEqual(['interpreter', 'options', 'variable', 'command'])
expect(message.blocks[3]).toMatchObject({ translation: [{ text: '删除' }, { text: ' ' }, { text: 'dest' }, { text: '(' }, { text: '连同里面的东西' }, { text: '、' }, { text: '不提示' }, { text: ')' }] })
expect(message.attributes.find(attribute => attribute.id === 'kind')?.values.map(value => value.name)).toEqual(['解释器', '选项', '变量', '命令'])
expect(symbols.map(symbol => symbol.occurrences.map(range => source.slice(range.startIndex, range.endIndex)))).toEqual([['dest', 'dest']])
})
it('解析失败:把原因放进 error', async () => {
const failing = { parse: async () => Promise.reject(new Error('语法包加载失败')) }
const { message } = await documentMessage(doc('typescript', 'const a = 1'), registryWithTypeScript(), failing, ignore)