- 钩子调用讲成状态、引用、记忆值、记忆函数、上下文值、过渡、副作用、钩子返回值、钩子调用几种卡片,行照签名表 reactHooks.ts 排,去掉 react.hook - 解构接住时名称一行写出解构,展开是「第几项 | 名称 | 说明」表,每项一个调用树操作;单个名字的按钮在名称一行最右边 - 属性表的行、子行可以带操作(RowAction),表格多一列「操作」,宿主按块记号加序号起键 - 调用树服务按键数次数,新增查所有引用(references):按所在函数分组,去掉定义处和依赖数组里的 - 钩子收的函数参数都收成小框,函数体是卡片子块,直接返回的表达式由 functionBody 排成「返回 …」卡片;小框和卡片折叠箭头同一个开关 - 规则卡片可指定语言种类图标(languageKind)、种类图标悬停字和颜色(KindBadge.tooltip / iconColor)
326 lines
22 KiB
TypeScript
326 lines
22 KiB
TypeScript
/**
|
||
* 代码阅读预览与扩展之间的消息,与 webview 端 `webview-ui/src/codeReader/types.ts` 同构,两边手动保持一致。
|
||
*/
|
||
|
||
import type { ClaudeImage } from '../../cc/spawnClaude'
|
||
import type { FileAttribute } from '../attributes'
|
||
import type { BlockSlot, CallTreeTarget, ChainSlot, CommentTarget, SourceColors } from '../blockView'
|
||
import type { ContractMiss } from '../callTree/endpoint'
|
||
import type { CallTree } from '../callTree/model'
|
||
import type { BlockAttributes, BlockConcept, KindBadge, Markdown, PreviewTable, PreviewText, PropertyItem, PropertyRow, SourceRange, ThemeColor } from '../contract'
|
||
import type { OpenedFrom } from '../diff/diffBase'
|
||
import type { DocumentDiff } from '../diff/previewDiff'
|
||
import type { ShownName } from '../nameResolution'
|
||
import type { ProfileChoice } from '../qa/askProfiles'
|
||
import type { AskRound } from '../qa/asks'
|
||
import type { CodeColors } from '../theme/codeColors'
|
||
import type { Excluded, FilterState } from './blockFilter'
|
||
|
||
export type { Excluded, ShownName }
|
||
|
||
export interface TranslatorOption { id: string, label: string }
|
||
|
||
/**
|
||
* 注释里一个不带路径的引用(`[Name]`、`[Class.member]`):symbol 是写的名字;block 是这段注释属于哪一块(块的 anchor),
|
||
* 从那块代码的声明起一层层往外找(见 symbolLinks.ts)。不在哪块的注释里的没有 block,只从文件顶层找。
|
||
* file 是这段注释写在哪份文件里(uri,见 [DefinitionPeek] 的 `uri`):定义卡片里的注释带着卡片那份文件,按那份文件的块、导入找;
|
||
* 页面上这份文档自己的注释没有 file。同一个名字写在不同块、不同文件的注释里,指到的可以不一样。
|
||
*/
|
||
export interface SymbolReference {
|
||
symbol: string
|
||
block?: string
|
||
file?: string
|
||
}
|
||
|
||
/**
|
||
* 让预览滚到包含 line 的块。definition 只在跳到定义时有:定义处那个名字在源码里的下标(Segment.offset),
|
||
* 预览展开把它折叠住的块和属性行,再让就是这处定义的那一块或属性表里那一行闪几下。
|
||
* endLine 只在跳到几行(line 到 endLine)时有:预览展开、闪包住这几行的那块。都没有是从文本编辑器切过来,只滚不闪。
|
||
*/
|
||
export interface Reveal {
|
||
line: number
|
||
definition?: number
|
||
endLine?: number
|
||
}
|
||
|
||
/** 文件里的几行:从 start 行到 end 行,1 起、两头都算,同链接里的 `#L起-L止`。 */
|
||
export interface LineRange {
|
||
start: number
|
||
end: number
|
||
}
|
||
|
||
/**
|
||
* 点中的名字在这份文档里的一处出现:源码下标 [start, end)。kind 同 VS Code 的 DocumentHighlightKind:
|
||
* write 是写入(定义、赋值),read 是读取,text 是语言扩展按文字认出来的。
|
||
*/
|
||
export interface Occurrence {
|
||
start: number
|
||
end: number
|
||
kind: 'text' | 'read' | 'write'
|
||
}
|
||
|
||
/**
|
||
* 块在源码里占的地方,按相对的量记,前面的块变长变短、挪了位置它都不跟着变:
|
||
* 离前一个兄弟块的结尾(第一个子块从父块的开头算,顶层第一块从文件开头算)隔几行(lineGap)、几个字符(gap),
|
||
* 自己占几行(lines,首尾两行的行号差)、几个字符(length,第一行行首到最后一行行尾)。块的开头是它第一行的行首。
|
||
*/
|
||
export interface BlockSpan {
|
||
lineGap: number
|
||
gap: number
|
||
lines: number
|
||
length: number
|
||
}
|
||
|
||
/**
|
||
* 页面上一张卡片画的内容(发给页面的样子,见 pageCard):同 BlockView 的这几样,块里的下标(名字的 offset、refers、defines)
|
||
* 都从块的开头算;不带行号、头部的最后一行(扩展端自己用),「重写注释」只带是换掉还是新写。
|
||
*/
|
||
interface PageCardBase {
|
||
id: string
|
||
anchor: string
|
||
kind: string
|
||
defines?: SourceRange
|
||
attributes: BlockAttributes
|
||
concepts: BlockConcept[]
|
||
commentTarget?: CommentTarget['kind']
|
||
badge?: KindBadge
|
||
tint?: ThemeColor
|
||
slot?: BlockSlot
|
||
step?: ChainSlot
|
||
callTree?: CallTreeTarget
|
||
}
|
||
|
||
export type PageCard = PageCardBase & ({ translation: PreviewText, items?: PropertyItem[], table?: PreviewTable, doc?: Markdown, rows?: PropertyRow[] } | { properties: PropertyRow[] })
|
||
|
||
/**
|
||
* 发给页面的一块(见 pageBlocks):卡片的内容,在源码里占的地方(相对的,见 BlockSpan),子块。内容没变、只是挪了位置的块,发出去一模一样。
|
||
* hash 是这些(连子块)的内容指纹:页面按它认出没变的块,不用逐块比内容。
|
||
*/
|
||
export type PageBlock = PageCard & {
|
||
span: BlockSpan
|
||
hash: string
|
||
children: PageBlock[]
|
||
}
|
||
|
||
/**
|
||
* 悬停名字、注释里的链接时浮窗里的定义卡片:定义所在的文件(path 是给人看的、从工作区文件夹算起的相对路径,同挑选框;
|
||
* uri 是这份文件本身,卡片里注释中不带路径的引用带着它,按这份文件找,见 [SymbolReference])、定义处那一行(0 起),
|
||
* 盖住定义处的那块(连同子块,和那个文件的预览画的是同一张卡片;它自己当那个文件的顶层第一块,span 从文件开头算),
|
||
* 显示成中文名的名字(下标是那个文件里的)。
|
||
*/
|
||
export interface DefinitionPeek {
|
||
path: string
|
||
uri: string
|
||
line: number
|
||
block: PageBlock
|
||
names: ShownName[]
|
||
/** 那块自己下面问过 AI 的各次,同那块下面的对话、按时间先后(子块上问的不算);没问过时没有 */
|
||
qa?: QaEntryView[]
|
||
}
|
||
|
||
export interface DocumentMessage {
|
||
type: 'document'
|
||
/** TextDocument.version:webview 靠它判断是不是新一份文档 */
|
||
version: number
|
||
languageId: string
|
||
blocks: PageBlock[]
|
||
/** 整份源码和它的着色,只这一份:编辑框里一块的源码、着色按它的编辑范围取;解析失败、语言不支持时是空的(没有块) */
|
||
source: string
|
||
colors: SourceColors
|
||
/** 这份文件里出现过的筛选属性和值(带显示名、块数),按筛选栏的先后排,见 fileAttributes */
|
||
attributes: FileAttribute[]
|
||
translators: TranslatorOption[]
|
||
translatorId: string
|
||
error?: string
|
||
/** 新预览只在第一份 document 里带:从文本编辑器切过来时是它顶部那一行,跳到定义时是定义处 */
|
||
reveal?: Reveal
|
||
/** 这个版本眼下已知的中文名:查过的,或上一版查到的跟着改动挪了位置的;查完再发 displayNames 换掉 */
|
||
names: ShownName[]
|
||
}
|
||
|
||
/**
|
||
* 问过、重写过的一次(给预览看的):说的话、回答(Markdown;重写记录是交回的注释正文,没交回时是空的)、什么时候(ISO 时间)、用哪个 profile 答的。
|
||
*/
|
||
export interface QaEntryView {
|
||
id: string
|
||
question: string
|
||
answer: string
|
||
createdAt: string
|
||
/** 用哪个 profile 答的(profile 名);选「默认」时、以前存的没有 */
|
||
profile?: string
|
||
/** 带的图片,预览里能直接用的地址(webview.asWebviewUri);没带图片时没有 */
|
||
images?: string[]
|
||
/** 重写记录才有:没写进文件的原因 */
|
||
error?: string
|
||
}
|
||
|
||
/** 挂在一块上的问答或重写记录;记号对不上这份文件里任何一块的不显示。 */
|
||
export interface QaThreadView {
|
||
anchor: string
|
||
entries: QaEntryView[]
|
||
}
|
||
|
||
/**
|
||
* 这份文件的问答和重写记录:available 为假时文件不在工作区文件夹里、没地方存,不给「问 AI」和「重写注释」;
|
||
* current、rewriteCurrent 是当前这一轮:正在答的问题、排着队和正在重写的注释,和出错、被叫停没记下留着的(页面重新加载后靠它们接上)。
|
||
*/
|
||
export interface QaMessage {
|
||
type: 'qa'
|
||
/** 能问 AI:问答有地方存(工作区外的库文件记在第一个工作区文件夹);没打开工作区文件夹时不能 */
|
||
available: boolean
|
||
/** 能重写注释:只有工作区里的文件,工作区外的库文件不改 */
|
||
rewritable: boolean
|
||
/** 块下面的问答,按块的记号 */
|
||
threads: QaThreadView[]
|
||
/** 这一页顶部、按路径记的问答;不挂在块上 */
|
||
path: QaEntryView[]
|
||
/** 顶部问的是这个文件、这个文件夹,还是「了解一块代码」找的一个功能 */
|
||
subject: 'file' | 'folder' | 'feature'
|
||
current: AskRound[]
|
||
/** 块下面的重写记录,按块的记号 */
|
||
rewrites: QaThreadView[]
|
||
rewriteCurrent: AskRound[]
|
||
}
|
||
|
||
/** 预览里的两种对话:问 AI(ask,块下面和页面顶部)、重写注释(rewrite),各有各的记录和 profile 下拉 */
|
||
export type ChatKind = 'ask' | 'rewrite'
|
||
|
||
/**
|
||
* VS Code 的 Sticky Scroll 设置(editor.stickyScroll.enabled / editor.stickyScroll.maxLineCount):卡片的开头滚到预览顶上后面、卡片还有一部分看得见时把它钉在顶上,
|
||
* 外层的在上、里层的在下,最多钉 maxLineCount 行。
|
||
*/
|
||
export interface StickyScrollSettings {
|
||
enabled: boolean
|
||
maxLineCount: number
|
||
}
|
||
|
||
/**
|
||
* reveal:已经开着的预览滚到某处(同 DocumentMessage.reveal)
|
||
* definitionProbed:id 那次 probeDefinition 的回答,found 表示 VS Code 查得到定义
|
||
* definitionPeeked:id 那次 peekDefinition / peekLink 的回答。查不到定义、定义所在的语言没有代码阅读、没有块盖住定义处、
|
||
* 指着的名字就是定义本身时没有 peek,页面不弹浮窗
|
||
* hoverDelay:VS Code 的 editor.hover.delay / editor.hover.hidingDelay(毫秒),鼠标停多久弹定义卡片、移开后多久收;ready 后发一次,设置改了再发
|
||
* stickyScroll:VS Code 的 Sticky Scroll 设置(按这份文件取,语言自己的设置优先),见 StickyScrollSettings;ready 后发一次,设置改了再发
|
||
* occurrencesFound:id 那次 findOccurrences 的回答,语言扩展没答(或没装)就是空的
|
||
* filter:整个工作区共用的块筛选和「只看改动」开关;ready 后先于第一份文档发一次,之后任何一个预览改了都发给所有预览
|
||
* codeColors:当前颜色主题(叠上用户设置里改的)给代码的配色,见 CodeColors,页面设成词性、种类的颜色变量;
|
||
* ready 后先于第一份文档发一次,换了颜色主题、改了代码配色的设置再发给所有预览
|
||
* qa:这份文件的问答;ready 后发一次,问答、正在答的问题变了再发
|
||
* profiles:kind 那种对话输入框旁边的 profile 下拉:选项和选中的那项;ready 后两种各发一次,任何一个预览改了哪种就把哪种发给所有预览
|
||
* answer:askId 那个问题的回答长了(text 是到现在为止的全文)、或换了在做的事
|
||
* answerEnd:askId 那个问题答完了:done 带最终的回答和存下的那条的 id,failed 带给人看的原因,stopped 是被叫停
|
||
* rewriteProgress:askId 那一轮重写排上队了(queued)、开始了、正文长了(text 是到现在为止写出来的)、或换了在做的事;question 是记在这一轮上的话(点按钮时是那句技能命令)
|
||
* rewriteEnd:askId 那一轮重写结束了:done 是模型答完、这一轮记下了,带交回的正文(text)、存下的那条的 id,没写进文件时带原因(error);
|
||
* failed 带给人看的原因,stopped 是被叫停,这两种都没记、文件没改
|
||
* moveOccurrence:跳到高亮着的名字的下一处(step 1)/ 上一处(step -1)出现,由这两条命令发给活动的预览
|
||
* openFind:打开查找栏,由「查找」命令发给活动的预览
|
||
* moveFind:查找栏里跳到下一处(step 1)/ 上一处(step -1)命中,由「查找下一处 / 上一处」命令发给查找栏开着的预览
|
||
* displayNames:version 这份文档里显示成中文名的名字,查到一步发一步(先本文件定义的,再别的文件定义的);不是页面上这个版本的不理
|
||
* diff:这份文件相比对比基准改了什么(审查工作副本里的、用「未提交的更改」文件行上的「打开更改」打开的有改动的才有,见 [对比基准](vscode/src/codeReader/diff/diffBase.ts#DiffBase)):每发一份文档之后算好了补发,
|
||
* 基准变了(提交后 HEAD 动了、换了审查的工单、文件有了改动、这个标签页换了从哪儿打开)再发;null 是不比了(退出了审查、改动提交了、从别处点开了)
|
||
* openedFrom:这个标签页是从哪儿打开的,页面记进自己的状态,VS Code 重启后恢复这个标签页时随 ready 报回来;ready 后发一次,开着时又从侧栏点开、换了从哪儿打开的再发
|
||
* repoLinksChecked:id 那次 checkRepoLinks 的回答,missing 是仓库里没有的路径,unresolved 是找不到的不带路径的引用,
|
||
* builtin 是语言自带、又问不到定义的不带路径的引用(Python 的 `ValueError`、`str`,页面当普通文字);两样都原样带回问的那几条
|
||
* repoLinkBroken:这个仓库链接打不开。没有 symbol 是文件或目录没有;有 symbol 是文件在、这个符号没有;没有 path 是不带路径的引用找不到,
|
||
* block、file 同 openRepoLink
|
||
* repoLinkBuiltin:点的不带路径的引用是语言自带、又问不到定义的名字,没打开,页面当普通文字;symbol、block、file 同 openRepoLink
|
||
* repoLinkOpened:这个仓库链接打开了。路径在;带了 symbol 时这个符号也在;没有 path 是不带路径的引用找到了,block、file 同 openRepoLink
|
||
* repoImagesChecked:id 那次 checkRepoImages 的回答。src 是预览里能直接用的图片地址;没有 src 是文件不在
|
||
* callTreeCounts:version 这份文档里各个调用树的次数(只包括大于 0 的),按调用树的键:能看调用树的块(BlockView.callTree)是块的记号,
|
||
* 落在几棵调用树里;卡片属性表里的操作([看调用树的操作](vscode/src/codeReader/contract.ts#CallTreeAction))是它的键,按它的查法算次数。不是页面上这个版本的不理
|
||
* callTree:键是 key 的那个调用树(同 callTreeCounts)。trees 空着、又没有 contractMiss 是没有调用它的地方;接口卡片在契约文件里没对上时带 contractMiss。
|
||
* 不是页面上这个版本的不理
|
||
*/
|
||
export type ExtensionToWebview
|
||
= | DocumentMessage
|
||
| ({ type: 'reveal' } & Reveal)
|
||
| { type: 'definitionProbed', id: number, found: boolean }
|
||
| { type: 'definitionPeeked', id: number, peek?: DefinitionPeek }
|
||
| { type: 'hoverDelay', delay: number, hidingDelay: number }
|
||
| ({ type: 'stickyScroll' } & StickyScrollSettings)
|
||
| { type: 'occurrencesFound', id: number, occurrences: Occurrence[] }
|
||
| { type: 'moveOccurrence', step: 1 | -1 }
|
||
| { type: 'openFind' }
|
||
| { type: 'moveFind', step: 1 | -1 }
|
||
| { type: 'displayNames', version: number, names: ShownName[] }
|
||
| ({ type: 'filter' } & FilterState)
|
||
| ({ type: 'codeColors' } & CodeColors)
|
||
| QaMessage
|
||
| ({ type: 'profiles', kind: ChatKind } & ProfileChoice)
|
||
| { type: 'answer', askId: string, text: string, activity?: string }
|
||
| { type: 'answerEnd', askId: string, status: 'done' | 'failed' | 'stopped', text?: string, error?: string, entryId?: string }
|
||
| { type: 'rewriteProgress', askId: string, question: string, text: string, activity?: string, queued?: true }
|
||
| { type: 'rewriteEnd', askId: string, status: 'done' | 'failed' | 'stopped', text?: string, error?: string, entryId?: string }
|
||
| { type: 'diff', diff: DocumentDiff | null }
|
||
| { type: 'openedFrom', from: OpenedFrom }
|
||
| { type: 'repoLinksChecked', id: number, missing: string[], unresolved: SymbolReference[], builtin: SymbolReference[] }
|
||
| { type: 'repoLinkBroken', path?: string, symbol?: string, block?: string, file?: string }
|
||
| ({ type: 'repoLinkBuiltin' } & SymbolReference)
|
||
| { type: 'repoLinkOpened', path?: string, symbol?: string, block?: string, file?: string }
|
||
| { type: 'repoImagesChecked', id: number, images: { path: string, src?: string }[] }
|
||
| { type: 'focusPathAsk' }
|
||
| { type: 'callTreeCounts', version: number, counts: Record<string, number> }
|
||
| { type: 'callTree', version: number, key: string, name: string, where: string, trees: CallTree[], contractMiss?: ContractMiss }
|
||
|
||
/**
|
||
* ready:页面准备好了,可以收消息;openedFrom 是页面记着的这个标签页是从哪儿打开的,新开的页面没记过就没有
|
||
* edit:把 startLine..endLine 这几行整行替换成 text(扩展端给每行补回原来的缩进)
|
||
* visibleLine:预览视口顶部那块的起始行,切回文本编辑器时把这行放到顶部
|
||
* probeDefinition:按住 ⌘ / Ctrl 指到带下标的名字上,问源码 offset 处有没有定义;id 标出是哪一次问,回答带回去;
|
||
* version 是这份下标所属的文档版本
|
||
* goToDefinition:⌘ / Ctrl + 点击,跳到 offset 处名字的定义
|
||
* peekDefinition:鼠标停在带下标的名字上,要 offset 处名字的定义卡片(几处定义取第一处);id、version 同 probeDefinition
|
||
* peekLink:鼠标停在注释里指到符号的链接上(带 #符号 的仓库链接、不带路径的引用),要那个符号的定义卡片;path、symbol、block、file 同 openRepoLink
|
||
* findOccurrences:单击带下标的名字,问它在这份文档里出现在哪几处;id、version 同 probeDefinition
|
||
* setFilter:改块筛选(整份替换),扩展端记下后发 filter 给所有预览
|
||
* setOnlyChanges:打开 / 关掉「只看改动」,扩展端记下后发 filter 给所有预览
|
||
* ask:问 anchor 那块代码;askId 由 webview 起,回答的消息带回去;扩展端接着这块最近一次问答的会话问,用问 AI 眼下选的 profile;
|
||
* images 是贴进输入框的图片(没贴是空的),随问题发给 Claude Code,答成了跟这条一起存
|
||
* rewriteComment:按注释规范重写 anchor 那块的注释(还没有就新写一段);askId 由 webview 起,过程用 rewriteProgress / rewriteEnd 带回去。
|
||
* 没有 request 是点了按钮:发技能命令,开新会话;有 request 是在输入框里说的修改意见,接着这块最近一次重写的会话说,images 是贴的图片
|
||
* stopRewrite:叫停 askId 那一轮重写,不写文件、不记
|
||
* forgetRound:页面上收起了 anchor 那块的问答(ask)或重写(rewrite),扩展端去掉这块留着的那一轮(出错、被叫停的)
|
||
* deleteRewrite:删掉 anchor 那块下面的一条重写记录
|
||
* stopAsk:叫停 askId 那个问题,这次不存
|
||
* deleteQa:删掉 anchor 那块下面的一次问答(已经理解了)
|
||
* selectProfile:kind 那种对话换 profile(id 是 profile 名,「默认」是 ''),扩展端记下后把这种的 profiles 发给所有预览
|
||
* occurrenceNavigation:眼下能不能用键盘在高亮着的名字的各处出现之间跳(有高亮、页面有焦点、焦点不在输入框里),变了才发;
|
||
* 扩展端按它设 when 子句用的上下文键
|
||
* findNavigation:眼下查找栏的快捷键归不归这个页面(查找栏开着、页面有焦点),变了才发;扩展端按它设 when 子句用的上下文键
|
||
* openRepoLink:点了注释里的仓库路径链接,打开 path(从仓库根算起)。symbol 是类名、函数名或「类名.成员名」,lines 是文件里的几行(和 symbol 二选一),
|
||
* 都没有就只打开文件或在代码阅读侧栏的树上定位目录;
|
||
* 没有 path 是不带路径的引用(`[Name]`、`[Class.member]`),按它写在的那份文件找 symbol:file 是那份文件(定义卡片里的注释才有,没有是这份文件),
|
||
* block 是它写在哪块的注释里(见 SymbolReference),从那块的声明起一层层往外找那份文件定义的,再是导入的(见 symbolLinks.ts)
|
||
* checkRepoLinks:预览里这批仓库路径问哪些文件或目录没有,这批不带路径的引用(references)问哪些找不到。id 标出是哪一次问
|
||
* checkRepoImages:预览里这批仓库图片,问哪些文件在,在的要预览里能直接用的地址。id 标出是哪一次问
|
||
* openCallTree:打开键是 key 的调用树(块的记号,或卡片上一个操作的键,同 callTreeCounts)。version 是它所在的文档版本,对不上就不查
|
||
* goToCallNode:点了调用树上的一个节点,打开 uri 那个文件,跳到 line 行 character 列(都从 0 起,见 CallTreeNode.jump)
|
||
*/
|
||
export type WebviewToExtension
|
||
= | { type: 'ready', openedFrom?: OpenedFrom }
|
||
| { type: 'setFilter', excluded: Excluded }
|
||
| { type: 'setOnlyChanges', on: boolean }
|
||
| { type: 'edit', startLine: number, endLine: number, text: string }
|
||
| { type: 'rewriteComment', askId: string, anchor: string, request?: string, images: ClaudeImage[] }
|
||
| { type: 'stopRewrite', askId: string }
|
||
| { type: 'deleteRewrite', anchor: string, entryId: string }
|
||
| { type: 'forgetRound', kind: ChatKind, anchor: string }
|
||
| { type: 'selectTranslator', id: string }
|
||
| { type: 'visibleLine', line: number }
|
||
| { type: 'probeDefinition', id: number, version: number, offset: number }
|
||
| { type: 'goToDefinition', version: number, offset: number }
|
||
| { type: 'peekDefinition', id: number, version: number, offset: number }
|
||
| { type: 'peekLink', id: number, path?: string, symbol: string, block?: string, file?: string }
|
||
| { type: 'findOccurrences', id: number, version: number, offset: number }
|
||
| { type: 'ask', askId: string, anchor: string, question: string, images: ClaudeImage[] }
|
||
| { type: 'stopAsk', askId: string }
|
||
| { type: 'deleteQa', anchor: string, entryId: string }
|
||
| { type: 'selectProfile', kind: ChatKind, id: string }
|
||
| { type: 'occurrenceNavigation', available: boolean }
|
||
| { type: 'findNavigation', available: boolean }
|
||
| { type: 'openRepoLink', path?: string, symbol?: string, block?: string, file?: string, lines?: LineRange }
|
||
| { type: 'checkRepoLinks', id: number, paths: string[], references: SymbolReference[] }
|
||
| { type: 'checkRepoImages', id: number, paths: string[] }
|
||
| { type: 'openCallTree', version: number, key: string }
|
||
| { type: 'goToCallNode', uri: string, line: number, character: number }
|