✨ feat(vscode): 代码阅读契约加命令规则(按命令名注册、读一条命令)、按位置的参数 / 输出 / 返回、解释器和选项块、分情况 / 命令 / 管道种类、常量色;模板引擎加节点读法;没有定义、高亮提供者的语言用语言插件认的同一文件里的名字跳转、高亮

This commit is contained in:
cruldra committed 2026-09-28 00:44:46 +08:00
1 parent cf09c24730
commit ff2a44f080
17 files changed
+555 -60

No files matched your search

+35 -6
View File
@@ -1,7 +1,7 @@
import type { CustomTextEditorProvider, Disposable, TextDocument, TextDocumentShowOptions, Uri, WebviewPanel } from 'vscode'
import type { ClaudeImage } from '../../cc/spawnClaude'
import type { BlockView } from '../blockView'
import type { BlockKind, RuleLocation, RuleReference, WorkspaceIndex } from '../contract'
import type { BlockKind, LocalSymbol, RuleLocation, RuleReference, WorkspaceIndex } from '../contract'
import type { DefinitionStart, IndexedName, NameSources } from '../nameResolution'
import type { CodeQa } from '../qa/codeQa'
import type { CodeReaderRegistry } from '../registry'
@@ -10,13 +10,14 @@ import type { TreeSitterRuntime } from '../runtime'
import type { IndexedEntry } from '../workspaceIndex'
import type { BlockFilter } from './blockFilter'
import type { Definition, FoundLocation } from './definitions'
import type { ExtensionToWebview, Reveal, WebviewToExtension } from './messages'
import type { ExtensionToWebview, Occurrence, Reveal, WebviewToExtension } from './messages'
import { commands, Range, window, workspace, WorkspaceEdit } from 'vscode'
import { logger } from '../../logging/logger'
import { webviewHtml, webviewUiRoot } from '../../webview/html'
import { DocumentCallees } from '../calleeKinds'
import { blockReplacement } from '../editText'
import { locate } from '../folderStore'
import { definitionFor, symbolAt, symbolOccurrences } from '../localSymbols'
import { DocumentNames, resolveNames } from '../nameResolution'
import { askPrompt, followUpPrompt } from '../qa/prompt'
import { DocumentLookups } from '../ruleLookups'
@@ -128,6 +129,8 @@ class Preview {
visibleLine: number | undefined
/** 最近一次发出去的块树和它的源码:问 AI 时按块的记号在里面找那块代码 */
private sent: { blocks: BlockView[], source: string } | undefined
/** 最近一次发出去的文档里语言插件自己认得出的名字(LanguageAdapter.symbols):语言扩展查不到定义、各处出现时用 */
private symbols: { version: number, list: LocalSymbol[] } | undefined
/** 这份文档各版本显示成中文名的名字 */
private readonly names: DocumentNames
/** 库规则问的名字的定义查到了什么:查到的变了就重发文档 */
@@ -150,7 +153,10 @@ class Preview {
) {
this.definitions = new DefinitionSources({
rule: async reference => ruleDefinitions(await owner.resolveReference(reference)),
language: offset => languageDefinitions(document.uri, document.positionAt(offset)),
language: async (offset) => {
const found = await languageDefinitions(document.uri, document.positionAt(offset))
return found.length > 0 ? found : this.localDefinitions(offset)
},
})
this.names = new DocumentNames((version, names) => {
if (this.ready && version === document.version)
@@ -228,13 +234,14 @@ class Preview {
const source = this.document.getText()
const session = this.lookups.session()
const callees = this.callees.session()
const { message, displayNames } = await documentMessage({ languageId, version, getText: () => source }, this.registry, this.runtime, (text) => {
const { message, displayNames, symbols } = await documentMessage({ languageId, version, getText: () => source }, 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)
return
this.definitions.remember(message.version, message.blocks)
this.sent = { blocks: message.blocks, source }
this.symbols = { version, list: symbols }
const reveal = this.pendingReveal
this.pendingReveal = undefined
this.post({ ...message, names: this.names.known(version), ...(reveal && { reveal }) })
@@ -260,6 +267,28 @@ class Preview {
return null
}
/** 这份文档里语言插件自己认得出、盖住 offset 的名字(只认最近一次发出去的那个版本)。 */
private localSymbol(offset: number): LocalSymbol | undefined {
return this.symbols?.version === this.document.version ? symbolAt(this.symbols.list, offset) : undefined
}
/** 语言扩展查不到定义时:语言插件自己认得出的名字的定义(见 definitionFor)。 */
private localDefinitions(offset: number): FoundLocation[] {
const symbol = this.localSymbol(offset)
const target = symbol && definitionFor(symbol, offset)
if (!target)
return []
const { document } = this
return [{ uri: document.uri, range: new Range(document.positionAt(target.startIndex), document.positionAt(target.endIndex)) }]
}
/** offset 处名字的各处出现:先问语言扩展,它答不上来时用语言插件自己认得出的名字(见 symbolOccurrences)。 */
private async occurrences(offset: number): Promise<Occurrence[]> {
const found = await occurrencesOf(this.document, offset)
const symbol = found.length > 0 ? undefined : this.localSymbol(offset)
return symbol ? symbolOccurrences(symbol) : found
}
/** 这份文档里 offset 处名字的定义(语言扩展查的)落在哪儿。 */
private async definitionStarts(offset: number): Promise<DefinitionStart[]> {
const { document } = this
@@ -272,7 +301,7 @@ class Preview {
const { document } = this
return {
uri: document.uri.toString(),
occurrences: async offset => (await occurrencesOf(document, offset)).map(({ start, end }) => ({ start, end })),
occurrences: async offset => (await this.occurrences(offset)).map(({ start, end }) => ({ start, end })),
definitions: offset => this.definitionStarts(offset),
indexed: name => this.owner.indexedNames(document.languageId, name),
}
@@ -403,7 +432,7 @@ class Preview {
const { document } = this
if (version !== document.version)
return
const occurrences = await occurrencesOf(document, offset)
const occurrences = await this.occurrences(offset)
if (version === document.version && this.ready)
this.post({ type: 'occurrencesFound', id, occurrences })
}