✨ feat(vscode): 代码阅读标出项目写明的入口文件和入口函数
This commit is contained in:
1 parent
78d5748b81
commit
718bbb7f6c
19 files changed
+761
-83
No files matched your search
@@ -1,4 +1,5 @@
|
||||
import type { Memento } from 'vscode'
|
||||
import type { BlockView } from '../blockView'
|
||||
import type { LibraryRule } from '../contract'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { packageCommandRules } from '../commands/packageCommands'
|
||||
@@ -6,14 +7,16 @@ import { shellCommandRules } from '../commands/shellCommands'
|
||||
import { createBashAdapter } from '../languages/bash'
|
||||
import { createDockerfileAdapter } from '../languages/dockerfile'
|
||||
import { createPythonAdapter } from '../languages/python'
|
||||
import { createRustAdapter } from '../languages/rust'
|
||||
import { createTypeScriptAdapter } from '../languages/typescript'
|
||||
import { CodeReaderRegistry } from '../registry'
|
||||
import { fastapiRule } from '../rules/fastapi'
|
||||
import { sqlalchemyRule } from '../rules/sqlalchemy'
|
||||
import { DOCKERFILE_WASM_DIR, runtime, WASM_DIR } from '../testSupport'
|
||||
import { DOCKERFILE_WASM_DIR, propertyLines, runtime, WASM_DIR } from '../testSupport'
|
||||
import { bashZhTranslator } from '../translators/bashZh'
|
||||
import { dockerfileZhTranslator } from '../translators/dockerfileZh'
|
||||
import { pythonZhTranslator } from '../translators/pythonZh'
|
||||
import { rustZhTranslator } from '../translators/rustZh'
|
||||
import { typescriptZhTranslator } from '../translators/typescriptZh'
|
||||
import { documentMessage } from './documentMessage'
|
||||
|
||||
@@ -196,3 +199,44 @@ describe('预览的 document 消息', () => {
|
||||
expect(message.error).toBe('语法包加载失败')
|
||||
})
|
||||
})
|
||||
|
||||
describe('入口文件的预览', () => {
|
||||
const CLI = [
|
||||
'import typer',
|
||||
'',
|
||||
'app = typer.Typer()',
|
||||
'',
|
||||
'',
|
||||
'def main():',
|
||||
' pass',
|
||||
'',
|
||||
'',
|
||||
'def helper():',
|
||||
' pass',
|
||||
'',
|
||||
].join('\n')
|
||||
|
||||
const nameRow = (block: BlockView): string => 'properties' in block ? propertyLines(block.properties)[0] : ''
|
||||
|
||||
it('名字对上的块(变量、函数都算),名称那一行名字后面加浅色的「入口」', async () => {
|
||||
const { message } = await documentMessage({ ...doc('python', CLI), entryNames: ['app', 'main'] }, registryWithPython(), runtime, ignore)
|
||||
expect(message.blocks.slice(1).map(nameRow)).toEqual(['名称: app 入口', '名称: main 入口', '名称: helper'])
|
||||
const [, app] = message.blocks
|
||||
expect('properties' in app && app.properties[0].value).toContainEqual({ text: ' 入口', role: 'hint' })
|
||||
})
|
||||
|
||||
it('对不上名字、不是入口:什么都不加', async () => {
|
||||
const plain = await documentMessage(doc('python', CLI), registryWithPython(), runtime, ignore)
|
||||
const unmatched = await documentMessage({ ...doc('python', CLI), entryNames: ['run'] }, registryWithPython(), runtime, ignore)
|
||||
expect(unmatched.message.blocks).toEqual(plain.message.blocks)
|
||||
expect(plain.message.blocks.map(nameRow).join('\n')).not.toContain('入口')
|
||||
})
|
||||
|
||||
it('rust:fn main 的名称后面加「入口」', async () => {
|
||||
const registry = new CodeReaderRegistry({ get: () => undefined, update: async () => {} } as Pick<Memento, 'get' | 'update'>)
|
||||
registry.registerLanguage(createRustAdapter(WASM_DIR))
|
||||
registry.registerTranslator(rustZhTranslator)
|
||||
const { message } = await documentMessage({ ...doc('rust', 'fn main() {\n run();\n}\n\nfn run() {}\n'), entryNames: ['main'] }, registry, runtime, ignore)
|
||||
expect(message.blocks.map(nameRow)).toEqual(['名称: main 入口', '名称: run'])
|
||||
})
|
||||
})
|
||||
@@ -5,6 +5,7 @@ import type { DocumentMessage } from './messages'
|
||||
import { fileAttributes, mergeAttributeNames } from '../attributes'
|
||||
import { readBlockViews } from '../blockView'
|
||||
import { commandRuleLookup } from '../commandRules'
|
||||
import { markEntryNames } from '../entries/entryMarks'
|
||||
import { ruleAttributeNames } from '../libraryRules'
|
||||
|
||||
/** 生成预览数据要读的那点文档信息(TextDocument 的子集)。 */
|
||||
@@ -12,6 +13,8 @@ export interface DocumentSnapshot {
|
||||
languageId: string
|
||||
version: number
|
||||
getText: () => string
|
||||
/** 这份文件是项目写明的入口时,预览里要标「入口」的名字(见 entries/entryPoints.ts) */
|
||||
entryNames?: readonly string[]
|
||||
}
|
||||
|
||||
/** 发给预览的文档,和这份源码里起了中文名的定义(扩展端接着找用到它们的各处)、语言插件自己认得出的名字(LocalSymbol)。 */
|
||||
@@ -25,6 +28,7 @@ export interface DocumentRead {
|
||||
* 当前文档 → 发给预览的 document 消息;语言不支持或解析失败时带 error,blocks 为空。库规则出错不算失败,交给 report 记下;
|
||||
* 规则查名字的定义时问 lookup(RuleContext.lookup),翻译插件问调用的名字定义成哪种块时问 calleeKind(SourceDocument.calleeKind)。
|
||||
* 筛选属性和值的名字先取翻译插件的,没给的再取库规则的(LibraryRule.attributeNames)。
|
||||
* 入口文件里名字对上的块,名称那一行在翻译好的结果上加「入口」(markEntryNames)。
|
||||
*/
|
||||
export async function documentMessage(
|
||||
document: DocumentSnapshot,
|
||||
@@ -66,7 +70,7 @@ export async function documentMessage(
|
||||
},
|
||||
})
|
||||
const names = mergeAttributeNames([translator?.attributeNames, ...ruleAttributeNames(rules, translator?.displayLanguage, report)])
|
||||
return { message: { ...message, blocks, attributes: fileAttributes(blocks, names) }, displayNames, symbols }
|
||||
return { message: { ...message, blocks: markEntryNames(blocks, source, document.entryNames ?? []), attributes: fileAttributes(blocks, names) }, displayNames, symbols }
|
||||
}
|
||||
catch (err) {
|
||||
return { message: { ...message, error: err instanceof Error ? err.message : String(err) }, displayNames: [], symbols: [] }
|
||||
|
||||
@@ -3,6 +3,7 @@ import type { ClaudeImage } from '../../cc/spawnClaude'
|
||||
import type { BlockKind, LocalSymbol, RuleLocation, RuleReference, WorkspaceIndex } from '../contract'
|
||||
import type { DiffBase } from '../diff/diffBase'
|
||||
import type { OldDocument, SentDocument } from '../diff/previewDiff'
|
||||
import type { WorkspaceEntries } from '../entries/workspaceEntries'
|
||||
import type { DefinitionStart, IndexedName, NameSources } from '../nameResolution'
|
||||
import type { CodeQa } from '../qa/codeQa'
|
||||
import type { CodeReaderRegistry } from '../registry'
|
||||
@@ -76,6 +77,8 @@ export class PreviewEditorProvider implements CustomTextEditorProvider {
|
||||
readonly indexed: (index: WorkspaceIndex, key: string) => Promise<IndexedEntry[]>,
|
||||
/** 预览标差异时对比什么 */
|
||||
readonly diffBases: DiffBases,
|
||||
/** 哪些文件是项目写明的入口、预览里标哪些名字 */
|
||||
readonly entries: Pick<WorkspaceEntries, 'namesOf' | 'onDidChange'>,
|
||||
) {}
|
||||
|
||||
/** 侧栏「问 AI」打开预览,并把光标放进顶部输入框。已经开着的就揭到前面再聚焦。 */
|
||||
@@ -253,6 +256,11 @@ class Preview {
|
||||
if (this.ready)
|
||||
this.post({ type: 'filter', ...state })
|
||||
}),
|
||||
// 项目的入口变了:重新发文档,名称那一行的「入口」跟着变
|
||||
owner.entries.onDidChange((uris) => {
|
||||
if (uris.some(uri => uri.toString() === document.uri.toString()))
|
||||
this.schedulePush()
|
||||
}),
|
||||
owner.qa.onDidChange((uris) => {
|
||||
if (uris.some(uri => uri.toString() === this.subject().uri.toString()))
|
||||
this.postQa()
|
||||
@@ -320,7 +328,7 @@ class Preview {
|
||||
const source = this.document.getText()
|
||||
const session = this.lookups.session()
|
||||
const callees = this.callees.session()
|
||||
const { message, displayNames, symbols } = await documentMessage({ languageId, version, getText: () => source }, this.registry, this.runtime, (text) => {
|
||||
const { message, displayNames, symbols } = await documentMessage({ languageId, version, getText: () => source, entryNames: this.owner.entries.namesOf(this.document.uri) }, this.registry, this.runtime, (text) => {
|
||||
logger.add({ level: 'warn', source: 'codeReader', message: `${this.document.uri.fsPath}:${text}` })
|
||||
}, session.lookup, callees.calleeKind)
|
||||
if (request !== this.latest || !this.ready)
|
||||
@@ -344,11 +352,11 @@ class Preview {
|
||||
|
||||
/**
|
||||
* 对比基准里的旧版本排成视图数据:和这份文档同一种语言、同一个翻译插件和库规则;规则查定义、调用的种类用这份文档眼下查到的答案,
|
||||
* 两边同样的写法翻得一样,不会因为答案晚到被当成改了。旧版本里规则出的错不记(记的是现在这份的)。
|
||||
* 两边同样的写法翻得一样,不会因为答案晚到被当成改了;项目入口也按眼下的标,「入口」两边都有。旧版本里规则出的错不记(记的是现在这份的)。
|
||||
*/
|
||||
private async readOld(source: string): Promise<OldDocument | undefined> {
|
||||
const { message } = await documentMessage(
|
||||
{ languageId: this.document.languageId, version: this.document.version, getText: () => source },
|
||||
{ languageId: this.document.languageId, version: this.document.version, getText: () => source, entryNames: this.owner.entries.namesOf(this.document.uri) },
|
||||
this.registry,
|
||||
this.runtime,
|
||||
() => {},
|
||||
|
||||
Reference in new issue
Block a user