🐛 fix(vscode): Rust 连着写的行注释合成一块注释,和别的语言走同一套拆块
This commit is contained in:
1 parent
51da724e68
commit
2f610e9cb8
11 files changed
+233
-121
No files matched your search
@@ -1,7 +1,8 @@
|
||||
import type { Access, ClassBlock, ClassFacts, CodeBlock, EnumBlock, FunctionBlock, ImplBlock, ImportBlock, ImportItem, LanguageAdapter, ModuleBlock, Node, ParameterFacts, TokenRole, TraitBlock, VariableBlock } from '../contract'
|
||||
import type { Access, ClassFacts, CodeBlock, EnumBlock, FunctionBlock, ImplBlock, ImportBlock, ImportItem, LanguageAdapter, Node, ParameterFacts, TokenRole, TraitBlock } from '../contract'
|
||||
import type { CommentRules } from './shared'
|
||||
import * as path from 'node:path'
|
||||
import { leadingAttributes, visibilityFacts } from '../rules/rustTree'
|
||||
import { compoundShape, extendHeader, headerSpan, leafBlock, leafShape, named } from './shared'
|
||||
import { compoundShape, extendHeader, headerSpan, leafBlock, leafShape, listBlocks, named } from './shared'
|
||||
|
||||
const STORAGE = new Set(['pub', 'async', 'const', 'static', 'mut', 'let'])
|
||||
|
||||
@@ -10,7 +11,7 @@ export function createRustAdapter(wasmDir: string): LanguageAdapter {
|
||||
id: 'rust',
|
||||
languageIds: ['rust'],
|
||||
grammarPath: () => path.join(wasmDir, 'tree-sitter-rust.wasm'),
|
||||
toBlocks: root => topBlocks(named(root)),
|
||||
toBlocks: root => topBlocks(named(root), -1),
|
||||
tokenRole: rustTokenRole,
|
||||
}
|
||||
}
|
||||
@@ -23,37 +24,28 @@ function unwrapExtern(item: Node): Node[] {
|
||||
return body ? named(body).flatMap(unwrapExtern) : []
|
||||
}
|
||||
|
||||
function topBlocks(items: Node[]): CodeBlock[] {
|
||||
const list = items.flatMap(unwrapExtern)
|
||||
const blocks: CodeBlock[] = []
|
||||
let index = 0
|
||||
while (index < list.length) {
|
||||
const item = list[index]
|
||||
if (isDoc(item)) {
|
||||
const docs = [item]
|
||||
let next = index + 1
|
||||
while (next < list.length && isDoc(list[next]) && list[next].startPosition.row <= docs[docs.length - 1].endPosition.row + 1)
|
||||
docs.push(list[next++])
|
||||
while (next < list.length && list[next].type === 'attribute_item')
|
||||
next++
|
||||
const target = list[next]
|
||||
if (target && target.type !== 'line_comment' && target.type !== 'block_comment' && target.type !== 'empty_statement') {
|
||||
blocks.push(withPreamble(itemBlock(target), docs))
|
||||
index = next + 1
|
||||
continue
|
||||
}
|
||||
}
|
||||
if (item.type === 'attribute_item' || item.type === 'empty_statement') {
|
||||
index++
|
||||
continue
|
||||
}
|
||||
if (item.type === 'line_comment' || item.type === 'block_comment')
|
||||
blocks.push(leafBlock('comment', item))
|
||||
else
|
||||
blocks.push(withPreamble(itemBlock(item), []))
|
||||
index++
|
||||
}
|
||||
return blocks
|
||||
/**
|
||||
* `//` 普通注释、讲所在模块的 `//!`、讲下一项的 `///` 各是一种写法,只和同一种连成一块。
|
||||
* `///` 和 `/**` 开头的块注释是外部文档注释,讲紧跟着的那一项(中间可以隔着 `#[…]`)。
|
||||
*/
|
||||
const COMMENTS: CommentRules = {
|
||||
lineStyle: comment => comment.type === 'line_comment' ? `//${docMarker(comment)}` : undefined,
|
||||
isDoc: comment => named(comment).some(child => child.type === 'outer_doc_comment_marker'),
|
||||
documents: new Set(['function', 'class', 'trait', 'impl', 'module', 'enum', 'const', 'variable']),
|
||||
}
|
||||
|
||||
/** 文档注释记号:外部的 `/`(块注释是 `*`)、内部的 `!`;普通注释没有。 */
|
||||
function docMarker(comment: Node): string {
|
||||
return named(comment).find(child => child.type === 'outer_doc_comment_marker' || child.type === 'inner_doc_comment_marker')?.text ?? ''
|
||||
}
|
||||
|
||||
/** 一层的各项(文件顶层、模块身体、impl 身体)→ 块;afterRow 同 listBlocks。`#[…]` 和多出来的空 `;` 不出块。 */
|
||||
function topBlocks(items: Node[], afterRow: number): CodeBlock[] {
|
||||
return listBlocks(items.flatMap(unwrapExtern), afterRow, (item) => {
|
||||
if (item.type === 'attribute_item' || item.type === 'empty_statement')
|
||||
return []
|
||||
return [withAttributes(itemBlock(item))]
|
||||
}, COMMENTS)
|
||||
}
|
||||
|
||||
function itemBlock(item: Node): CodeBlock {
|
||||
@@ -90,7 +82,7 @@ function moduleBlock(node: Node): CodeBlock {
|
||||
const { access, attributes } = visibilityFacts(node)
|
||||
return {
|
||||
kind: 'module',
|
||||
...compoundShape(node, body.startIndex, named(body), items => topBlocks(items)),
|
||||
...compoundShape(node, body.startIndex, named(body), topBlocks),
|
||||
...(attributes && { attributes }),
|
||||
facts: classFacts(node, access),
|
||||
}
|
||||
@@ -112,25 +104,10 @@ function valueBlock(node: Node, kind: 'const' | 'variable'): CodeBlock {
|
||||
}
|
||||
}
|
||||
|
||||
/** 文档注释和写在前面的属性算进头部。文档注释的第一句是说明。 */
|
||||
function withPreamble(block: CodeBlock, docs: Node[]): CodeBlock {
|
||||
const [doc] = docs
|
||||
const attribute = leadingAttributes(block.node)[0]
|
||||
let next = block
|
||||
if (doc && isDocumentedKind(next))
|
||||
next = { ...extendHeader(next, doc), facts: { ...next.facts, doc } } as typeof next
|
||||
const from = doc ?? attribute
|
||||
if (from && next.header.startIndex > from.startIndex)
|
||||
next = extendHeader(next, from)
|
||||
return next
|
||||
}
|
||||
|
||||
function isDocumentedKind(block: CodeBlock): block is FunctionBlock | ClassBlock | TraitBlock | ImplBlock | ModuleBlock | EnumBlock | VariableBlock {
|
||||
return block.kind === 'function' || block.kind === 'class' || block.kind === 'trait' || block.kind === 'impl' || block.kind === 'module' || block.kind === 'enum' || block.kind === 'const' || block.kind === 'variable'
|
||||
}
|
||||
|
||||
function isDoc(node: Node): boolean {
|
||||
return (node.type === 'line_comment' || node.type === 'block_comment') && named(node).some(child => child.type === 'outer_doc_comment_marker')
|
||||
/** 写在前面的 `#[…]` 算进头部。 */
|
||||
function withAttributes(block: CodeBlock): CodeBlock {
|
||||
const [attribute] = leadingAttributes(block.node)
|
||||
return attribute && block.header.startIndex > attribute.startIndex ? extendHeader(block, attribute) : block
|
||||
}
|
||||
|
||||
function useBlock(node: Node): ImportBlock {
|
||||
@@ -224,10 +201,9 @@ function traitBlock(node: Node): TraitBlock {
|
||||
function implBlock(node: Node): ImplBlock {
|
||||
const { access, attributes } = visibilityFacts(node)
|
||||
const body = node.childForFieldName('body')
|
||||
const children = body ? topBlocks(named(body)) : []
|
||||
return {
|
||||
kind: 'impl',
|
||||
...compoundShape(node, body?.startIndex ?? node.endIndex, [], () => children),
|
||||
...compoundShape(node, body?.startIndex ?? node.endIndex, named(body), topBlocks),
|
||||
...(attributes && { attributes }),
|
||||
facts: classFacts(node, access, implType(node)),
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user