✨ feat(vscode): 代码阅读函数块默认折叠,函数说明进属性表「说明」行
This commit is contained in:
1 parent
62f48fe67c
commit
9b32d4b5a8
17 files changed
+489
-100
No files matched your search
@@ -1,17 +1,20 @@
|
||||
import type { ScrollAnchor } from './scrollPosition'
|
||||
import type { BlockKind, BlockView } from './types'
|
||||
|
||||
/**
|
||||
* 标签页切走时 VS Code 会销毁 webview、切回来重新加载,靠它恢复:哪些块停在「编辑」、
|
||||
* 哪些块和属性行折叠了(块 id 是它在树里的位置,文档刷新后照旧对得上;属性行 id 见 propertyRowId),以及滚到了哪。
|
||||
* 用户把哪些块和属性行折叠 / 展开了(块 id 是它在树里的位置,文档刷新后照旧对得上;属性行 id 见 propertyRowId),以及滚到了哪。
|
||||
*/
|
||||
export interface ViewState {
|
||||
editing: string[]
|
||||
collapsed: string[]
|
||||
/** 用户自己点过折叠箭头的块和属性行:id → 折叠着没有。没点过的按默认,见 collapsedIds */
|
||||
folds: Record<string, boolean>
|
||||
scroll?: ScrollAnchor
|
||||
}
|
||||
|
||||
export interface ViewStateStorage {
|
||||
getState: () => ViewState | undefined
|
||||
/** 存下来的东西可能是旧版本的形状,读的时候逐项核对 */
|
||||
getState: () => unknown
|
||||
setState: (state: ViewState) => void
|
||||
}
|
||||
|
||||
@@ -23,7 +26,7 @@ export interface ViewStateStore {
|
||||
|
||||
/** 一个 webview 只有一份状态:块的状态和滚动位置由不同地方各自更新,存的时候合在一起。 */
|
||||
export function createViewStateStore(storage: ViewStateStorage): ViewStateStore {
|
||||
let current: ViewState = storage.getState() ?? { editing: [], collapsed: [] }
|
||||
let current = readViewState(storage.getState())
|
||||
return {
|
||||
get: () => current,
|
||||
update: (patch) => {
|
||||
@@ -33,8 +36,45 @@ export function createViewStateStore(storage: ViewStateStorage): ViewStateStore
|
||||
}
|
||||
}
|
||||
|
||||
function isRecord(value: unknown): value is Record<string, unknown> {
|
||||
return typeof value === 'object' && value !== null && !Array.isArray(value)
|
||||
}
|
||||
|
||||
function isScrollAnchor(value: unknown): value is ScrollAnchor {
|
||||
return isRecord(value) && [value.line, value.offset, value.scrollTop].every(field => typeof field === 'number')
|
||||
}
|
||||
|
||||
/** 存下来的状态逐项核对,形状不对的项(包括旧版本存的)当没存过。 */
|
||||
function readViewState(saved: unknown): ViewState {
|
||||
const state = isRecord(saved) ? saved : {}
|
||||
const editing = Array.isArray(state.editing) ? state.editing.filter((id): id is string => typeof id === 'string') : []
|
||||
const folds = isRecord(state.folds)
|
||||
? Object.fromEntries(Object.entries(state.folds).filter((entry): entry is [string, boolean] => typeof entry[1] === 'boolean'))
|
||||
: {}
|
||||
return isScrollAnchor(state.scroll) ? { editing, folds, scroll: state.scroll } : { editing, folds }
|
||||
}
|
||||
|
||||
/** 块默认折叠吗:函数块收起主体(属性表照常显示),其余块展开。属性行默认都展开。 */
|
||||
export function foldedByDefault(kind: BlockKind): boolean {
|
||||
return kind === 'function'
|
||||
}
|
||||
|
||||
/** 眼下折叠着的块和属性行:用户点过的按他点的,没点过的按 foldedByDefault。 */
|
||||
export function collapsedIds(blocks: readonly BlockView[], folds: Readonly<Record<string, boolean>>): Set<string> {
|
||||
const collapsed = new Set(Object.keys(folds).filter(id => folds[id]))
|
||||
const visit = (list: readonly BlockView[]): void => {
|
||||
for (const block of list) {
|
||||
if (folds[block.id] === undefined && foldedByDefault(block.kind))
|
||||
collapsed.add(block.id)
|
||||
visit(block.children)
|
||||
}
|
||||
}
|
||||
visit(blocks)
|
||||
return collapsed
|
||||
}
|
||||
|
||||
/**
|
||||
* 属性表里带子行的那一行(输入参数、导入项)的折叠 id,和块 id 放在同一个 collapsed 里:
|
||||
* 属性表里带子行的那一行(输入参数、导入项)的折叠 id,和块 id 放在同一份 folds 里:
|
||||
* `<块 id>/p<行序号>`,例如 '6.1.0/p3'。块 id 只由数字和点组成,带 '/' 的不会和任何块 id 撞上。
|
||||
*/
|
||||
export function propertyRowId(blockId: string, rowIndex: number): string {
|
||||
|
||||
Reference in new issue
Block a user