Files
superwork/vscode/src/codeReader/editor/documentMessage.ts
T

79 lines
3.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import type { DisplayName, LocalSymbol, RuleContext, SourceDocument } from '../contract'
import type { CodeReaderRegistry } from '../registry'
import type { TreeSitterRuntime } from '../runtime'
import type { DocumentMessage } from './messages'
import { fileAttributes, mergeAttributeNames } from '../attributes'
import { readBlockViews } from '../blockView'
import { commandRuleLookup } from '../commandRules'
import { markEntryBlocks } from '../entries/entryMarks'
import { ruleAttributeNames } from '../libraryRules'
/** 生成预览数据要读的那点文档信息(TextDocument 的子集)。 */
export interface DocumentSnapshot {
languageId: string
version: number
getText: () => string
/** 这份文件是项目写明的入口时,预览里名字对上的块标成入口(见 entries/entryPoints.ts) */
entryNames?: readonly string[]
}
/** 发给预览的文档,和这份源码里起了中文名的定义(扩展端接着找用到它们的各处)、语言插件自己认得出的名字(LocalSymbol)。 */
export interface DocumentRead {
message: DocumentMessage
displayNames: DisplayName[]
symbols: LocalSymbol[]
}
/**
* 当前文档 → 发给预览的 document 消息;语言不支持或解析失败时带 error,blocks 为空。库规则出错不算失败,交给 report 记下;
* 规则查名字的定义时问 lookup(RuleContext.lookup),翻译插件问调用的名字定义成哪种块时问 calleeKind(SourceDocument.calleeKind)。
* 筛选属性和值的名字先取翻译插件的,没给的再取库规则的(LibraryRule.attributeNames)。
* 入口文件里名字对上的块,概念列表的第一个换成入口(markEntryBlocks)。
*/
export async function documentMessage(
document: DocumentSnapshot,
registry: Pick<CodeReaderRegistry, 'languageFor' | 'translatorsFor' | 'selectedTranslator' | 'rulesFor' | 'commandRulesFor'>,
runtime: Pick<TreeSitterRuntime, 'parse'>,
report: (message: string) => void,
lookup?: RuleContext['lookup'],
calleeKind?: SourceDocument['calleeKind'],
): Promise<DocumentRead> {
const { languageId, version } = document
const source = document.getText()
const translator = registry.selectedTranslator(languageId)
const message: DocumentMessage = {
type: 'document',
version,
languageId,
blocks: [],
attributes: [],
translators: registry.translatorsFor(languageId).map(({ id, label }) => ({ id, label })),
translatorId: translator?.id ?? '',
names: [],
}
const adapter = registry.languageFor(languageId)
if (!adapter)
return { message: { ...message, error: `代码阅读还不支持「${languageId}」这种语言` }, displayNames: [], symbols: [] }
try {
const rules = registry.rulesFor(languageId)
const { blocks, displayNames, symbols } = await readBlockViews(runtime, adapter, translator, languageId, source, {
rules: { rules, report, lookup },
calleeKind,
commandRule: commandRuleLookup(registry.commandRulesFor(languageId), report),
embedded: (embeddedId) => {
const embeddedAdapter = registry.languageFor(embeddedId)
return embeddedAdapter && {
adapter: embeddedAdapter,
translator: registry.selectedTranslator(embeddedId),
commandRule: commandRuleLookup(registry.commandRulesFor(embeddedId), report),
}
},
})
const names = mergeAttributeNames([translator?.attributeNames, ...ruleAttributeNames(rules, translator?.displayLanguage, report)])
return { message: { ...message, blocks: markEntryBlocks(blocks, source, document.entryNames ?? []), attributes: fileAttributes(blocks, names) }, displayNames, symbols }
}
catch (err) {
return { message: { ...message, error: err instanceof Error ? err.message : String(err) }, displayNames: [], symbols: [] }
}
}