✨ feat(vscode): 代码阅读加异常卡片,Python、TypeScript 的异常类画成同一张表(属性、构造参数),方法照常是子块

This commit is contained in:
cruldra committed 2026-09-27 10:42:10 +08:00
1 parent d5a092dd6f
commit 0afd012c94
21 files changed
+1118 -66

No files matched your search

@@ -15,6 +15,7 @@ body {
--cr-kind-function: #dcdcaa;
--cr-kind-type: #4ec9b0;
--cr-kind-enum: #b180d7;
--cr-kind-exception: #f14c4c;
--cr-kind-data: #9cdcfe;
--cr-kind-branch: #ce9178;
--cr-kind-loop: #8f9cff;
@@ -45,6 +46,7 @@ body.vscode-high-contrast-light {
--cr-kind-function: #795e26;
--cr-kind-type: #267f99;
--cr-kind-enum: #652d90;
--cr-kind-exception: #cd3131;
--cr-kind-data: #001080;
--cr-kind-branch: #a31515;
--cr-kind-loop: #4f56d6;
@@ -59,6 +61,7 @@ body.vscode-high-contrast-light {
[data-kind="function"] { --kind: var(--cr-kind-function); }
:is([data-kind="class"], [data-kind="type"]) { --kind: var(--cr-kind-type); }
[data-kind="enum"] { --kind: var(--cr-kind-enum); }
[data-kind="exception"] { --kind: var(--cr-kind-exception); }
:is([data-kind="field"], [data-kind="const"], [data-kind="variable"]) { --kind: var(--cr-kind-data); }
:is([data-kind="if"], [data-kind="else"]) { --kind: var(--cr-kind-branch); }
[data-kind="loop"] { --kind: var(--cr-kind-loop); }
@@ -326,12 +326,34 @@ describe('跳到定义:TS / Python 源码里闪哪一处', () => {
const views = await withBlocks(ts, 'typescript', source, blocks => toBlockViews(blocks, { source, language: ts, markers: [] }, typescriptZhTranslator))
expect([...collapsedIds(views, {})].sort()).toEqual(['0', '0.0'])
const pySource = ['class NotFound(AppException):', ' """找不到。"""', ' def run(self):', ' pass'].join('\n')
const pySource = ['class NotFound(AppResponse):', ' """找不到。"""', ' def run(self):', ' pass'].join('\n')
const atPy = (needle: string): ReturnType<typeof jump> => jump(py, 'python', pythonZhTranslator, pySource, needle)
expect(await atPy('NotFound')).toEqual({ plan: { id: '0', expand: [] }, flashed: 'class NotFound(AppException):' })
expect(await atPy('NotFound')).toEqual({ plan: { id: '0', expand: [] }, flashed: 'class NotFound(AppResponse):' })
expect(await atPy('run')).toEqual({ plan: { id: '0.0', expand: ['0'] }, flashed: 'def run(self):' })
})
it('异常块:类名闪整块,属性名只闪「属性」表里它那一行,构造函数的参数只闪「构造参数」表里它那一行(都先展开那一行);留下的构造函数照常是子块,异常块默认折叠', async () => {
const source = [
'class Failed(Exception):',
' status = 500',
'',
' def __init__(self, message: str) -> None:',
' self.message = message',
].join('\n')
const at = (needle: string): ReturnType<typeof jump> => jump(py, 'python', pythonZhTranslator, source, needle)
expect(await at('Failed')).toEqual({ plan: { id: '0', expand: [] }, flashed: 'class Failed(Exception):' })
expect(await at('status')).toEqual({ plan: { id: '0', row: '0/p3/0', expand: ['0/p3'] }, flashed: 'status | 500' })
expect(await at('message: str')).toEqual({ plan: { id: '0', row: '0/p4/0', expand: ['0/p4'] }, flashed: 'message | 字符串 | ' })
expect(await at('__init__')).toEqual({ plan: { id: '0.0', expand: ['0'] }, flashed: 'def __init__(self, message: str) -> None:' })
const tsSource = 'export class ApiError extends Error {\n status = 500\n constructor(public code: string) {\n super(code)\n }\n}'
const atTs = (needle: string): ReturnType<typeof jump> => jump(ts, 'typescript', typescriptZhTranslator, tsSource, needle)
expect(await atTs('status')).toEqual({ plan: { id: '0', row: '0/p3/0', expand: ['0/p3'] }, flashed: 'status | 500' })
expect(await atTs('code:')).toEqual({ plan: { id: '0', row: '0/p4/0', expand: ['0/p4'] }, flashed: 'code | 字符串 | ' })
const views = await withBlocks(ts, 'typescript', tsSource, blocks => toBlockViews(blocks, { source: tsSource, language: ts, markers: [] }, typescriptZhTranslator))
expect([...collapsedIds(views, {})].sort()).toEqual(['0', '0.0'])
})
it('库规则认领的块:类名闪整块,字段名只闪字段表里它那一行(先展开「字段」那一行);留下的方法照常,卡片默认折叠', async () => {
const source = [
'from sqlalchemy.orm import Mapped, mapped_column',
+1 -1
View File
@@ -3,7 +3,7 @@
*/
export type BlockKind
= | 'import' | 'function' | 'class' | 'enum' | 'type' | 'field' | 'const' | 'variable'
= | 'import' | 'function' | 'class' | 'enum' | 'exception' | 'type' | 'field' | 'const' | 'variable'
| 'if' | 'else' | 'loop' | 'try' | 'catch' | 'finally' | 'return' | 'statement' | 'comment'
/** 着色用的词性,源码着色和译文着色共用。 */
@@ -115,6 +115,10 @@ describe('眼下折叠着哪些', () => {
expect([...collapsedIds([block('0', 'enum', [block('0.0', 'function')]), block('1', 'if')], {})]).toEqual(['0', '0.0'])
})
it('没点过:异常块(下面留着构造函数、方法)和类块一样折叠', () => {
expect([...collapsedIds([block('0', 'exception', [block('0.0', 'function')]), block('1', 'if')], {})]).toEqual(['0', '0.0'])
})
it('点过的按用户的:展开的函数、类保持展开,折叠的其他块、属性行保持折叠', () => {
const folds = { '1': false, '2': false, '1.0': true, '1.0.0': false, [propertyRowId('0', 2)]: true, [propertyRowId('2.0', 1)]: false }
expect([...collapsedIds(BLOCKS, folds)].sort()).toEqual(['0/p2', '1.0', '2.0'])
@@ -54,9 +54,9 @@ function readViewState(saved: unknown): ViewState {
return isScrollAnchor(state.scroll) ? { editing, folds, scroll: state.scroll } : { editing, folds }
}
/** 块默认折叠吗:函数、类、枚举块和库规则的卡片收起子块(属性表照常显示),其余块展开。属性行和带下一层的子行默认都展开。 */
/** 块默认折叠吗:函数、类、枚举、异常块和库规则的卡片收起子块(属性表照常显示),其余块展开。属性行和带下一层的子行默认都展开。 */
export function foldedByDefault(block: Pick<BlockView, 'kind' | 'badge'>): boolean {
return block.badge !== undefined || block.kind === 'function' || block.kind === 'class' || block.kind === 'enum'
return block.badge !== undefined || ['function', 'class', 'enum', 'exception'].includes(block.kind)
}
/** 眼下折叠着的块、属性行和子行:用户点过的按他点的,没点过的按 foldedByDefault。 */