✨ feat(vscode): 代码阅读把推导式换成按读的顺序重排的遍历小框

This commit is contained in:
cruldra committed 2026-09-26 16:15:09 +08:00
1 parent 677fb7da1f
commit 6416cdf714
16 files changed
+641 -91

No files matched your search

+49 -1
View File
@@ -1,4 +1,4 @@
import type { Access, BlockShape, ClassFacts, CodeBlock, EntryFacts, FunctionFacts, ImportFacts, ImportItem, LanguageAdapter, Node, ParameterFacts, TextKind, TokenRole } from '../contract'
import type { Access, BlockShape, ClassFacts, CodeBlock, EntryFacts, FunctionFacts, ImportFacts, ImportItem, IterationClause, IterationFacts, IterationResult, LanguageAdapter, Node, ParameterFacts, TextKind, TokenRole } from '../contract'
import type { CommentRules } from './shared'
import * as path from 'node:path'
import { children, compoundShape, leafBlock, leafShape, listBlocks, named, sameNode, syntaxChildren } from './shared'
@@ -258,6 +258,54 @@ function dictionaryEntries(value: Node | null): EntryFacts[] | undefined {
})
}
const ITERATION_RESULTS: Record<string, IterationResult> = {
generator_expression: 'generator',
list_comprehension: 'list',
set_comprehension: 'set',
dictionary_comprehension: 'dict',
}
/**
* 推导式、生成器表达式的结构,别的节点没有。几种读不成遍历的写法也没有,照常翻:
* `for x in a, b`(语法树认、Python 3 不认的多个来源),以及缺了变量、来源、条件或每一项的值(写到一半的代码)。
*/
export function pythonIteration(node: Node): IterationFacts | undefined {
const result = ITERATION_RESULTS[node.type]
const body = node.childForFieldName('body')
if (!result || !body)
return undefined
const clauses: IterationClause[] = []
for (const child of syntaxChildren(node)) {
if (child.type === 'for_in_clause') {
const variables = child.childForFieldName('left')
const sources = child.childrenForFieldName('right').filter(source => source !== null)
if (!variables || sources.length !== 1)
return undefined
clauses.push({ kind: 'for', variables, source: sources[0], async: child.children.some(token => token?.type === 'async') })
}
else if (child.type === 'if_clause') {
const [condition] = syntaxChildren(child)
if (!condition)
return undefined
clauses.push({ kind: 'if', condition })
}
}
if (clauses[0]?.kind !== 'for')
return undefined
const key = result === 'dict' ? body.childForFieldName('key') : undefined
const value = result === 'dict' ? body.childForFieldName('value') : body
if (!value || key === null)
return undefined
const facts: IterationFacts = { result, clauses, value, ...(key && { key }) }
// 调用唯一的参数是生成器表达式时只写一对括号(f(x for x in y)),语法树把这对括号算给生成器
const call = node.parent
const open = node.child(0)
const close = node.child(node.childCount - 1)
if (result === 'generator' && call?.type === 'call' && sameNode(call.childForFieldName('arguments'), node) && open && close)
facts.sharedParentheses = { open, close }
return facts
}
/** elif / else 展平成紧跟 if 的兄弟块。 */
function ifBlocks(node: Node): CodeBlock[] {
const blocks = [bodyBlock('if', node, bodyOf(node), 'other')]