✨ feat(vscode): 新增「了解一块代码」:AI 找功能代码占一栏,对话里接着改
主栏标题栏的放大镜问要了解哪一块,占一个栏位建一栏(和收藏共用 30 个栏位,视图改名 slot1..30,按 slotKindN 分收藏 / 功能挂标题栏按钮),同时开对话页让 Claude 只读地在全部工作区文件夹里找,按 --json-schema 交回环节 → 文件 + 符号 + 一句话。 对话复用预览顶部的聊天(CodeQa.askTop:会话续接、进行中的一轮、记录存 workspaceState);结构不合格算这一轮没答成、留着能再画出来。 条目每次画、点时按眼下的代码找:有语言插件的解析成代码块按「类名.方法名」找,没有的问 VS Code 文档符号;找不到画成灰的。
This commit is contained in:
1 parent
16d27004d8
commit
880bf7fc57
38 files changed
+3386
-378
No files matched your search
@@ -1,6 +1,8 @@
|
||||
import type { ExtensionContext, Uri } from 'vscode'
|
||||
import type { CodeReaderApi, RuleLocation, RuleReference } from './contract'
|
||||
import type { TargetSpot } from './editor/openTarget'
|
||||
import type { FileNode } from './explorer/fileTree'
|
||||
import type { FeatureRow } from './features/featureViews'
|
||||
import type { IndexedName } from './nameResolution'
|
||||
import { commands, window, workspace } from 'vscode'
|
||||
import { logger } from '../logging/logger'
|
||||
@@ -21,8 +23,10 @@ import { registerPathAsk } from './explorer/pathAskPanel'
|
||||
import { registerRevealCommands } from './explorer/revealCommands'
|
||||
import { RowDecorator } from './explorer/rowDecorator'
|
||||
import { TreeLocator } from './explorer/treeLocator'
|
||||
import { FAVORITE_SLOTS, favoriteCommand } from './favorites/favoriteSlots'
|
||||
import { favoriteCommand } from './favorites/favoriteSlots'
|
||||
import { FavoriteViews } from './favorites/favoriteViews'
|
||||
import { featureCommand } from './features/features'
|
||||
import { FeatureViews, locateItem, OPEN_FEATURE_ITEM } from './features/featureViews'
|
||||
import { createBashAdapter } from './languages/bash'
|
||||
import { createDockerfileAdapter } from './languages/dockerfile'
|
||||
import { createPythonAdapter } from './languages/python'
|
||||
@@ -49,6 +53,8 @@ import { sqlxRule } from './rules/sqlx'
|
||||
import { tauriRule } from './rules/tauri'
|
||||
import { thiserrorRule } from './rules/thiserror'
|
||||
import { bundledWasmDir, indexGrammar, TreeSitterRuntime } from './runtime'
|
||||
import { SlotPool } from './slots/slotPool'
|
||||
import { SLOTS } from './slots/slots'
|
||||
import { bashZhTranslator } from './translators/bashZh'
|
||||
import { dockerfileZhTranslator } from './translators/dockerfileZh'
|
||||
import { pythonZhTranslator } from './translators/pythonZh'
|
||||
@@ -64,18 +70,26 @@ const LANGUAGE_IDS_CONTEXT = 'superpowers.codeReader.languageIds'
|
||||
const FILES_VIEW = 'superpowers.codeReader.files'
|
||||
const OPEN_COMMAND = 'superpowers.codeReader.open'
|
||||
|
||||
/** 侧栏点文件:语言受支持就用预览打开,否则用 VS Code 默认的打开方式(见 openingFor)。 */
|
||||
async function openFile(uri: Uri, registry: CodeReaderRegistry): Promise<void> {
|
||||
const opening = openingFor(await languageOf(uri), languageId => registry.languageFor(languageId) !== undefined)
|
||||
if (opening.kind === 'preview')
|
||||
// 和 vscode.open 一样按「预览标签」打开(用户关了 workbench.editor.enablePreview 时 VS Code 自会固定)
|
||||
await commands.executeCommand('vscode.openWith', uri, PREVIEW_VIEW_TYPE, { preview: true })
|
||||
/**
|
||||
* 侧栏点文件、点「了解一块代码」栏里的一条:语言受支持就用预览打开,否则用 VS Code 默认的打开方式(见 openingFor)。
|
||||
* 给了 spot(条目的符号在哪)就跳过去:预览滚到那一块、闪一下,普通编辑器选中那个名字。
|
||||
*/
|
||||
async function openFile(uri: Uri, registry: CodeReaderRegistry, previews: PreviewEditorProvider, spot?: TargetSpot): Promise<void> {
|
||||
const opening = openingFor(await languageOf(uri), languageId => registry.languageFor(languageId) !== undefined, spot)
|
||||
if (opening.kind === 'default') {
|
||||
await commands.executeCommand('vscode.open', uri, opening.selection && { selection: opening.selection })
|
||||
return
|
||||
}
|
||||
// 和 vscode.open 一样按「预览标签」打开(用户关了 workbench.editor.enablePreview 时 VS Code 自会固定)
|
||||
const open = (): Thenable<unknown> => commands.executeCommand('vscode.openWith', uri, PREVIEW_VIEW_TYPE, { preview: true })
|
||||
if (opening.reveal)
|
||||
await previews.openAt(uri, opening.reveal, open)
|
||||
else
|
||||
await commands.executeCommand('vscode.open', uri)
|
||||
await open()
|
||||
}
|
||||
|
||||
/**
|
||||
* 接入代码阅读:注册表、侧栏的几栏(主栏的文件树可以按审查工单只看 PR 改过的文件,常驻的「未提交的更改」,每个收藏目录一栏;
|
||||
* 接入代码阅读:注册表、侧栏的几栏(主栏的文件树可以按审查工单只看 PR 改过的文件,常驻的「未提交的更改」,每个收藏目录、每个「了解一块代码」找的功能各一栏;
|
||||
* 行上有问路径、复制、在系统文件管理器里显示、文件注释、收藏目录)、预览编辑器(含问 AI,按文件所在位置标差异)、编辑器右上角的「预览 / 编辑」切换。
|
||||
* 内置的语言插件、翻译插件、库规则和命令规则与其他扩展一样通过返回的 API 注册。
|
||||
*/
|
||||
@@ -104,11 +118,31 @@ export function registerCodeReader(context: ExtensionContext): CodeReaderApi {
|
||||
const locator = new TreeLocator(files, view)
|
||||
const review = new ReviewMode(context, FILES_VIEW, view, files)
|
||||
const uncommitted = new UncommittedView(context, OPEN_COMMAND, decorator)
|
||||
const favorites = new FavoriteViews(context.workspaceState, OPEN_COMMAND, decorator)
|
||||
// 收藏目录、「了解一块代码」共用一池栏位
|
||||
const slots = new SlotPool()
|
||||
const favorites = new FavoriteViews(context.workspaceState, slots, OPEN_COMMAND, decorator)
|
||||
const features = new FeatureViews(context.workspaceState, slots, qa, item => locateItem(item, { adapterFor: languageId => registry.languageFor(languageId), runtime }))
|
||||
const heads = new HeadBases()
|
||||
// 预览对比什么按文件所在的位置定:审查工作副本里的对比 PR 的目标分支,工作区仓库里有改动的对比上一次提交
|
||||
const diffBases = locatedDiffBases([review, heads])
|
||||
const previews = new PreviewEditorProvider(context.extensionUri, registry, runtime, new BlockFilter(context.workspaceState), resolve, qa, namesIn, (index, key) => indexes.find(index, key), diffBases, entries, uri => locator.reveal(uri))
|
||||
const previews = new PreviewEditorProvider(
|
||||
context.extensionUri,
|
||||
registry,
|
||||
runtime,
|
||||
new BlockFilter(context.workspaceState),
|
||||
resolve,
|
||||
qa,
|
||||
namesIn,
|
||||
(index, key) => indexes.find(index, key),
|
||||
diffBases,
|
||||
entries,
|
||||
uri => locator.reveal(uri),
|
||||
(subject, request) => features.ask(subject, request),
|
||||
)
|
||||
const openChat = async (page: Uri | undefined): Promise<void> => {
|
||||
if (page)
|
||||
await previews.openAsking(page)
|
||||
}
|
||||
|
||||
context.subscriptions.push(
|
||||
qa,
|
||||
@@ -139,6 +173,7 @@ export function registerCodeReader(context: ExtensionContext): CodeReaderApi {
|
||||
review,
|
||||
uncommitted,
|
||||
favorites,
|
||||
features,
|
||||
heads,
|
||||
// 主栏审查时刷新是重读 PR 改过的文件,平时是重读工作区文件树
|
||||
commands.registerCommand('superpowers.codeReader.refresh', () => review.reviewing ? review.reload() : files.refresh()),
|
||||
@@ -151,13 +186,23 @@ export function registerCodeReader(context: ExtensionContext): CodeReaderApi {
|
||||
commands.registerCommand('superpowers.codeReader.showUncommittedTests', () => uncommitted.setTestsHidden(false)),
|
||||
// 「更改」组文件行上的按钮传来的是这一行的节点
|
||||
commands.registerCommand('superpowers.codeReader.stage', (node?: FileNode) => uncommitted.stage(node)),
|
||||
// 目录行上的按钮传来的是这一行的节点;收藏栏标题栏上的按钮不带是哪一栏,所以每个栏位各一条命令
|
||||
// 目录行上的按钮传来的是这一行的节点;栏标题栏上的按钮不带是哪一栏,所以每个栏位各一套命令
|
||||
commands.registerCommand('superpowers.codeReader.addFavorite', (node?: FileNode) => favorites.add(node)),
|
||||
...FAVORITE_SLOTS.flatMap(slot => [
|
||||
commands.registerCommand('superpowers.codeReader.findFeature', async () => openChat(await features.find())),
|
||||
...SLOTS.flatMap(slot => [
|
||||
commands.registerCommand(favoriteCommand('rename', slot), () => favorites.rename(slot)),
|
||||
commands.registerCommand(favoriteCommand('remove', slot), () => favorites.remove(slot)),
|
||||
commands.registerCommand(featureCommand('openChat', slot), () => openChat(features.chatPage(slot))),
|
||||
commands.registerCommand(featureCommand('rename', slot), () => features.rename(slot)),
|
||||
commands.registerCommand(featureCommand('remove', slot), () => features.remove(slot)),
|
||||
]),
|
||||
commands.registerCommand(OPEN_COMMAND, (uri: Uri) => openFile(uri, registry)),
|
||||
commands.registerCommand(OPEN_COMMAND, (uri: Uri) => openFile(uri, registry, previews)),
|
||||
// 「了解一块代码」栏里的条目行传来的是这一行:按眼下的代码找到它再打开
|
||||
commands.registerCommand(OPEN_FEATURE_ITEM, async (row?: FeatureRow) => {
|
||||
const found = await features.target(row)
|
||||
if (found)
|
||||
await openFile(found.uri, registry, previews, found.spot)
|
||||
}),
|
||||
// 标题栏按钮传来的是 (文件 Uri, { groupId }),原样转给 VS Code 定位是哪一组的哪个标签
|
||||
commands.registerCommand('superpowers.codeReader.showPreview', (...args: unknown[]) => showPreview(previews, args)),
|
||||
commands.registerCommand('superpowers.codeReader.showSource', (...args: unknown[]) => showSource(previews, args)),
|
||||
|
||||
Reference in new issue
Block a user