✨ feat(vscode): 代码阅读认出代码里起的中文名(Annotated[…, Comment("…")]、@Comment 装饰器、行尾 # @Comment、docstring / JSDoc 的参数说明),预览里定义和用到它的各处都写中文名,悬停看原名,定义处后面淡淡写原名
This commit is contained in:
1 parent
1b1299dc1f
commit
44c221ea2b
45 files changed
+1685
-128
No files matched your search
@@ -2,6 +2,7 @@ import type { CustomTextEditorProvider, Disposable, TextDocument, TextDocumentSh
|
||||
import type { ClaudeImage } from '../../cc/spawnClaude'
|
||||
import type { BlockView } from '../blockView'
|
||||
import type { RuleLocation, RuleReference } from '../contract'
|
||||
import type { IndexedName, NameSources } from '../nameResolution'
|
||||
import type { CodeQa } from '../qa/codeQa'
|
||||
import type { CodeReaderRegistry } from '../registry'
|
||||
import type { TreeSitterRuntime } from '../runtime'
|
||||
@@ -13,6 +14,7 @@ import { logger } from '../../logging/logger'
|
||||
import { webviewHtml, webviewUiRoot } from '../../webview/html'
|
||||
import { blockReplacement } from '../editText'
|
||||
import { locate } from '../folderStore'
|
||||
import { DocumentNames, resolveNames } from '../nameResolution'
|
||||
import { askPrompt, followUpPrompt } from '../qa/prompt'
|
||||
import { definitionAction } from './definitionAction'
|
||||
import { findDefinitions, languageDefinitions, pickDefinition, ruleDefinitions } from './definitions'
|
||||
@@ -46,6 +48,8 @@ export class PreviewEditorProvider implements CustomTextEditorProvider {
|
||||
readonly resolveReference: (reference: RuleReference) => Promise<RuleLocation[]>,
|
||||
/** 问 AI:各预览共用,同一份文件开在几处时问答、正在答的问题都一样 */
|
||||
readonly qa: CodeQa,
|
||||
/** 工作区里别的文件定义的、原名叫 name 的中文名(languageId 是查的这份文档的语言) */
|
||||
readonly indexedNames: (languageId: string, name: string) => Promise<IndexedName[]>,
|
||||
) {}
|
||||
|
||||
resolveCustomTextEditor(document: TextDocument, panel: WebviewPanel): void {
|
||||
@@ -118,6 +122,8 @@ class Preview {
|
||||
visibleLine: number | undefined
|
||||
/** 最近一次发出去的块树和它的源码:问 AI 时按块的记号在里面找那块代码 */
|
||||
private sent: { blocks: BlockView[], source: string } | undefined
|
||||
/** 这份文档各版本显示成中文名的名字 */
|
||||
private readonly names: DocumentNames
|
||||
|
||||
constructor(
|
||||
private readonly document: TextDocument,
|
||||
@@ -136,6 +142,10 @@ class Preview {
|
||||
rule: async reference => ruleDefinitions(await owner.resolveReference(reference)),
|
||||
language: offset => languageDefinitions(document.uri, document.positionAt(offset)),
|
||||
})
|
||||
this.names = new DocumentNames((version, names) => {
|
||||
if (this.ready && version === document.version)
|
||||
this.post({ type: 'displayNames', version, names })
|
||||
})
|
||||
this.disposables = [
|
||||
panel.webview.onDidReceiveMessage((msg: WebviewToExtension) => this.handleMessage(msg)),
|
||||
panel.onDidChangeViewState(() => {
|
||||
@@ -146,8 +156,10 @@ class Preview {
|
||||
owner.navigation.update(this, false)
|
||||
}),
|
||||
workspace.onDidChangeTextDocument((e) => {
|
||||
if (e.document === document && e.contentChanges.length > 0)
|
||||
this.schedulePush()
|
||||
if (e.document !== document || e.contentChanges.length === 0)
|
||||
return
|
||||
this.names.edited(document.version, e.contentChanges.map(change => ({ offset: change.rangeOffset, length: change.rangeLength, text: change.text })))
|
||||
this.schedulePush()
|
||||
}),
|
||||
// 页面没 ready 时收不到,等它 ready 再随第一份文档之前补发
|
||||
filter.subscribe((excluded) => {
|
||||
@@ -202,7 +214,7 @@ class Preview {
|
||||
const request = ++this.latest
|
||||
const { languageId, version } = this.document
|
||||
const source = this.document.getText()
|
||||
const message = await documentMessage({ languageId, version, getText: () => source }, this.registry, this.runtime, (text) => {
|
||||
const { message, displayNames } = await documentMessage({ languageId, version, getText: () => source }, this.registry, this.runtime, (text) => {
|
||||
logger.add({ level: 'warn', source: 'codeReader', message: `${this.document.uri.fsPath}:${text}` })
|
||||
})
|
||||
if (request !== this.latest || !this.ready)
|
||||
@@ -211,7 +223,22 @@ class Preview {
|
||||
this.sent = { blocks: message.blocks, source }
|
||||
const reveal = this.pendingReveal
|
||||
this.pendingReveal = undefined
|
||||
this.post(reveal === undefined ? message : { ...message, reveal })
|
||||
this.post({ ...message, names: this.names.known(version), ...(reveal && { reveal }) })
|
||||
// 文档在解析期间又改了的,等下一次发文档再查
|
||||
if (version === this.document.version)
|
||||
this.names.resolve(version, report => resolveNames(displayNames, message.blocks, this.nameSources(), report))
|
||||
}
|
||||
|
||||
/** 找中文名落在哪些名字上时问的:这份文档的语言扩展、工作区里的中文名索引。 */
|
||||
private nameSources(): NameSources {
|
||||
const { document } = this
|
||||
return {
|
||||
uri: document.uri.toString(),
|
||||
occurrences: async offset => (await occurrencesOf(document, offset)).map(({ start, end }) => ({ start, end })),
|
||||
definitions: async offset => (await languageDefinitions(document.uri, document.positionAt(offset)))
|
||||
.map(({ uri, range }) => ({ uri: uri.toString(), line: range.start.line, character: range.start.character })),
|
||||
indexed: name => this.owner.indexedNames(document.languageId, name),
|
||||
}
|
||||
}
|
||||
|
||||
/** 跳到高亮着的名字的下一处 / 上一处出现;页面不在就算了(页面重新加载时高亮已经没了)。 */
|
||||
@@ -230,6 +257,7 @@ class Preview {
|
||||
|
||||
dispose(): void {
|
||||
clearTimeout(this.timer)
|
||||
this.names.dispose()
|
||||
for (const disposable of this.disposables)
|
||||
disposable.dispose()
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user