✨ feat(vscode): 代码阅读预览里工作区外的库文件也能问 AI,问答记进第一个工作区文件夹,重写注释不对库文件开放
This commit is contained in:
1 parent
cecae0e244
commit
39dfd9b084
24 files changed
+463
-79
No files matched your search
@@ -208,6 +208,29 @@ describe('页面重新加载后,调用树弹框照旧开着', () => {
|
||||
})
|
||||
})
|
||||
|
||||
describe('问 AI 和重写注释各按各的能不能用', () => {
|
||||
const DOC = documentOf(1, [{ ...block('0', 'rglob'), commentTarget: 'replace' }])
|
||||
const qaMessage = (rewritable: boolean): ExtensionToWebview => ({ type: 'qa', available: true, rewritable, threads: [], path: [], subject: 'file', current: [], rewrites: [], rewriteCurrent: [] })
|
||||
const tool = (label: string) => container.querySelector(`[data-id="0"] [aria-label="${label}"]`)
|
||||
|
||||
it('工作区外的库文件(rewritable 为假):块上能问 AI、顶部能问,没有重写注释的按钮', async () => {
|
||||
await load()
|
||||
await deliver(qaMessage(false))
|
||||
await deliver(DOC)
|
||||
expect(tool('问 AI')).not.toBeNull()
|
||||
expect(container.querySelectorAll('.cr-qa')).toHaveLength(1)
|
||||
expect(tool('按注释规范重写')).toBeNull()
|
||||
})
|
||||
|
||||
it('项目里的文件:两个按钮都有', async () => {
|
||||
await load()
|
||||
await deliver(qaMessage(true))
|
||||
await deliver(DOC)
|
||||
expect(tool('问 AI')).not.toBeNull()
|
||||
expect(tool('按注释规范重写')).not.toBeNull()
|
||||
})
|
||||
})
|
||||
|
||||
describe('代码配色跟着当前颜色主题', () => {
|
||||
it('扩展端发来的配色设成 body 上的变量:词性的 --cr-<词性>,种类的 --cr-kind-<种类>;换了主题再发来就换', async () => {
|
||||
const style = document.body.style
|
||||
@@ -309,7 +332,7 @@ describe('一条消息只重画受影响的卡片', () => {
|
||||
|
||||
it('没展开、没说过的块下面不画问答区;展开一块只重画那一块', async () => {
|
||||
await load()
|
||||
await deliver({ type: 'qa', available: true, threads: [], path: [], subject: 'file', current: [], rewrites: [], rewriteCurrent: [] })
|
||||
await deliver({ type: 'qa', available: true, rewritable: true, threads: [], path: [], subject: 'file', current: [], rewrites: [], rewriteCurrent: [] })
|
||||
await deliver(copy(DOC))
|
||||
// 顶部那条一直摊开
|
||||
expect(container.querySelectorAll('.cr-qa')).toHaveLength(1)
|
||||
|
||||
@@ -25,9 +25,9 @@ export function BlockTools({ editing, onToggleEdit, asking, onToggleAsk, rewrite
|
||||
onToggleEdit: () => void
|
||||
/** 块下面的问答区展开着 */
|
||||
asking?: boolean
|
||||
/** 没给就不显示「问 AI」(文件不在工作区文件夹里,问答没地方存) */
|
||||
/** 没给就不显示「问 AI」(问答没地方存) */
|
||||
onToggleAsk?: () => void
|
||||
/** 没给就不显示「按注释规范重写」(不能写注释的块) */
|
||||
/** 没给就不显示「按注释规范重写」(不能写注释的块、工作区外的库文件) */
|
||||
rewrite?: RewriteTool
|
||||
/** 没给就不显示调用树。count 是后台数出的棵数,大于 0 时按钮上带这个数字,是 0 时只有图标(还没数到、没有调用者,点开时会当场再问) */
|
||||
callTree?: { anchor: string, count: number, open: boolean, onOpen: () => void }
|
||||
|
||||
@@ -82,9 +82,9 @@ export interface BlockTreeHandle {
|
||||
edit?: { onToggleEdit: (id: string) => void, onFocused: () => void }
|
||||
/** 打开一块的调用树弹框。和 state.callTree 同时有 */
|
||||
onOpenCall?: (anchor: string) => void
|
||||
/** 问 AI;文件不在工作区文件夹里(问答没地方存)时 state 里 available 是 false */
|
||||
/** 问 AI;问答没地方存(没打开工作区文件夹)时 `state` 里 [ChatState.available] 是 `false` */
|
||||
qa?: QaTree
|
||||
/** 按注释规范重写;同问 AI */
|
||||
/** 按注释规范重写;工作区外的库文件不能重写,`state` 里 [ChatState.available] 是 `false` */
|
||||
rewrite?: RewriteTree
|
||||
}
|
||||
|
||||
@@ -247,7 +247,7 @@ function shapeOf(block: BlockView, state: BlockTreeState): BlockShape {
|
||||
}
|
||||
}
|
||||
|
||||
/** 一块的问 AI:能问(文件在工作区文件夹里)时按钮展开没有;对话区展开着或说过时才有,没展开又没说过的块不画。 */
|
||||
/** 一块的问 AI:能问(问答有地方存)时按钮展开没有;对话区展开着或说过时才有,没展开又没说过的块不画。 */
|
||||
interface AskShape {
|
||||
asking?: boolean
|
||||
chat?: ChatView
|
||||
|
||||
@@ -10,7 +10,7 @@ function thread(anchor: string, ...ids: string[]): QaThreadView {
|
||||
}
|
||||
|
||||
function message(threads: QaThreadView[], current: QaMessage['current'] = []): QaMessage {
|
||||
return { type: 'qa', available: true, threads, path: [], subject: 'file', current, rewrites: [], rewriteCurrent: [] }
|
||||
return { type: 'qa', available: true, rewritable: true, threads, path: [], subject: 'file', current, rewrites: [], rewriteCurrent: [] }
|
||||
}
|
||||
|
||||
function qa(threads: QaThreadView[], current: QaMessage['current'] = []): QaAction {
|
||||
@@ -53,6 +53,7 @@ describe('问 AI 的状态', () => {
|
||||
message: {
|
||||
type: 'qa',
|
||||
available: true,
|
||||
rewritable: true,
|
||||
threads: [],
|
||||
path: [{ id: 'p', question: '这文件夹干什么', answer: '放源码', createdAt: '2026-09-25T10:00:00.000Z' }],
|
||||
subject: 'folder',
|
||||
|
||||
@@ -32,7 +32,7 @@ export const PATH_ASK_ANCHOR = '\0path'
|
||||
|
||||
/** 一种块下面的对话的状态 */
|
||||
export interface ChatState {
|
||||
/** 文件不在工作区文件夹里时记录没地方存,不给这种对话 */
|
||||
/** 这份文件能不能开这种对话(见 [QaMessage.available]、[QaMessage.rewritable]),不能时不给 */
|
||||
available: boolean
|
||||
threads: QaThreadView[]
|
||||
/** 当前这一轮的,按先后 */
|
||||
|
||||
@@ -334,12 +334,14 @@ export interface AskRound {
|
||||
}
|
||||
|
||||
/**
|
||||
* 这份文件的问答和重写记录:available 为假时文件不在工作区文件夹里、没地方存,不给「问 AI」和「重写注释」;
|
||||
* 这份文件的问答和重写记录:[available] 为假时问答没地方存(没打开工作区文件夹),不给「问 AI」;
|
||||
* [rewritable] 为假时不给「重写注释」(工作区外的库文件,重写会改到它本身)。
|
||||
* current、rewriteCurrent 是扩展端记着的当前一轮(页面重新加载后靠它们接上)
|
||||
*/
|
||||
export interface QaMessage {
|
||||
type: 'qa'
|
||||
available: boolean
|
||||
rewritable: boolean
|
||||
threads: QaThreadView[]
|
||||
/** 这一页顶部、按路径记的问答;不挂在块上 */
|
||||
path: QaEntryView[]
|
||||
|
||||
@@ -55,7 +55,7 @@ export function useRewrite(): RewriteTree {
|
||||
const off = onMessage((msg) => {
|
||||
switch (msg.type) {
|
||||
case 'qa':
|
||||
dispatch({ type: 'sync', available: msg.available, threads: msg.rewrites, current: msg.rewriteCurrent })
|
||||
dispatch({ type: 'sync', available: msg.rewritable, threads: msg.rewrites, current: msg.rewriteCurrent })
|
||||
return
|
||||
case 'profiles':
|
||||
if (msg.kind === 'rewrite')
|
||||
|
||||
Reference in new issue
Block a user