✨ feat(vscode): 代码阅读类块改成属性表并默认折叠,类的说明进「说明」行
This commit is contained in:
1 parent
3329aca2e1
commit
43323659e1
22 files changed
+580
-121
No files matched your search
@@ -62,7 +62,7 @@ export function BlockLevel({ blocks, kind, tree }: { blocks: BlockView[], kind?:
|
||||
)
|
||||
}
|
||||
|
||||
/** 预览状态的内容:函数、导入、常量、变量块是属性表,其余是一行译文。 */
|
||||
/** 预览状态的内容:函数、类、导入、常量、变量块是属性表,其余是一行译文。 */
|
||||
function BlockPreview({ block, tree }: { block: BlockView, tree: BlockTreeState }): ReactElement {
|
||||
if ('properties' in block)
|
||||
return <PropertyGrid blockId={block.id} rows={block.properties} collapsed={tree.collapsed} onToggleFold={tree.onToggleFold} />
|
||||
|
||||
@@ -39,7 +39,7 @@ function PropertyItems({ rowId, items }: { rowId: string, items: PropertyItem[]
|
||||
)
|
||||
}
|
||||
|
||||
/** 函数、导入、常量、变量块的预览:属性名一列对齐,值按词性着色;输入参数、导入项下面展开子行。 */
|
||||
/** 函数、类、导入、常量、变量块的预览:属性名一列对齐,值按词性着色;输入参数、导入项下面展开子行。 */
|
||||
export function PropertyGrid({ blockId, rows, collapsed, onToggleFold }: {
|
||||
blockId: string
|
||||
rows: PropertyRow[]
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import MarkdownIt from 'markdown-it'
|
||||
|
||||
/**
|
||||
* 注释、函数说明的 Markdown 排版:CommonMark 加 GFM 的表格、删除线,带 http(s):// 的网址和邮箱自动成链接。
|
||||
* 注释、函数和类说明的 Markdown 排版:CommonMark 加 GFM 的表格、删除线,带 http(s):// 的网址和邮箱自动成链接。
|
||||
* 源码里的 HTML 当文字显示;链接只认 http / https / mailto,别的写法照原文显示——
|
||||
* webview 会拦下 <a> 的点击交给 VS Code 在外部打开。图片不渲染:webview 的 CSP 不放行外部图片。
|
||||
*/
|
||||
|
||||
@@ -245,6 +245,28 @@ describe('跳到定义:TS / Python 源码里闪哪一处', () => {
|
||||
expect(await at('line of')).toEqual({ plan: { id: '1.0', expand: ['1'] }, flashed: 'for (const line of lines) {' })
|
||||
})
|
||||
|
||||
it('类:类名是块自己的名字闪整块,泛型参数只闪「类型参数」一行;类默认折叠,跳到类里的方法、参数要先展开它', async () => {
|
||||
const source = [
|
||||
'export class Repo<T> extends Base {',
|
||||
' load(id: T) {',
|
||||
' return id',
|
||||
' }',
|
||||
'}',
|
||||
].join('\n')
|
||||
const at = (needle: string): ReturnType<typeof jump> => jump(ts, 'typescript', typescriptZhTranslator, source, needle)
|
||||
expect(await at('Repo')).toEqual({ plan: { id: '0', expand: [] }, flashed: 'export class Repo<T> extends Base {' })
|
||||
expect(await at('T>')).toEqual({ plan: { id: '0', row: '0/p3', expand: [] }, flashed: '类型参数: T' })
|
||||
expect(await at('load')).toEqual({ plan: { id: '0.0', expand: ['0'] }, flashed: 'load(id: T) {' })
|
||||
expect(await at('id: T')).toEqual({ plan: { id: '0.0', row: '0.0/p3/0', expand: ['0', '0.0/p3'] }, flashed: 'id | T | ' })
|
||||
const views = await withBlocks(ts, 'typescript', source, blocks => toBlockViews(blocks, source, ts, typescriptZhTranslator))
|
||||
expect([...collapsedIds(views, {})].sort()).toEqual(['0', '0.0'])
|
||||
|
||||
const pySource = ['class NotFound(AppException):', ' """找不到。"""', ' 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('run')).toEqual({ plan: { id: '0.0', expand: ['0'] }, flashed: 'def run(self):' })
|
||||
})
|
||||
|
||||
it('typeScript:翻译插件没标 defines 时闪整块', async () => {
|
||||
const at = (needle: string): ReturnType<typeof jump> => jump(ts, 'typescript', withoutDefines(typescriptZhTranslator), TS, needle)
|
||||
expect(await at('path: string')).toEqual({ plan: { id: '1', expand: ['1/p3'] }, flashed: 'export function load(path: string, { encoding }: Options): string {' })
|
||||
|
||||
@@ -37,7 +37,7 @@ function shows(text: PreviewText, offset: number): boolean {
|
||||
|
||||
/**
|
||||
* 块里哪儿是 offset 处的定义,从具体到笼统:
|
||||
* ① 块自己的名字(函数名、只声明一个变量时的变量名)→ 整块;
|
||||
* ① 块自己的名字(函数名、类名、只声明一个变量时的变量名)→ 整块;
|
||||
* ② 属性表里讲这个定义的一行 / 子行(defines 盖住 offset:参数、导入项、多变量声明里的一个)→ 只闪它,子行连它所在的行一起展开;
|
||||
* ③ 块里只是显示着这个名字(一行译文里的循环变量、没填 defines 的翻译插件)→ 整块,名字在子行里时展开那一行。
|
||||
* 不在这块里是 undefined。
|
||||
|
||||
@@ -20,7 +20,7 @@ export interface Segment { text: string, role: TokenRole, offset?: number }
|
||||
/** 一段 Markdown 说明文字:注释、JSDoc、docstring 去掉注释符号、引号和共同缩进后的原文,按 Markdown 渲染成注释色的段落、列表、代码块 */
|
||||
export interface Markdown { markdown: string }
|
||||
|
||||
/** 预览里显示的一段文字:着色的词(一行译文、属性值),或整段 Markdown 说明(注释块、函数的说明) */
|
||||
/** 预览里显示的一段文字:着色的词(一行译文、属性值),或整段 Markdown 说明(注释块、函数和类的说明) */
|
||||
export type PreviewText = Segment[] | Markdown
|
||||
|
||||
/** 源码里一段的下标,end 为开区间 */
|
||||
@@ -53,12 +53,12 @@ interface BlockViewBase {
|
||||
code: string
|
||||
/** 源码着色(拼起来等于 code) */
|
||||
codeTokens: Segment[]
|
||||
/** 块自己的名字(函数名、只声明一个变量时的变量名)在源码里的范围:跳到的定义就是它时闪整块 */
|
||||
/** 块自己的名字(函数名、类名、只声明一个变量时的变量名)在源码里的范围:跳到的定义就是它时闪整块 */
|
||||
defines?: SourceRange
|
||||
children: BlockView[]
|
||||
}
|
||||
|
||||
/** 函数、导入、常量、变量块预览时是属性表,注释块是 Markdown 说明,其余是一行译文 */
|
||||
/** 函数、类、导入、常量、变量块预览时是属性表,注释块是 Markdown 说明,其余是一行译文 */
|
||||
export type BlockView = BlockViewBase & ({ translation: PreviewText } | { properties: PropertyRow[] })
|
||||
|
||||
export interface TranslatorOption { id: string, label: string }
|
||||
|
||||
@@ -76,12 +76,12 @@ describe('webview 状态', () => {
|
||||
})
|
||||
|
||||
describe('眼下折叠着哪些', () => {
|
||||
it('没点过:函数块(含方法、嵌套函数)折叠,其余块和属性行展开', () => {
|
||||
expect([...collapsedIds(BLOCKS, {})].sort()).toEqual(['1', '1.0.0', '2.0'])
|
||||
it('没点过:函数块(含方法、嵌套函数)、类块折叠,其余块和属性行展开', () => {
|
||||
expect([...collapsedIds(BLOCKS, {})].sort()).toEqual(['1', '1.0.0', '2', '2.0'])
|
||||
})
|
||||
|
||||
it('点过的按用户的:展开的函数保持展开,折叠的其他块、属性行保持折叠', () => {
|
||||
const folds = { '1': false, '2': true, '1.0.0': false, [propertyRowId('0', 2)]: true, [propertyRowId('2.0', 1)]: false }
|
||||
expect([...collapsedIds(BLOCKS, folds)].sort()).toEqual(['0/p2', '2', '2.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(kind: BlockKind): boolean {
|
||||
return kind === 'function'
|
||||
return kind === 'function' || kind === 'class'
|
||||
}
|
||||
|
||||
/** 眼下折叠着的块和属性行:用户点过的按他点的,没点过的按 foldedByDefault。 */
|
||||
|
||||
Reference in new issue
Block a user