✨ feat(vscode): 代码阅读「了解一块代码」改成按路径列调用树:结果是几条路径(用户的一种操作一条),每条从入口一路调到后端服务、数据表,跨进程的写明怎么连过去(via),结构用扁平的 nodes 加 parent 连成树、不用递归;侧栏路径下面一层层展开节点,回答里用嵌套列表画树;回答和找的过程里的代码位置写成仓库链接,功能对话页上的链接按找代码用的工作区文件夹检查、打开、悬停;旧格式的结果当没有,栏上方提示打开对话重新找;删功能前先弹模态框确认,说清连带删掉调用树和问答记录,点「删除」才删
This commit is contained in:
1 parent
cc445e7123
commit
c6de46ad37
17 files changed
+978
-253
No files matched your search
@@ -3,24 +3,28 @@
|
||||
* 这里是记录怎么读、怎么改,栏里一行、栏上方一句话怎么写。不碰 VS Code。
|
||||
*/
|
||||
|
||||
import type { FeatureItem, FeatureResult } from './featureResult'
|
||||
import type { CallNode, FeatureResult } from './featureResult'
|
||||
import { escapeMarkdown } from '../explorer/rowDecoration'
|
||||
import { freeSlot, SLOTS } from '../slots/slots'
|
||||
import { itemLabel, parseFeatureResult } from './featureResult'
|
||||
|
||||
/** 一个功能:question 是用户问的那句话(对话页标签上的名字,开新会话时发给 AI),name 是栏标题(开始时就是问题),result 是 AI 最近一次交回的结果(还没交回过时没有)。 */
|
||||
/**
|
||||
* 一个功能:question 是用户问的那句话(对话页标签上的名字,开新会话时发给 AI),name 是栏标题(开始时就是问题),result 是 AI 最近一次交回的结果(还没交回过时没有)。
|
||||
* `outdated` 是存着的结果是以前的格式、读不了,只好当没有结果,栏上方提示重新找一次;交回新结果后就没有了。
|
||||
*/
|
||||
export interface Feature {
|
||||
id: string
|
||||
question: string
|
||||
name: string
|
||||
slot: number
|
||||
result?: FeatureResult
|
||||
outdated?: true
|
||||
}
|
||||
|
||||
/** 功能栏里找得到的条目行的 contextValue 带的标记(见 entryContext):行菜单只挂文件能用的那几样(问 AI、复制、在系统文件管理器中显示)。 */
|
||||
/** 功能栏里找得到的节点行的 contextValue 带的标记(见 entryContext):行菜单只挂文件能用的那几样(问 AI、复制、在系统文件管理器中显示)。 */
|
||||
export const FEATURE_MARKER = 'feature'
|
||||
|
||||
/** 找不到的条目行的 contextValue:什么菜单都不挂。 */
|
||||
/** 找不到的节点行的 contextValue:什么菜单都不挂。 */
|
||||
export const MISSING_CONTEXT = `${FEATURE_MARKER} missing`
|
||||
|
||||
/** 第 slot 个功能栏标题栏上的按钮命令:openChat 打开对话、rename 重命名、remove 删除。标题栏按钮不知道点的是哪一栏,所以每个栏位各一条。 */
|
||||
@@ -47,7 +51,8 @@ export function parseFeatures(value: unknown): Feature[] {
|
||||
if (features.some(feature => feature.slot === slot))
|
||||
continue
|
||||
const parsed = result === undefined ? undefined : parseFeatureResult(result)
|
||||
features.push({ id, question, name, slot, ...(parsed && 'result' in parsed && { result: parsed.result }) })
|
||||
const outdated = raw.outdated === true || (parsed !== undefined && 'error' in parsed)
|
||||
features.push({ id, question, name, slot, ...(parsed && 'result' in parsed && { result: parsed.result }), ...(outdated && { outdated }) })
|
||||
}
|
||||
return features
|
||||
}
|
||||
@@ -64,7 +69,7 @@ export function renameFeature(features: readonly Feature[], slot: number, name:
|
||||
|
||||
/** id 那个功能换成这次交回的结果。 */
|
||||
export function withResult(features: readonly Feature[], id: string, result: FeatureResult): Feature[] {
|
||||
return features.map(feature => feature.id === id ? { ...feature, result } : feature)
|
||||
return features.map(({ outdated, ...feature }) => feature.id === id ? { ...feature, result } : { ...feature, ...(outdated && { outdated }) })
|
||||
}
|
||||
|
||||
/** 删掉第 slot 栏的功能,空出这个栏位。 */
|
||||
@@ -73,12 +78,16 @@ export function removeFeature(features: readonly Feature[], slot: number): Featu
|
||||
}
|
||||
|
||||
/**
|
||||
* 栏里一行条目怎么画:名字(符号名,只有文件的写文件名)、后面淡色的那一句话、悬停提示(文件、符号、那句话)。
|
||||
* found 是按眼下的代码找没找到;找不到的悬停先说「找不到了」。
|
||||
* 栏里调用树上一个节点的那一行怎么画:名字(符号名,只有文件的写文件名)、后面淡色的说明(跨进程连过来的先写怎么连的,再写那一句话)、
|
||||
* 悬停提示(文件路径和那一句话)。found 是按眼下的代码找没找到;找不到的悬停先说「找不到了」。
|
||||
*/
|
||||
export function itemRow(item: FeatureItem, found: boolean): { label: string, description: string, tooltip: string } {
|
||||
const lines = [`**${escapeMarkdown(item.path)}**`, ...(item.symbol === undefined ? [] : [escapeMarkdown(item.symbol)]), escapeMarkdown(item.role)]
|
||||
return { label: itemLabel(item), description: item.role, tooltip: [...(found ? [] : ['找不到了']), ...lines].join(' \n') }
|
||||
export function nodeRow(node: CallNode, found: boolean): { label: string, description: string, tooltip: string } {
|
||||
const lines = [`**${escapeMarkdown(node.path)}**`, escapeMarkdown(node.role)]
|
||||
return {
|
||||
label: itemLabel(node),
|
||||
description: node.via === undefined ? node.role : `${node.via} · ${node.role}`,
|
||||
tooltip: [...(found ? [] : ['找不到了']), ...lines].join(' \n'),
|
||||
}
|
||||
}
|
||||
|
||||
/** 一个功能眼下在不在找:running 还在找(activity 是正在做的事),failed 没找成(error 是原因),stopped 被叫停了;没在找时没有。 */
|
||||
@@ -93,10 +102,10 @@ function sentence(text: string): string {
|
||||
}
|
||||
|
||||
/**
|
||||
* 栏上方的一句话(TreeView.message):正在找、没找成(可以在对话里接着说重试)、没找到相关的代码、还没有结果;
|
||||
* 栏上方的一句话(TreeView.message):正在找、没找成(可以在对话里接着说重试)、没找到相关的代码、还没有结果、存着的结果是旧格式(`outdated`,见 [Feature]);
|
||||
* 有结果、又没在找时不说话。有旧结果时再找没成,旧结果留着。
|
||||
*/
|
||||
export function featureMessage(result: FeatureResult | undefined, run: FeatureRun | undefined): string | undefined {
|
||||
export function featureMessage(result: FeatureResult | undefined, run: FeatureRun | undefined, outdated = false): string | undefined {
|
||||
if (run?.status === 'running') {
|
||||
const doing = result ? '正在按你说的改…' : '正在找…'
|
||||
return run.activity ? `${doing}(${run.activity})` : doing
|
||||
@@ -106,9 +115,12 @@ export function featureMessage(result: FeatureResult | undefined, run: FeatureRu
|
||||
? `这次没改成:${sentence(run.error)}下面还是上一次的结果,可以在对话里接着说,让它再改一次。`
|
||||
: `没找成:${sentence(run.error)}可以在对话里接着说,让它再找一次。`
|
||||
}
|
||||
if (!result)
|
||||
return '还没有结果,可以在对话里接着说,让它再找一次。'
|
||||
if (result.groups.length === 0)
|
||||
if (!result) {
|
||||
return outdated
|
||||
? '结果是旧格式,点标题栏的「打开对话」,说一声「重新找」,就按路径和调用树重新找一次。'
|
||||
: '还没有结果,可以在对话里接着说,让它再找一次。'
|
||||
}
|
||||
if (result.paths.length === 0)
|
||||
return '没找到和这个功能直接相关的代码,可以在对话里换个说法接着说。'
|
||||
return undefined
|
||||
}
|
||||
Reference in new issue
Block a user