✨ feat(vscode): 代码阅读的调用与构造:跨多行写的调用排成「新建 / 调用 名字 · N 个参数」一行,实参摊成参数 / 值表;Python 查被调用名字的定义分新建和调用,查到后刷新

This commit is contained in:
cruldra committed 2026-09-27 22:08:16 +08:00
1 parent ebf228cdc7
commit ecc415d763
30 files changed
+1033 -157

No files matched your search

+11 -2
View File
@@ -8,9 +8,10 @@ import { AskThread } from './AskThread'
import { BlockTools } from './BlockTools'
import { CodeEditor } from './CodeEditor'
import { KindIcon } from './kindIcons'
import { PropertyGrid } from './PropertyGrid'
import { PropertyGrid, PropertyTable } from './PropertyGrid'
import { asksOf, historyOf } from './qa'
import { TextPreview } from './TextPreview'
import { translationTableId } from './viewState'
export interface BlockTreeState {
version: number
@@ -112,13 +113,21 @@ function BlockQa({ anchor, qa }: { anchor: string, qa: QaTree }): ReactElement {
)
}
/** 预览状态的内容:函数、类、枚举、导入、常量、变量块和库规则的卡片是属性表,其余是一行译文,带说明的译文下面接着说明。 */
/**
* 预览状态的内容:函数、类、枚举、导入、常量、变量块和库规则的卡片是属性表,其余是一行译文;
* 译文下面依次接着摊开实参的表(跨几行写的调用)、说明。
*/
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} />
return (
<>
<TextPreview text={block.translation} />
{block.table && (
<div className="mt-[3px]">
<PropertyTable parentId={translationTableId(block.id)} columns={block.table.columns} items={block.table.items} />
</div>
)}
{block.doc && <TextPreview text={block.doc} className="mt-0.5" />}
</>
)
@@ -96,9 +96,9 @@ function PropertyItems({ parentId, items, folding }: { parentId: string, items:
/**
* 给了列名的子行(输入参数、数据表的字段)排成表格:第一行是表头(列名),下面每个子行一行;外框圆角,格子之间、行之间一条分隔线。
* 列宽按整列的内容定(见 tableTemplate),最后一列分剩下的,长了在格子里换行。
* 列宽按整列的内容定(见 tableTemplate),最后一列分剩下的,长了在格子里换行。一行译文下面摊开实参的表也用它。
*/
function PropertyTable({ parentId, columns, items }: { parentId: string, columns: string[], items: PropertyItem[] }): ReactElement {
export function PropertyTable({ parentId, columns, items }: { parentId: string, columns: string[], items: PropertyItem[] }): ReactElement {
return (
<div className="pl-[5px]">
<div className="cr-table" role="table" style={{ gridTemplateColumns: tableTemplate(columns.length) }}>
@@ -95,6 +95,16 @@ describe('跳到定义:滚到哪块、展开哪些', () => {
expect(revealPlan(BLOCKS, 4, 102)).toEqual({ id: '1.0.0', expand: ['1', '1.0'] })
})
it('名字在一行译文下面那张表里(跨几行写的调用的实参):表总是展开的,目标是那块,不用展开什么', () => {
const call: BlockView = {
...textBlock('0.0', 'return', 1, [word('返回'), word('新建'), name('UserDetailResponse', 10)]),
table: { columns: ['参数', '值'], items: [{ cells: [[name('id', 40)], [name('user', 43), { text: '.', role: 'plain' }, name('id', 48)]] }] },
}
const blocks = [textBlock('0', 'if', 0, [word('如果'), name('user', 3)], [call])]
expect(revealPlan(blocks, 9, 48)).toEqual({ id: '0.0', expand: ['0'] })
expect(occurrencePlan(blocks, { start: 40, end: 42, kind: 'read' }, () => false)).toEqual({ id: '0.0', expand: ['0'] })
})
it('名字在框里(套了几层都算)也是显示着它', () => {
const inner = { style: 'iteration' as const, label: '列表', segments: [word('遍历'), name('row', 30), word('取'), name('y', 40)] }
const blocks: BlockView[] = [
+10 -5
View File
@@ -1,4 +1,4 @@
import type { BlockView, Occurrence, PreviewText, PropertyItem, SourceRange } from './types'
import type { BlockView, Occurrence, PreviewTable, PreviewText, PropertyItem, SourceRange } from './types'
import { blockPath } from './filter'
import { showsOccurrence } from './occurrences'
import { showsOffset } from './segments'
@@ -38,19 +38,24 @@ function shows(text: PreviewText, offset: number): boolean {
return !('markdown' in text) && showsOffset(text, offset)
}
/** 一行译文下面那张表(总是展开的)里有格子满足 test。 */
function tableShows(table: PreviewTable | undefined, test: (cell: PreviewText) => boolean): boolean {
return table?.items.some(item => item.cells.some(test)) ?? false
}
/**
* 块里哪儿是 offset 处的定义,从具体到笼统:
* ① 块自己的名字(函数名、类名、只声明一个变量时的变量名)→ 整块;
* ② 属性表里讲这个定义的一行 / 子行(defines 盖住 offset:参数、导入项、多变量声明里的一个、对象一项的键)→ 只闪它,
* 子行连它上面的各层(所在的行、嵌套时外层的子行)一起展开;
* ③ 块里只是显示着这个名字(一行译文里的循环变量、没填 defines 的翻译插件)→ 整块,名字在子行里时展开它上面的各层。
* ③ 块里只是显示着这个名字(一行译文和它下面的表里的名字、没填 defines 的翻译插件)→ 整块,名字在子行里时展开它上面的各层。
* 不在这块里是 undefined。
*/
function locate(block: BlockView, offset: number): Spot | undefined {
if (covers(block.defines, offset))
return { expand: [] }
if ('translation' in block)
return shows(block.translation, offset) ? { expand: [] } : undefined
return shows(block.translation, offset) || tableShows(block.table, cell => shows(cell, offset)) ? { expand: [] } : undefined
const rows = block.properties.map((row, index) => ({ row, id: propertyRowId(block.id, index) }))
for (const { row, id } of rows) {
if (covers(row.defines, offset))
@@ -120,10 +125,10 @@ export function uncoveredPlan(plan: RevealPlan, covered: ReadonlyMap<string, str
return owner === undefined ? plan : { id: owner, expand: blockPath(owner).slice(0, -1) }
}
/** 块里哪儿显示着满足 test 的文字(译文、属性行的值、各层子行的格子):要展开的属性行和子行;不在这块里是 undefined。 */
/** 块里哪儿显示着满足 test 的文字(译文和它下面的表、属性行的值、各层子行的格子):要展开的属性行和子行;不在这块里是 undefined。 */
function showingSpot(block: BlockView, test: (text: PreviewText) => boolean): string[] | undefined {
if ('translation' in block)
return test(block.translation) ? [] : undefined
return test(block.translation) || tableShows(block.table, test) ? [] : undefined
for (const [index, row] of block.properties.entries()) {
if (test(row.value))
return []
+8 -2
View File
@@ -71,6 +71,12 @@ export interface PropertyRow extends Defines {
columns?: string[]
}
/** 一张带表头和边框的表:列名,每行几列对齐的格子,同 PropertyRow 给了 columns 的子行 */
export interface PreviewTable {
columns: string[]
items: PropertyItem[]
}
/** 一种颜色在暗色、亮色主题下各用哪个(CSS 颜色值);高对比主题跟着暗 / 亮走 */
export interface ThemeColor { dark: string, light: string }
@@ -108,9 +114,9 @@ interface BlockViewBase {
/**
* 函数、类、枚举、导入、常量、变量块和库规则的卡片预览时是属性表,注释块是 Markdown 说明,其余是一行译文;
* 一行译文的块带说明时 doc 是说明的 Markdown 原文,排在译文下面
* 一行译文下面依次是:跨几行写的调用摊开各个实参的表(table),块的说明(doc,Markdown 原文)
*/
export type BlockView = BlockViewBase & ({ translation: PreviewText, doc?: Markdown } | { properties: PropertyRow[] })
export type BlockView = BlockViewBase & ({ translation: PreviewText, table?: PreviewTable, doc?: Markdown } | { properties: PropertyRow[] })
export interface TranslatorOption { id: string, label: string }
@@ -90,3 +90,8 @@ export function propertyRowId(blockId: string, rowIndex: number): string {
export function propertyItemId(parentId: string, itemIndex: number): string {
return `${parentId}/${itemIndex}`
}
/** 一行译文下面那张表(跨几行写的调用的实参)的 id:表里各行的 id 是 propertyItemId(它, 行号)。这张表总是展开的。 */
export function translationTableId(blockId: string): string {
return `${blockId}/t`
}