Initial Dever 0.0.1

This commit is contained in:
Codex committed 2026-11-03 03:32:07 +00:00
commit 81233d098c
1479 files changed
+163782

No files matched your search

+103
View File
@@ -0,0 +1,103 @@
const vscode = require('vscode');
const { createInspection, range, uri } = require('./inspection.cjs');
const { at, relations } = require('./graph.cjs');
const { registerReading } = require('./reading.cjs');
const { registerHover } = require('./hover.cjs');
function registerNavigation(context) {
const inspection = createInspection(context);
const selector = [
{ language: 'dever', scheme: 'file' },
{ language: 'dever', scheme: 'dever-source' }
];
async function item(index, symbol, root) {
const first = symbol.declarations[0];
if (!first) return undefined;
await inspection.verify(index, first.file, root);
const end = symbol.declarations.at(-1).end;
const span = range({ start: first.start, end });
const selected = new vscode.Range(span.start, span.start);
const value = new vscode.CallHierarchyItem(vscode.SymbolKind.Function, symbol.name, symbol.kind,
uri(index, first.file, root), span, selected);
return value;
}
async function lookup(document, position) {
const state = await inspection.current(document);
return state ? { ...state, symbols: at(state.index, state.file, position) } : undefined;
}
context.subscriptions.push(vscode.languages.registerDefinitionProvider(selector, {
async provideDefinition(document, position) {
const state = await lookup(document, position);
if (!state) return [];
return Promise.all(state.symbols.flatMap(symbol => symbol.declarations)
.map(site => inspection.location(state.index, site, state.root)));
}
}));
context.subscriptions.push(vscode.languages.registerReferenceProvider(selector, {
async provideReferences(document, position, options) {
const state = await lookup(document, position);
if (!state) return [];
const ids = new Set(state.symbols.map(symbol => symbol.id));
const sites = state.index.calls.filter(call => ids.has(call.callee)).map(call => call.site);
if (options.includeDeclaration) sites.push(...state.symbols.flatMap(symbol => symbol.declarations));
const unique = [...new Map(sites.map(site => [JSON.stringify(site), site])).values()];
return Promise.all(unique.map(site => inspection.location(state.index, site, state.root)));
}
}));
async function hierarchy(value, incoming) {
const document = await vscode.workspace.openTextDocument(value.uri);
const state = await inspection.current(document);
if (!state) throw new Error('请保存源码后重新打开调用层级。');
const { root, index, file } = state;
const start = value.selectionRange.start;
const symbol = index.symbols.find(symbol => symbol.name === value.name && symbol.declarations.some(site =>
site.file === file && site.start.line === start.line && site.start.character === start.character));
if (!symbol) throw new Error('函数位置已变化,请重新打开调用层级。');
await inspection.verify(index, symbol.declarations[0].file, root);
const result = [];
for (const relation of relations(index, symbol.id, incoming)) {
const target = await item(index, relation.symbol, root);
if (!target) continue;
for (const call of relation.calls) await inspection.verify(index, call.site.file, root);
const ranges = relation.calls.map(call => range(call.site));
result.push(incoming ? new vscode.CallHierarchyIncomingCall(target, ranges)
: new vscode.CallHierarchyOutgoingCall(target, ranges));
}
return result;
}
context.subscriptions.push(vscode.languages.registerCallHierarchyProvider(selector, {
async prepareCallHierarchy(document, position) {
const state = await lookup(document, position);
if (!state) return [];
return (await Promise.all(state.symbols.map(symbol => item(state.index, symbol, state.root)))).filter(Boolean);
},
provideCallHierarchyIncomingCalls(value) { return hierarchy(value, true); },
provideCallHierarchyOutgoingCalls(value) { return hierarchy(value, false); }
}));
context.subscriptions.push(vscode.languages.registerCodeLensProvider(selector, {
onDidChangeCodeLenses: inspection.changed.event,
async provideCodeLenses(document) {
const state = await inspection.current(document);
if (!state) return [];
return state.index.symbols.filter(symbol => symbol.kind !== 'generated'
&& symbol.declarations[0]?.file === state.file).map(symbol => {
const incoming = relations(state.index, symbol.id, true);
const count = incoming.reduce((total, relation) => total + relation.calls.length, 0);
const start = range(symbol.declarations[0]).start;
return new vscode.CodeLens(new vscode.Range(start, start), {
title: `${incoming.length} 个调用方 · ${count} 处调用 · 查看调用关系`,
command: 'dever.showCalls', arguments: [state.root, symbol.name]
});
});
}
}));
registerReading(context, inspection, lookup);
registerHover(context, selector, inspection, lookup);
}
module.exports = { registerNavigation };