✨ feat(vscode): 代码阅读加「问 AI」,块下面问 Claude Code,问答存进 .spx 挂在块下

This commit is contained in:
cruldra committed 2026-09-26 21:12:47 +08:00
1 parent badc722640
commit fb53bb727c
34 files changed
+2726 -43

No files matched your search

+21 -10
View File
@@ -3,10 +3,13 @@ import type { TreeSitterRuntime } from './runtime'
import { blockAttributes } from './attributes'
import { commonIndent, splitLines } from './editText'
import { activeRules, claimBlock, claimedShape, importsIn } from './libraryRules'
import { BlockAnchors } from './qa/anchor'
interface BlockViewBase {
/** 在树里的位置,例如 '6.1.0'。 */
id: string
/** 块的位置记号(见 BlockAnchors):问答挂在它上面,文件别处改了照样认得回来。 */
anchor: string
/** BlockKind,或库规则卡片的种类 id(RuleCard.kind,带点,例如 sqlalchemy.table)。 */
kind: string
/**
@@ -155,41 +158,49 @@ export function toBlockViews(blocks: CodeBlock[], source: string, adapter: Langu
const doc = block.doc && translator?.doc(block.doc, document)
return { translation: translator ? translator.translate(block, document) : [], ...(doc && { doc }) }
}
/** 块照它自己的样子(语言插件报的,或库规则认成的属性表块):头部是编辑范围,子块照常交给各规则看。 */
function plain(block: CodeBlock, id: string): BlockView {
/** 按源码先后逐块给位置记号:先序遍历,块的记号在它的子块之前要 */
const anchors = new BlockAnchors()
/** 块照它自己的样子(语言插件报的,或库规则认成的属性表块):头部是编辑范围,子块照常交给各规则看。scope 见 BlockAnchors.place */
function plain(block: CodeBlock, id: string, scope: string): BlockView {
const name = ownName(block)
const rows = sourceRows(block.node.tree.rootNode, block.header.startRow, block.header.endRow)
const { anchor, inner } = anchors.place(scope, block.kind, name?.text, rows.code)
return {
id,
anchor,
kind: block.kind,
...sourceRows(block.node.tree.rootNode, block.header.startRow, block.header.endRow),
...rows,
...(name && { defines: { startIndex: name.startIndex, endIndex: name.endIndex } }),
attributes: blockAttributes(block),
children: block.children.map((child, i) => build(child, `${id}.${i}`)),
children: block.children.map((child, i) => build(child, `${id}.${i}`, inner)),
...('facts' in block ? { properties: translator ? translator.describe(block, document) : [] } : textView(block)),
}
}
function build(block: CodeBlock, id: string): BlockView {
function build(block: CodeBlock, id: string, scope: string): BlockView {
const claim = active.length > 0 ? claimBlock(block, active, context, rules.report) : undefined
if (!claim)
return plain(block, id)
return plain(block, id, scope)
const { span, kept } = claimedShape(block, claim.block.absorbs)
if ('as' in claim.block) {
const { attributes } = block
return plain({ ...claim.block.as, node: block.node, header: span, children: kept, ...(attributes && { attributes }) }, id)
return plain({ ...claim.block.as, node: block.node, header: span, children: kept, ...(attributes && { attributes }) }, id, scope)
}
const { kind, badge, rows, defines, attributes } = claim.block
const lines = sourceRows(block.node.tree.rootNode, span.startRow, span.endRow)
const { anchor, inner } = anchors.place(scope, kind, defines && source.slice(defines.startIndex, defines.endIndex), lines.code)
return {
id,
anchor,
kind,
...sourceRows(block.node.tree.rootNode, span.startRow, span.endRow),
...lines,
...(defines && { defines: { startIndex: defines.startIndex, endIndex: defines.endIndex } }),
attributes: { ...blockAttributes(block), ...attributes, kind },
badge,
children: kept.map((child, i) => build(child, `${id}.${i}`)),
children: kept.map((child, i) => build(child, `${id}.${i}`, inner)),
properties: rows,
}
}
return blocks.map((block, i) => build(block, String(i)))
return blocks.map((block, i) => build(block, String(i), ''))
}
/** 解析一份源码并转成视图数据;语法树用完即释放。 */