✨ feat(vscode): 有说明的函数、类卡片也能重写注释
重写按钮不再只挂在单独的注释卡片上。只替换说明那几行,上下文用这块代码,不当成文件顶上的说明。
This commit is contained in:
1 parent
b608f6cb87
commit
a66e4410e7
5 files changed
+46
-7
No files matched your search
@@ -4,6 +4,7 @@ import type { TreeSitterRuntime } from './runtime'
|
||||
import { blockAttributes } from './attributes'
|
||||
import { KIND_ICONS } from './contract'
|
||||
import { commonIndent, splitLines } from './editText'
|
||||
import { commentSpan } from './languages/shared'
|
||||
import { activeRules, claimBlock, importsIn } from './libraryRules'
|
||||
import { BlockAnchors } from './qa/anchor'
|
||||
|
||||
@@ -35,6 +36,9 @@ interface BlockViewBase {
|
||||
* 同一个 id 只留第一个。webview 按这个画图标,不自己用种类查。
|
||||
*/
|
||||
concepts: BlockConcept[]
|
||||
/** 能重写的那段注释的起止行,0 起。注释块是整块;函数、类等是它的说明。没有说明就没有,不显示重写按钮。 */
|
||||
commentStartLine?: number
|
||||
commentEndLine?: number
|
||||
/** 库规则的卡片才有:筛选栏里这个种类的名字,卡片边框的颜色(RuleCard.badge)。图标在 concepts 里。预览同类块一样默认收起它的子块。 */
|
||||
badge?: KindBadge
|
||||
/** 库规则放进父卡片里的子块才有(见 RuleSlot):画在父卡片属性表第 row 行下面,不排在父卡片的子块里。 */
|
||||
@@ -330,6 +334,11 @@ export function toBlockViews(
|
||||
}
|
||||
return concepts
|
||||
}
|
||||
function commentLines(block: CodeBlock): { commentStartLine: number, commentEndLine: number } | undefined {
|
||||
const span = commentSpan(block)
|
||||
return span && { commentStartLine: span.startLine, commentEndLine: span.endLine }
|
||||
}
|
||||
|
||||
/** 块照它自己的样子(语言插件报的,或库规则认成的属性表块):编辑范围是 span,头部是块自己那部分,子块照常交给各规则看。scope 见 BlockAnchors.place */
|
||||
function plain(block: CodeBlock, span: SourceSpan, id: string, scope: string): BlockView {
|
||||
const name = ownName(block)
|
||||
@@ -343,6 +352,7 @@ export function toBlockViews(
|
||||
...(name && { defines: { startIndex: name.startIndex, endIndex: name.endIndex } }),
|
||||
attributes: blockAttributes(block),
|
||||
concepts: blockConcepts(block),
|
||||
...commentLines(block),
|
||||
children: [
|
||||
...list(block.children, `${id}.`, inner),
|
||||
...embeddedChildren(block, id, inner, block.children.length),
|
||||
@@ -378,6 +388,7 @@ export function toBlockViews(
|
||||
...(defines && { defines: { startIndex: defines.startIndex, endIndex: defines.endIndex } }),
|
||||
attributes: { ...blockAttributes(block), ...attributes, kind },
|
||||
concepts: blockConcepts(block, replacement),
|
||||
...commentLines(block),
|
||||
badge,
|
||||
children: list(kept, `${id}.`, inner, 0, slots),
|
||||
properties: rows,
|
||||
|
||||
@@ -147,6 +147,20 @@ describe('重写注释的提示', () => {
|
||||
expect(isModuleComment('"""旧"""', ['function'])).toBe(false)
|
||||
})
|
||||
|
||||
it('函数上的说明用这块代码当上下文,不当成文件顶上的说明', () => {
|
||||
const prompt = commentRewritePrompt({
|
||||
comment: '"""旧说明"""',
|
||||
source: 'def run():\n """旧说明"""\n return 1\n\ndef other():\n return 2',
|
||||
startLine: 1,
|
||||
endLine: 1,
|
||||
earlierKinds: [],
|
||||
attached: 'def run():\n return 1',
|
||||
})
|
||||
expect(prompt).toContain('def run():')
|
||||
expect(prompt).toContain('return 1')
|
||||
expect(prompt).not.toContain('def other()')
|
||||
})
|
||||
|
||||
it('模型套了代码围栏时只留里面的正文', () => {
|
||||
expect(modelCommentBody('```\n新说明\n```')).toBe('新说明')
|
||||
expect(modelCommentBody(' ')).toBeUndefined()
|
||||
|
||||
@@ -285,6 +285,8 @@ export interface CommentRewriteInput {
|
||||
earlierKinds: readonly string[]
|
||||
/** 普通注释后面紧挨着的那一块的原文;没有就不填 */
|
||||
following?: string
|
||||
/** 说明挂在这块代码上(函数、类的 docstring)。有它就不当成文件顶上的说明,上下文用这块。 */
|
||||
attached?: string
|
||||
}
|
||||
|
||||
/** 发给模型的整段话。开头是技能命令,Claude Code 自己加载技能。注释认不出就不组。 */
|
||||
@@ -292,12 +294,14 @@ export function commentRewritePrompt(input: CommentRewriteInput): string | undef
|
||||
const body = commentProse(input.comment)
|
||||
if (body === undefined)
|
||||
return undefined
|
||||
const fileComment = isModuleComment(input.comment, input.earlierKinds)
|
||||
const context = fileComment
|
||||
? clip(splitLines(input.source).filter((_, index) => index < input.startLine || index > input.endLine).join('\n').trim(), '文件其余部分')
|
||||
: input.following
|
||||
? clip(input.following, '这块代码')
|
||||
: { text: '(后面没有紧挨着的代码)', note: '' }
|
||||
const fileComment = input.attached === undefined && isModuleComment(input.comment, input.earlierKinds)
|
||||
const context = input.attached !== undefined
|
||||
? clip(input.attached, '这块代码')
|
||||
: fileComment
|
||||
? clip(splitLines(input.source).filter((_, index) => index < input.startLine || index > input.endLine).join('\n').trim(), '文件其余部分')
|
||||
: input.following
|
||||
? clip(input.following, '这块代码')
|
||||
: { text: '(后面没有紧挨着的代码)', note: '' }
|
||||
return [
|
||||
COMMENT_SKILL,
|
||||
'只按这个技能重写这一段注释。用中文。不要改代码,不要加技能没要求的中文名记号。只输出新注释的正文,不要定界符,不要解释。',
|
||||
|
||||
@@ -219,6 +219,16 @@ function ownDoc(block: CodeBlock): Node | undefined {
|
||||
}
|
||||
}
|
||||
|
||||
/** 能重写的那段注释:注释块是整块;函数、类、枚举、异常、常量、变量是它的说明。没有说明就没有。 */
|
||||
export function commentSpan(block: CodeBlock): { startLine: number, endLine: number } | undefined {
|
||||
if (block.kind === 'comment')
|
||||
return { startLine: block.header.startRow, endLine: block.header.endRow }
|
||||
const doc = ownDoc(block)
|
||||
if (!doc)
|
||||
return undefined
|
||||
return { startLine: doc.startPosition.row, endLine: doc.endPosition.row }
|
||||
}
|
||||
|
||||
/** 类属性的说明,照源码顺序:紧挨在它上面的注释块、它这一行行尾的注释、Python 紧跟在后面的属性 docstring。 */
|
||||
function fieldDocs(children: readonly CodeBlock[], block: CodeBlock): Node[] {
|
||||
const trailing = block.node.nextNamedSibling
|
||||
|
||||
Reference in new issue
Block a user