🐛 fix(vscode): 注释里不带路径的引用从被注释的声明起一层层往外找,同类的方法、类的成员都能链到
This commit is contained in:
1 parent
15972c0b35
commit
5120e50228
15 files changed
+450
-167
No files matched your search
@@ -14,7 +14,7 @@ import type { TreeSitterRuntime } from '../runtime'
|
||||
import type { ImportedName, LinkTarget, SymbolNode } from '../symbolLinks'
|
||||
import type { BlockFilter } from './blockFilter'
|
||||
import type { FoundLocation } from './definitions'
|
||||
import type { ChatKind, DefinitionPeek, ExtensionToWebview, Occurrence, Reveal, WebviewToExtension } from './messages'
|
||||
import type { ChatKind, DefinitionPeek, ExtensionToWebview, Occurrence, Reveal, SymbolReference, WebviewToExtension } from './messages'
|
||||
import type { TargetSpot } from './openTarget'
|
||||
import type { TopSubject } from './pathPreview'
|
||||
import { realpath } from 'node:fs/promises'
|
||||
@@ -33,7 +33,7 @@ import { DocumentNames, resolveNames } from '../nameResolution'
|
||||
import { PATH_ASK_ANCHOR } from '../qa/pathQa'
|
||||
import { askPrompt, followUpPrompt } from '../qa/prompt'
|
||||
import { DocumentLookups } from '../ruleLookups'
|
||||
import { resolveReference } from '../symbolLinks'
|
||||
import { referenceScope, resolveReference } from '../symbolLinks'
|
||||
import { definitionAction } from './definitionAction'
|
||||
import { definitionSiteNames, namesOnCard, peekBlock } from './definitionPeek'
|
||||
import { definitionKind, findDefinitions, languageDefinitions, pickDefinition, ruleDefinitions } from './definitions'
|
||||
@@ -669,16 +669,16 @@ class Preview {
|
||||
await this.peekDefinition(msg.id, msg.version, msg.offset)
|
||||
return
|
||||
case 'peekLink':
|
||||
await this.peekLink(msg.id, msg.path, msg.symbol)
|
||||
await this.peekLink(msg.id, msg.path, msg.symbol, msg.block)
|
||||
return
|
||||
case 'findOccurrences':
|
||||
await this.findOccurrences(msg.id, msg.version, msg.offset)
|
||||
return
|
||||
case 'openRepoLink':
|
||||
await this.openRepoLink(msg.path, msg.symbol)
|
||||
await this.openRepoLink(msg.path, msg.symbol, msg.block)
|
||||
return
|
||||
case 'checkRepoLinks':
|
||||
await this.checkRepoLinks(msg.id, msg.paths, msg.symbols)
|
||||
await this.checkRepoLinks(msg.id, msg.paths, msg.references)
|
||||
return
|
||||
case 'checkRepoImages':
|
||||
await this.checkRepoImages(msg.id, msg.paths)
|
||||
@@ -770,10 +770,10 @@ class Preview {
|
||||
}
|
||||
|
||||
/** 回答 webview 第 id 次要注释里的链接指的符号的卡片:符号同点这个链接时找的那个(symbolTarget),找不到没有。 */
|
||||
private async peekLink(id: number, rel: string | undefined, symbol: string): Promise<void> {
|
||||
private async peekLink(id: number, rel: string | undefined, symbol: string, block: string | undefined): Promise<void> {
|
||||
let peek: DefinitionPeek | undefined
|
||||
try {
|
||||
const target = await this.symbolTarget(rel, symbol)
|
||||
const target = await this.symbolTarget(rel, symbol, block)
|
||||
peek = target && await this.peekAt(Uri.parse(target.uri), target.selection.startIndex)
|
||||
}
|
||||
catch (err) {
|
||||
@@ -843,8 +843,8 @@ class Preview {
|
||||
}
|
||||
}
|
||||
|
||||
/** 预览里这批仓库路径,哪些文件或目录不在;这批不带路径的引用,哪些找不到。 */
|
||||
private async checkRepoLinks(id: number, paths: string[], symbols: string[]): Promise<void> {
|
||||
/** 预览里这批仓库路径,哪些文件或目录不在;这批不带路径的引用,各按写在哪块找,哪些找不到。 */
|
||||
private async checkRepoLinks(id: number, paths: string[], references: SymbolReference[]): Promise<void> {
|
||||
const root = await repoRootOf(this.document.uri.fsPath)
|
||||
const asked = new Map<string, Promise<SymbolNode[]>>()
|
||||
const symbolsOf = (uri: string): Promise<SymbolNode[]> => {
|
||||
@@ -858,10 +858,10 @@ class Preview {
|
||||
return rel
|
||||
return undefined
|
||||
})),
|
||||
Promise.all(symbols.map(async symbol => await this.resolveSymbolLink(symbol, symbolsOf) ? undefined : symbol)),
|
||||
Promise.all(references.map(async reference => await this.resolveSymbolLink(reference, symbolsOf) ? undefined : reference)),
|
||||
])
|
||||
if (this.ready)
|
||||
this.post({ type: 'repoLinksChecked', id, missing: missing.filter(rel => rel !== undefined), unresolved: unresolved.filter(symbol => symbol !== undefined) })
|
||||
this.post({ type: 'repoLinksChecked', id, missing: missing.filter(rel => rel !== undefined), unresolved: unresolved.filter(reference => reference !== undefined) })
|
||||
}
|
||||
|
||||
/** 仓库根放进这个预览能读的本地目录,图片地址才能加载。真实位置和 git 给的路径不一样时两个都放。 */
|
||||
@@ -905,19 +905,19 @@ class Preview {
|
||||
|
||||
/**
|
||||
* 打开注释里的仓库链接:目录在代码阅读侧栏的树上定位,文件用编辑器打开。
|
||||
* 带了符号就按文档符号的名字跳过去;文件或符号没有就不打开。没有路径的是不带路径的引用,按这份文件找(见 resolveSymbolLink)。
|
||||
* 带了符号就按文档符号的名字跳过去;文件或符号没有就不打开。没有路径的是不带路径的引用,按这份文件、从它写在的那块(block)找(见 resolveSymbolLink)。
|
||||
*/
|
||||
private async openRepoLink(rel: string | undefined, symbol?: string): Promise<void> {
|
||||
private async openRepoLink(rel: string | undefined, symbol?: string, block?: string): Promise<void> {
|
||||
const link = rel ?? `[${symbol}]`
|
||||
try {
|
||||
if (symbol !== undefined) {
|
||||
const target = await this.symbolTarget(rel, symbol)
|
||||
const target = await this.symbolTarget(rel, symbol, block)
|
||||
if (!target) {
|
||||
this.markRepoLinkBroken(rel, symbol)
|
||||
this.markRepoLinkBroken(rel, symbol, block)
|
||||
return
|
||||
}
|
||||
await this.showLinkTarget(target)
|
||||
this.markRepoLinkOpened(rel, symbol)
|
||||
this.markRepoLinkOpened(rel, symbol, block)
|
||||
return
|
||||
}
|
||||
if (rel === undefined)
|
||||
@@ -946,12 +946,12 @@ class Preview {
|
||||
}
|
||||
|
||||
/**
|
||||
* 链接指的符号在哪:没有 path 的是不带路径的引用,按这份文件找(resolveSymbolLink);有 path 的在那个文件的文档符号里找(locateRepoSymbol)。
|
||||
* 文件没有、是目录、符号没有时没有。点链接、悬停链接看定义卡片都按它找。
|
||||
* 链接指的符号在哪:没有 path 的是不带路径的引用,按这份文件、从它写在的那块(block)找(resolveSymbolLink);
|
||||
* 有 path 的在那个文件的文档符号里找(locateRepoSymbol)。文件没有、是目录、符号没有时没有。点链接、悬停链接看定义卡片都按它找。
|
||||
*/
|
||||
private async symbolTarget(rel: string | undefined, symbol: string): Promise<LinkTarget | undefined> {
|
||||
private async symbolTarget(rel: string | undefined, symbol: string, block: string | undefined): Promise<LinkTarget | undefined> {
|
||||
if (rel === undefined)
|
||||
return this.resolveSymbolLink(symbol)
|
||||
return this.resolveSymbolLink({ symbol, block })
|
||||
const root = await repoRootOf(this.document.uri.fsPath)
|
||||
const entry = root === undefined ? undefined : await resolveRepoEntry(root, rel)
|
||||
return entry && !entry.isDirectory ? this.locateRepoSymbol(Uri.file(entry.fsPath), symbol) : undefined
|
||||
@@ -964,13 +964,15 @@ class Preview {
|
||||
}
|
||||
|
||||
/**
|
||||
* 注释里不带路径的引用(`[Name]`、`[Class.member]`)指到哪:本文件定义的优先,再是导入进来的(见 symbolLinks.ts)。
|
||||
* 注释里不带路径的引用(`[Name]`、`[Class.member]`)指到哪:从它写在的那块(block,在眼下这份块树里找)的声明起一层层往外找本文件定义的,
|
||||
* 再是导入进来的(见 symbolLinks.ts)。检查坏链接、点击、悬停看定义卡片都走这里。
|
||||
* 文档符号同仓库链接找符号那一套(symbols,一批引用一起问时共用一份),导入的名字问语言扩展它的定义(同跳到定义),定义几处取第一处。
|
||||
*/
|
||||
private async resolveSymbolLink(symbol: string, symbols: (uri: string) => Promise<SymbolNode[]> = documentSymbolNodes): Promise<LinkTarget | undefined> {
|
||||
const { document } = this
|
||||
private async resolveSymbolLink({ symbol, block }: SymbolReference, symbols: (uri: string) => Promise<SymbolNode[]> = documentSymbolNodes): Promise<LinkTarget | undefined> {
|
||||
const { document, sent } = this
|
||||
const at = block === undefined || !sent ? undefined : referenceScope(sent.blocks, block)
|
||||
try {
|
||||
return await resolveReference(symbol, this.imports, {
|
||||
return await resolveReference(symbol, at, this.imports, {
|
||||
uri: document.uri.toString(),
|
||||
symbols,
|
||||
definition: async (offset) => {
|
||||
@@ -998,14 +1000,14 @@ class Preview {
|
||||
await this.openElsewhere(doc.uri, { range: new Range(doc.positionAt(selection.startIndex), doc.positionAt(selection.endIndex)), offset: selection.startIndex })
|
||||
}
|
||||
|
||||
private markRepoLinkBroken(path: string | undefined, symbol?: string): void {
|
||||
private markRepoLinkBroken(path: string | undefined, symbol?: string, block?: string): void {
|
||||
if (this.ready)
|
||||
this.post({ type: 'repoLinkBroken', ...(path !== undefined && { path }), ...(symbol !== undefined && { symbol }) })
|
||||
this.post({ type: 'repoLinkBroken', ...(path !== undefined && { path }), ...(symbol !== undefined && { symbol }), ...(block !== undefined && { block }) })
|
||||
}
|
||||
|
||||
private markRepoLinkOpened(path: string | undefined, symbol?: string): void {
|
||||
private markRepoLinkOpened(path: string | undefined, symbol?: string, block?: string): void {
|
||||
if (this.ready)
|
||||
this.post({ type: 'repoLinkOpened', ...(path !== undefined && { path }), ...(symbol !== undefined && { symbol }) })
|
||||
this.post({ type: 'repoLinkOpened', ...(path !== undefined && { path }), ...(symbol !== undefined && { symbol }), ...(block !== undefined && { block }) })
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in new issue
Block a user