132 lines
6.6 KiB
TypeScript
132 lines
6.6 KiB
TypeScript
/**
|
||
* 代码阅读预览与扩展之间的消息,与 webview 端 `webview-ui/src/codeReader/types.ts` 同构,两边手动保持一致。
|
||
*/
|
||
|
||
import type { ClaudeImage } from '../../cc/spawnClaude'
|
||
import type { FileAttribute } from '../attributes'
|
||
import type { BlockView } from '../blockView'
|
||
import type { ProfileChoice } from '../qa/askProfiles'
|
||
import type { RunningAsk } from '../qa/asks'
|
||
import type { Excluded } from './blockFilter'
|
||
|
||
export type { Excluded }
|
||
|
||
export interface TranslatorOption { id: string, label: string }
|
||
|
||
/**
|
||
* 让预览滚到包含 line 的块。definition 只在跳到定义时有:定义处那个名字在源码里的下标(Segment.offset),
|
||
* 预览展开把它折叠住的块和属性行,再让就是这处定义的那一块或属性表里那一行闪几下。
|
||
*/
|
||
export interface Reveal {
|
||
line: number
|
||
definition?: number
|
||
}
|
||
|
||
/**
|
||
* 点中的名字在这份文档里的一处出现:源码下标 [start, end)。kind 同 VS Code 的 DocumentHighlightKind:
|
||
* write 是写入(定义、赋值),read 是读取,text 是语言扩展按文字认出来的。
|
||
*/
|
||
export interface Occurrence {
|
||
start: number
|
||
end: number
|
||
kind: 'text' | 'read' | 'write'
|
||
}
|
||
|
||
export interface DocumentMessage {
|
||
type: 'document'
|
||
/** TextDocument.version:webview 靠它判断是不是新一份文档 */
|
||
version: number
|
||
languageId: string
|
||
blocks: BlockView[]
|
||
/** 这份文件里出现过的筛选属性和值(带显示名、块数),按筛选栏的先后排,见 fileAttributes */
|
||
attributes: FileAttribute[]
|
||
translators: TranslatorOption[]
|
||
translatorId: string
|
||
error?: string
|
||
/** 新预览只在第一份 document 里带:从文本编辑器切过来时是它顶部那一行,跳到定义时是定义处 */
|
||
reveal?: Reveal
|
||
}
|
||
|
||
/** 问过的一次(给预览看的):问题、回答(Markdown)、什么时候问的(ISO 时间)、用哪个 profile 答的。 */
|
||
export interface QaEntryView {
|
||
id: string
|
||
question: string
|
||
answer: string
|
||
createdAt: string
|
||
/** 用哪个 profile 答的(profile 名);选「默认」时、以前存的没有 */
|
||
profile?: string
|
||
/** 问题带的图片,预览里能直接用的地址(webview.asWebviewUri);没带图片时没有 */
|
||
images?: string[]
|
||
}
|
||
|
||
/** 挂在一块上的问答;记号对不上这份文件里任何一块的不显示。 */
|
||
export interface QaThreadView {
|
||
anchor: string
|
||
entries: QaEntryView[]
|
||
}
|
||
|
||
/**
|
||
* 这份文件的问答:available 为假时文件不在工作区文件夹里、问答没地方存,不给「问 AI」;
|
||
* running 是正在答的问题(页面重新加载后靠它接上)。
|
||
*/
|
||
export interface QaMessage {
|
||
type: 'qa'
|
||
available: boolean
|
||
threads: QaThreadView[]
|
||
running: RunningAsk[]
|
||
}
|
||
|
||
/**
|
||
* reveal:已经开着的预览滚到某处(同 DocumentMessage.reveal)
|
||
* definitionProbed:id 那次 probeDefinition 的回答,found 表示 VS Code 查得到定义
|
||
* occurrencesFound:id 那次 findOccurrences 的回答,语言扩展没答(或没装)就是空的
|
||
* filter:整个工作区共用的块筛选;ready 后先于第一份文档发一次,之后任何一个预览改了都发给所有预览
|
||
* qa:这份文件的问答;ready 后发一次,问答、正在答的问题变了再发
|
||
* askProfiles:「问 AI」输入框旁边的 profile 下拉:选项和选中的那项;ready 后发一次,任何一个预览改了都发给所有预览
|
||
* answer:askId 那个问题的回答长了(text 是到现在为止的全文)、或换了在做的事
|
||
* answerEnd:askId 那个问题答完了:done 带最终的回答和存下的那条的 id,failed 带给人看的原因,stopped 是被叫停
|
||
* moveOccurrence:跳到高亮着的名字的下一处(step 1)/ 上一处(step -1)出现,由这两条命令发给活动的预览
|
||
*/
|
||
export type ExtensionToWebview
|
||
= | DocumentMessage
|
||
| ({ type: 'reveal' } & Reveal)
|
||
| { type: 'definitionProbed', id: number, found: boolean }
|
||
| { type: 'occurrencesFound', id: number, occurrences: Occurrence[] }
|
||
| { type: 'moveOccurrence', step: 1 | -1 }
|
||
| { type: 'filter', excluded: Excluded }
|
||
| QaMessage
|
||
| ({ type: 'askProfiles' } & ProfileChoice)
|
||
| { type: 'answer', askId: string, text: string, activity?: string }
|
||
| { type: 'answerEnd', askId: string, status: 'done' | 'failed' | 'stopped', text?: string, error?: string, entryId?: string }
|
||
|
||
/**
|
||
* edit:把 startLine..endLine 这几行整行替换成 text(扩展端给每行补回原来的缩进)
|
||
* visibleLine:预览视口顶部那块的起始行,切回文本编辑器时把这行放到顶部
|
||
* probeDefinition:按住 ⌘ / Ctrl 指到带下标的名字上,问源码 offset 处有没有定义;id 标出是哪一次问,回答带回去;
|
||
* version 是这份下标所属的文档版本
|
||
* goToDefinition:⌘ / Ctrl + 点击,跳到 offset 处名字的定义
|
||
* findOccurrences:单击带下标的名字,问它在这份文档里出现在哪几处;id、version 同 probeDefinition
|
||
* setFilter:改块筛选(整份替换),扩展端记下后发 filter 给所有预览
|
||
* ask:问 anchor 那块代码;askId 由 webview 起,回答的消息带回去;扩展端接着这块最近一次问答的会话问,用眼下选的 profile;
|
||
* images 是贴进输入框的图片(没贴是空的),随问题发给 Claude Code,答成了跟这条一起存
|
||
* stopAsk:叫停 askId 那个问题,这次不存
|
||
* deleteQa:删掉 anchor 那块下面的一次问答(已经理解了)
|
||
* selectAskProfile:「问 AI」换 profile(id 是 profile 名,「默认」是 ''),扩展端记下后发 askProfiles 给所有预览
|
||
* occurrenceNavigation:眼下能不能用键盘在高亮着的名字的各处出现之间跳(有高亮、页面有焦点、焦点不在输入框里),变了才发;
|
||
* 扩展端按它设 when 子句用的上下文键
|
||
*/
|
||
export type WebviewToExtension
|
||
= | { type: 'ready' }
|
||
| { type: 'setFilter', excluded: Excluded }
|
||
| { type: 'edit', startLine: number, endLine: number, text: string }
|
||
| { type: 'selectTranslator', id: string }
|
||
| { type: 'visibleLine', line: number }
|
||
| { type: 'probeDefinition', id: number, version: number, offset: number }
|
||
| { type: 'goToDefinition', version: number, offset: number }
|
||
| { 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: 'selectAskProfile', id: string }
|
||
| { type: 'occurrenceNavigation', available: boolean }
|