import { describe, expect, it } from 'vitest' import { blockCodes, toBlockViews } from './blockView' import { blockReplacement, commonIndent, reindentBlock, replaceLines } from './editText' import { createPythonAdapter } from './languages/python' import { createTypeScriptAdapter } from './languages/typescript' import { readFixture, WASM_DIR, withBlocks } from './testSupport' describe('行替换', () => { it('多行块替换后每个非空行补回原来的缩进,空行保持空', () => { const source = [ 'function f() {', ' if (a)', ' return 1', '}', ].join('\n') const edited = replaceLines(source, 1, 2, 'if (a && b) {\n\n return 2\n}') expect(edited).toBe([ 'function f() {', ' if (a && b) {', '', ' return 2', ' }', '}', ].join('\n')) }) it('保留 \\r\\n 换行', () => { expect(replaceLines('a\r\n b\r\n c\r\n', 1, 1, 'x\ny')).toBe('a\r\n x\r\n y\r\n c\r\n') }) it('共同缩进逐字符比,混用制表符和空格时只取相同的前缀', () => { expect(commonIndent(['\t a', '', '\t b'])).toBe('\t ') expect(commonIndent(['\ta', ' b'])).toBe('') expect(reindentBlock([' x'], 'a\n b')).toBe(' a\n b') }) it.each([ [createTypeScriptAdapter(WASM_DIR), 'typescript', 'envLock.ts.txt'], [createTypeScriptAdapter(WASM_DIR), 'typescript', 'issueLock.ts.txt'], [createTypeScriptAdapter(WASM_DIR), 'typescript', 'classes.ts.txt'], [createPythonAdapter(WASM_DIR), 'python', 'sample.py'], [createPythonAdapter(WASM_DIR), 'python', 'routes.py'], [createPythonAdapter(WASM_DIR), 'python', 'classes.py'], ] as const)('%#: 把预览里的 code 原样写回,文件不变(去缩进与补缩进互逆,函数、类头部连着说明也一样)', async (adapter, languageId, fixture) => { const source = readFixture(fixture) const views = await withBlocks(adapter, languageId, source, blocks => toBlockViews(blocks, { source, language: adapter, markers: [] }, undefined)) const all = views.flatMap(function flat(view): typeof views { return [view, ...view.children.flatMap(flat)] }) for (const view of all) expect(replaceLines(source, view.startLine, view.endLine, blockCodes(source)(view)), view.id).toBe(source) }) }) describe('块内修改写回的替换范围', () => { const doc = ['class A {', ' run() {', ' go()', ' }', '}'] const lineAt = (n: number): string => doc[n] it('从起始行行首替换到结束行行尾,新文本补回原来的缩进', () => { expect(blockReplacement(lineAt, doc.length, 1, 2, 'run(): void {\n go(1)')).toEqual({ startLine: 1, endLine: 2, endCharacter: 8, text: ' run(): void {\n go(1)', unchanged: false, }) }) it('改完和原来一样时标记 unchanged', () => { expect(blockReplacement(lineAt, doc.length, 1, 2, 'run() {\n go()')?.unchanged).toBe(true) }) it('行号已不在文档里时不替换', () => { expect(blockReplacement(lineAt, doc.length, 3, 5, 'x')).toBeUndefined() expect(blockReplacement(lineAt, doc.length, -1, 0, 'x')).toBeUndefined() expect(blockReplacement(lineAt, doc.length, 2, 1, 'x')).toBeUndefined() expect(blockReplacement(lineAt, doc.length, 0.5, 1, 'x')).toBeUndefined() }) })