Initial Dever 0.0.1
This commit is contained in:
commit
81233d098c
1479 files changed
+163782
No files matched your search
@@ -0,0 +1,119 @@
|
||||
const vscode = require('vscode');
|
||||
const path = require('node:path');
|
||||
const { relations } = require('./graph.cjs');
|
||||
const { uri, projectRoot } = require('./inspection.cjs');
|
||||
const { openFlowPreview } = require('./dist/flow-preview.cjs');
|
||||
const { description, command } = require('./hover.cjs');
|
||||
|
||||
function registerReading(context, inspection, lookup) {
|
||||
const changed = new vscode.EventEmitter();
|
||||
const previews = new Map();
|
||||
context.subscriptions.push(changed, inspection.changed.event(() => {
|
||||
for (const uri of previews.values()) changed.fire(uri);
|
||||
}));
|
||||
context.subscriptions.push(vscode.workspace.onDidCloseTextDocument(document => {
|
||||
previews.delete(document.uri.toString());
|
||||
}));
|
||||
const provider = {
|
||||
onDidChange: changed.event,
|
||||
async provideTextDocumentContent(documentUri) {
|
||||
previews.set(documentUri.toString(), documentUri);
|
||||
const { root, name } = JSON.parse(documentUri.query);
|
||||
const index = await inspection.load(root);
|
||||
const symbols = index.symbols.filter(symbol => symbol.name === name);
|
||||
if (!symbols.length) throw new Error(`函数已不存在:${name}`);
|
||||
const lines = [`# ${name}`, '', '静态源码关系;分支可能只执行一部分,任务派发不表示同步执行。', '', index.coverage, ''];
|
||||
if (index.documentation_errors.length) lines.push('**说明校验未通过。** 详见“Dever”输出。', '');
|
||||
function link(site) {
|
||||
const file = index.files[site.file];
|
||||
const target = uri(index, site.file, root).with({ fragment: `L${site.start.line + 1},${site.start.character + 1}` });
|
||||
return `[${file.path}:${site.start.line + 1}](${target.toString()})`;
|
||||
}
|
||||
for (const symbol of symbols) {
|
||||
for (const signature of symbol.signatures) lines.push('```dever', signature, '```', '');
|
||||
const detail = await description(inspection, index, symbol, root);
|
||||
if (detail) lines.push(detail.markdown, '', `[主题说明](${detail.uri.toString()})`, '');
|
||||
for (const site of symbol.declarations) {
|
||||
await inspection.verify(index, site.file, root);
|
||||
lines.push('## 定义', '', link(site), '');
|
||||
}
|
||||
for (const incoming of [true, false]) {
|
||||
lines.push(incoming ? '## 谁调用它' : '## 它调用谁', '');
|
||||
const related = relations(index, symbol.id, incoming);
|
||||
if (!related.length) lines.push('当前已检查源码中没有此类关系。', '');
|
||||
else lines.push('| 函数 | 领域 | 关系 | 调用位置 | 定义 / 上下游 |', '| --- | --- | --- | --- | --- |');
|
||||
for (const relation of related) {
|
||||
for (const call of relation.calls) {
|
||||
await inspection.verify(index, call.site.file, root);
|
||||
const definitions = relation.symbol.declarations.map(link).join('、') || '内建操作';
|
||||
const chain = command('dever.showCalls', [root, relation.symbol.name]);
|
||||
lines.push(`| ${relation.symbol.name} | ${relation.symbol.name.split('.').slice(0, 2).join('.')} | ${call.kind} | ${link(call.site)} | ${definitions} · [上下游](${chain}) |`);
|
||||
}
|
||||
}
|
||||
lines.push('');
|
||||
}
|
||||
}
|
||||
return lines.join('\n');
|
||||
}
|
||||
};
|
||||
context.subscriptions.push(vscode.workspace.registerTextDocumentContentProvider('dever-calls', provider));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('dever.showCalls', async (root, name) => {
|
||||
try {
|
||||
if (!root || !name) {
|
||||
const editor = vscode.window.activeTextEditor;
|
||||
if (!editor) return;
|
||||
const state = await lookup(editor.document, editor.selection.active);
|
||||
if (!state) throw new Error('请先保存源码,再查看调用关系。');
|
||||
if (!state.symbols.length) throw new Error('请把光标放在函数或调用位置。');
|
||||
root = state.root;
|
||||
name = state.symbols[0].name;
|
||||
}
|
||||
const target = vscode.Uri.from({ scheme: 'dever-calls', path: '/calls.md', query: JSON.stringify({ root, name }) });
|
||||
await openFlowPreview(context, target, root, {
|
||||
name,
|
||||
changed: inspection.changed,
|
||||
read: name => provider.provideTextDocumentContent(target.with({ query: JSON.stringify({ root, name }) }))
|
||||
});
|
||||
} catch (error) { vscode.window.showErrorMessage(error.message); }
|
||||
}));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('dever.previewDocumentation', async (root, name) => {
|
||||
try {
|
||||
const document = vscode.window.activeTextEditor?.document;
|
||||
if (!root || !name) {
|
||||
if (!document) return;
|
||||
const state = await lookup(document, vscode.window.activeTextEditor.selection.active);
|
||||
root = state?.root || await projectRoot(document);
|
||||
name = state?.symbols[0]?.name;
|
||||
}
|
||||
const index = await inspection.load(root);
|
||||
const symbol = index.symbols.find(value => value.name === name);
|
||||
const detail = symbol && await description(inspection, index, symbol, root);
|
||||
if (!detail) throw new Error('该符号尚未提供 doc/ 说明。');
|
||||
await vscode.commands.executeCommand('markdown.showPreviewToSide', detail.uri.with({ fragment: `L${detail.line + 1}` }));
|
||||
} catch (error) { vscode.window.showErrorMessage(error.message); }
|
||||
}));
|
||||
context.subscriptions.push(vscode.commands.registerCommand('dever.openDomainLinks', async (root, name) => {
|
||||
try {
|
||||
const document = vscode.window.activeTextEditor?.document;
|
||||
if (!root && !document) return;
|
||||
root ||= await projectRoot(document);
|
||||
const index = await inspection.load(root);
|
||||
const symbol = index.symbols.find(value => value.name === name);
|
||||
const source = symbol?.declarations[0];
|
||||
const filename = source ? index.files[source.file].path : document.uri.fsPath;
|
||||
const relative = path.relative(path.join(root, 'module'), filename).split(path.sep);
|
||||
if (relative.length < 3 || relative[0] === '..') {
|
||||
throw new Error('请在 module/<组件>/<领域>/ 内的源码中执行此命令。');
|
||||
}
|
||||
const target = vscode.Uri.file(path.join(root, 'module', ...relative.slice(0, 2), 'link.md'));
|
||||
await inspection.checkLinks(root);
|
||||
const panel = await openFlowPreview(context, target, root);
|
||||
const changed = inspection.changed.event(() => panel.dispose());
|
||||
panel.onDidDispose(() => changed.dispose());
|
||||
} catch (error) {
|
||||
vscode.window.showErrorMessage(`${error.message} 可在项目根运行 dever inspect . --links 生成索引。`);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
module.exports = { registerReading };
|
||||
Reference in new issue
Block a user