✨ feat(vscode): 代码阅读加「问 AI」,块下面问 Claude Code,问答存进 .spx 挂在块下
This commit is contained in:
1 parent
badc722640
commit
fb53bb727c
34 files changed
+2726
-43
No files matched your search
@@ -0,0 +1,102 @@
|
||||
import type { BlockView } from '../blockView'
|
||||
import { describe, expect, it } from 'vitest'
|
||||
import { toBlockViews } from '../blockView'
|
||||
import { createPythonAdapter } from '../languages/python'
|
||||
import { WASM_DIR, withBlocks } from '../testSupport'
|
||||
import { anchorSteps, BlockAnchors } from './anchor'
|
||||
|
||||
const py = createPythonAdapter(WASM_DIR)
|
||||
|
||||
function views(source: string): Promise<BlockView[]> {
|
||||
return withBlocks(py, 'python', source, blocks => toBlockViews(blocks, source, py, undefined))
|
||||
}
|
||||
|
||||
function flatten(list: BlockView[]): BlockView[] {
|
||||
return list.flatMap(view => [view, ...flatten(view.children)])
|
||||
}
|
||||
|
||||
/** 各块的记号,按源码先后,连同它这块的第一行源码 */
|
||||
async function anchors(source: string): Promise<[string, string][]> {
|
||||
return flatten(await views(source)).map(view => [view.anchor, view.code.split('\n')[0]])
|
||||
}
|
||||
|
||||
const SOURCE = `class ReferralRelation(Base):
|
||||
def display(self):
|
||||
if self.active:
|
||||
return self.name
|
||||
return "none"
|
||||
|
||||
def other(self):
|
||||
if self.active:
|
||||
return 1
|
||||
|
||||
|
||||
def helper(x):
|
||||
print(x)
|
||||
print(x)
|
||||
`
|
||||
|
||||
describe('块的位置记号', () => {
|
||||
it('有名字的块是外层各个有名字的块加自己的种类和名字;没名字的块是外层最近的有名字的块加种类和源码哈希;同一层重复的依次编号', async () => {
|
||||
const list = await anchors(SOURCE)
|
||||
const hashed = (anchor: string): string => anchor.replace(/@[0-9a-f]{8}/g, '@#')
|
||||
expect(list.map(([anchor, code]) => [hashed(anchor), code])).toEqual([
|
||||
['class ReferralRelation', 'class ReferralRelation(Base):'],
|
||||
['class ReferralRelation > function display', 'def display(self):'],
|
||||
['class ReferralRelation > function display > if @#', 'if self.active:'],
|
||||
['class ReferralRelation > function display > return @#', 'return self.name'],
|
||||
['class ReferralRelation > function display > return @#', 'return "none"'],
|
||||
['class ReferralRelation > function other', 'def other(self):'],
|
||||
['class ReferralRelation > function other > if @#', 'if self.active:'],
|
||||
['class ReferralRelation > function other > return @#', 'return 1'],
|
||||
['function helper', 'def helper(x):'],
|
||||
['function helper > statement @#', 'print(x)'],
|
||||
['function helper > statement @#[1]', 'print(x)'],
|
||||
])
|
||||
// 两个函数里一模一样的条件各在各的函数下面,互不影响;源码不同的两个返回哈希不同
|
||||
expect(list[2][0].split(' > ').at(-1)).toBe(list[6][0].split(' > ').at(-1))
|
||||
expect(list[3][0]).not.toBe(list[4][0])
|
||||
expect(new Set(list.map(([anchor]) => anchor)).size).toBe(list.length)
|
||||
})
|
||||
|
||||
it('上面插几行、改缩进和空白:记号都不变', async () => {
|
||||
const before = await anchors(SOURCE)
|
||||
const after = await anchors(`import os\n\n# 新加的注释\n${SOURCE.replace('print(x)\n print(x)', 'print( x )\n print(x)')}`)
|
||||
const shifted = after.filter(([anchor]) => before.some(([old]) => old === anchor))
|
||||
expect(shifted.map(([anchor]) => anchor)).toEqual(before.map(([anchor]) => anchor))
|
||||
})
|
||||
|
||||
it('改别的函数的名字:别处的记号不变,改名的函数和它里面的块换了记号', async () => {
|
||||
const before = new Set((await anchors(SOURCE)).map(([anchor]) => anchor))
|
||||
const after = (await anchors(SOURCE.replace('def other(self)', 'def renamed(self)'))).map(([anchor]) => anchor)
|
||||
const kept = after.filter(anchor => before.has(anchor))
|
||||
expect(kept).toEqual([...before].filter(anchor => !anchor.includes('function other')))
|
||||
expect(after.filter(anchor => !before.has(anchor)).every(anchor => anchor.includes('function renamed'))).toBe(true)
|
||||
})
|
||||
|
||||
it('没名字的块自己的源码改了:记号变了,旧问答认不回来;有名字的块改了主体、签名照样认得', async () => {
|
||||
const before = await anchors(SOURCE)
|
||||
const after = await anchors(SOURCE.replace('if self.active:\n return self.name', 'if self.visible:\n return self.name').replace('def helper(x):', 'def helper(x, y=1):'))
|
||||
const anchorOf = (list: [string, string][], code: string): string | undefined => list.find(([, line]) => line === code)?.[0]
|
||||
expect(after.map(([anchor]) => anchor)).not.toContain(anchorOf(before, 'if self.active:'))
|
||||
expect(anchorOf(after, 'return self.name')).toBe(anchorOf(before, 'return self.name'))
|
||||
expect(anchorOf(after, 'def helper(x, y=1):')).toBe(anchorOf(before, 'def helper(x):'))
|
||||
})
|
||||
|
||||
it('拆回各层:没名字的一层只有种类,编号去掉', () => {
|
||||
expect(anchorSteps('class ReferralRelation > function display[1] > if @3fa1c2d0[2]')).toEqual([
|
||||
{ kind: 'class', name: 'ReferralRelation' },
|
||||
{ kind: 'function', name: 'display' },
|
||||
{ kind: 'if' },
|
||||
])
|
||||
expect(anchorSteps('variable { a, b }')).toEqual([{ kind: 'variable', name: '{ a, b }' }])
|
||||
})
|
||||
|
||||
it('名字里的空白压成一个空格,空名字按没名字算', () => {
|
||||
const anchors = new BlockAnchors()
|
||||
expect(anchors.place('', 'variable', '{\n a,\n b\n}', '').anchor).toBe('variable { a, b }')
|
||||
const unnamed = anchors.place('scope', 'statement', ' ', 'x = 1')
|
||||
expect(unnamed.anchor).toMatch(/^scope > statement @[0-9a-f]{8}$/)
|
||||
expect(unnamed.inner).toBe('scope')
|
||||
})
|
||||
})
|
||||
Reference in new issue
Block a user