✨ feat(vscode): 代码阅读函数块默认折叠,函数说明进属性表「说明」行
This commit is contained in:
1 parent
62f48fe67c
commit
9b32d4b5a8
17 files changed
+489
-100
No files matched your search
@@ -1,4 +1,4 @@
|
||||
import type { BlockShape, CodeBlock, Node, SourceSpan, TextKind } from '../contract'
|
||||
import type { BlockShape, CodeBlock, FunctionBlock, Node, SourceSpan, TextKind } from '../contract'
|
||||
|
||||
/** 语言插件共用的建树工具:取子节点、算头部、把一串语句切成块。 */
|
||||
|
||||
@@ -85,9 +85,24 @@ export function compoundShape(outer: Node, bodyStart: number, items: Node[], lis
|
||||
return { node: outer, header, children: list([...between, ...items], header.endRow) }
|
||||
}
|
||||
|
||||
/** 语言怎么认注释。 */
|
||||
export interface CommentRules {
|
||||
/** 行注释:相邻几行合成一块。 */
|
||||
isLine: (comment: Node) => boolean
|
||||
/** 文档注释(JSDoc):紧贴在函数块前面时是这个函数的说明,见 FunctionFacts.doc。 */
|
||||
isDoc: (comment: Node) => boolean
|
||||
}
|
||||
|
||||
/** 函数块带上说明:说明进 facts.doc,头部往上延到它开头。 */
|
||||
function documented(block: FunctionBlock, doc: Node): FunctionBlock {
|
||||
return { ...extendHeader(block, doc), facts: { ...block.facts, doc } }
|
||||
}
|
||||
|
||||
/**
|
||||
* 一串语句 → 块。注释单独成块,相邻行的行注释合成一块;
|
||||
* 和前一条语句(或头部)同一行的注释是行尾注释,跟着那一行显示,不单独成块。
|
||||
* 文档注释和下一条语句之间只有空白、下一条语句是函数块时,它是这个函数的说明,不单独成块;
|
||||
* 中间隔着的装饰器(不出块的语句)不算隔开。
|
||||
* afterRow 是这串语句之前的最后一行(头部结尾行),模块顶层传 -1;
|
||||
* toBlocks 的 first 表示它是这串里第一条非注释语句(Python 认 docstring 用)。
|
||||
*/
|
||||
@@ -95,20 +110,32 @@ export function listBlocks(
|
||||
items: Node[],
|
||||
afterRow: number,
|
||||
toBlocks: (item: Node, first: boolean) => CodeBlock[],
|
||||
isLineComment: (comment: Node) => boolean,
|
||||
comments: CommentRules,
|
||||
): CodeBlock[] {
|
||||
const out: CodeBlock[] = []
|
||||
let lastRow = afterRow
|
||||
let lineRun: CodeBlock | undefined
|
||||
let doc: Node | undefined
|
||||
let first = true
|
||||
for (const item of items) {
|
||||
const flushDoc = (): void => {
|
||||
if (doc)
|
||||
out.push(leafBlock('comment', doc))
|
||||
doc = undefined
|
||||
}
|
||||
items.forEach((item, i) => {
|
||||
if (item.type === 'comment') {
|
||||
if (item.startPosition.row === lastRow)
|
||||
continue
|
||||
const line = isLineComment(item)
|
||||
return
|
||||
flushDoc()
|
||||
const line = comments.isLine(item)
|
||||
const next = items[i + 1]
|
||||
if (line && lineRun && item.startPosition.row === lineRun.header.endRow + 1) {
|
||||
lineRun.header = { ...lineRun.header, endIndex: item.endIndex, endRow: item.endPosition.row }
|
||||
}
|
||||
else if (comments.isDoc(item) && next && next.type !== 'comment' && sameNode(item.nextSibling, next)) {
|
||||
doc = item
|
||||
lineRun = undefined
|
||||
}
|
||||
else {
|
||||
const block = leafBlock('comment', item)
|
||||
out.push(block)
|
||||
@@ -116,12 +143,22 @@ export function listBlocks(
|
||||
}
|
||||
}
|
||||
else {
|
||||
out.push(...toBlocks(item, first))
|
||||
const blocks = toBlocks(item, first)
|
||||
const [head] = blocks
|
||||
if (head?.kind === 'function' && doc) {
|
||||
blocks[0] = documented(head, doc)
|
||||
doc = undefined
|
||||
}
|
||||
else if (head) {
|
||||
flushDoc()
|
||||
}
|
||||
out.push(...blocks)
|
||||
first = false
|
||||
lineRun = undefined
|
||||
}
|
||||
lastRow = item.endPosition.row
|
||||
}
|
||||
})
|
||||
flushDoc()
|
||||
return out
|
||||
}
|
||||
|
||||
|
||||
Reference in new issue
Block a user