184 lines
7.1 KiB
TypeScript

import * as vscode from 'vscode';
import { LanguageClient } from 'vscode-languageclient/node';
import { UpdateConfigurationType } from '../../global/lsp';
import * as Linter from '../lsp/linter/common';
import { HdlLangID } from '../../global/enum';
import * as lspLinter from '../lsp/linter';
interface ConfigItem {
name: string,
value: CommonValue
}
type CommonValue = string | boolean | number;
/**
* @description 注册配置文件变动时发生的操作
* 该操作一定发生在 lsp 启动后。
* @param client
* @param packageJson
*/
export async function registerConfigurationUpdater(client: LanguageClient, packageJson: any) {
// 常规 lsp 相关的配置
const lspConfigures: ConfigItem[] = [];
const properties = packageJson?.contributes?.configuration?.properties;
const dideConfig = vscode.workspace.getConfiguration('digital-ide');
for (const propertyName of Object.keys(properties) || []) {
if (propertyName.includes('function.lsp')) {
const section = propertyName.slice(12);
let value = dideConfig.get<CommonValue>(section, '');
lspConfigures.push({ name: propertyName, value });
}
}
const supportLinters: Linter.SupportLinterName[] = ['iverilog', 'vivado', 'modelsim', 'verible', 'verilator'];
// 初始化,配置参数全部同步到后端
await client.sendRequest(UpdateConfigurationType, {
configs: lspConfigures,
configType: 'lsp'
});
// 初始化,配置全部 linter 到后端
await updateLinterInstallPathConfiguration(
client,
Linter.getLinterConfigurationName(HdlLangID.Verilog)
);
await updateLinterConfiguration(
client,
Linter.getLinterConfigurationName(HdlLangID.Verilog),
Linter.getLinterName(HdlLangID.Verilog)
);
await updateLinterInstallPathConfiguration(
client,
Linter.getLinterConfigurationName(HdlLangID.SystemVerilog)
);
await updateLinterConfiguration(
client,
Linter.getLinterConfigurationName(HdlLangID.SystemVerilog),
Linter.getLinterName(HdlLangID.SystemVerilog)
);
await updateLinterInstallPathConfiguration(
client,
Linter.getLinterConfigurationName(HdlLangID.Vhdl)
);
await updateLinterConfiguration(
client,
Linter.getLinterConfigurationName(HdlLangID.Vhdl),
Linter.getLinterName(HdlLangID.Vhdl)
);
// 监听配置文件的变化,变化时需要做出的行为
vscode.workspace.onDidChangeConfiguration(async event => {
const changeConfigs: ConfigItem[] = [];
const dideConfig = vscode.workspace.getConfiguration('');
for (const config of lspConfigures) {
if (event.affectsConfiguration(config.name)) {
const lastestValue = dideConfig.get<CommonValue>(config.name, '');
changeConfigs.push({ name: config.name, value: lastestValue });
}
}
if (changeConfigs.length > 0) {
await client.sendRequest(UpdateConfigurationType, {
configs: changeConfigs,
configType: 'lsp'
});
}
// 本次更新时,当前各个语言正在使用的诊断器的名字的映射表
// 因为 getLinterName 需要进行一次映射,此处为后续的遍历预缓存一波
const currentLinterConfiguration: Record<HdlLangID, string> = {
[HdlLangID.Verilog]: Linter.getLinterName(HdlLangID.Verilog),
[HdlLangID.SystemVerilog]: Linter.getLinterName(HdlLangID.SystemVerilog),
[HdlLangID.Vhdl]: Linter.getLinterName(HdlLangID.Vhdl),
[HdlLangID.Unknown]: HdlLangID.Unknown
};
const linterManager: Record<HdlLangID, lspLinter.LinterManager> = {
[HdlLangID.Verilog]: lspLinter.vlogLinterManager,
[HdlLangID.SystemVerilog]: lspLinter.svlogLinterManager,
[HdlLangID.Vhdl]: lspLinter.vhdlLinterManager,
[HdlLangID.Unknown]: lspLinter.reserveLinterManager
};
// 需要讨论的可能受到配置文件更新影响 linter 功能的语言列表
const affectsLangIDs = [HdlLangID.Verilog, HdlLangID.SystemVerilog, HdlLangID.Vhdl];
// 对于诊断器路径的修改
for (const linterName of supportLinters) {
const configuratioName = Linter.getLinterInstallConfigurationName(linterName);
if (event.affectsConfiguration(configuratioName)) {
// 查看谁使用了这个诊断器,更新它的基本信息
for (const langID of affectsLangIDs) {
if (linterName === currentLinterConfiguration[langID]) {
const linterConfigurationName = Linter.getLinterConfigurationName(langID);
// 低频操作,随便糟蹋
await updateLinterConfiguration(client, linterConfigurationName, linterName);
// 更新当前诊断器状态
await linterManager[langID].updateCurrentLinterItem();
linterManager[langID].updateStatusBar();
}
}
}
}
});
}
export async function registerLinter(client: LanguageClient) {
// 初始化,配置全部 linter 到 linterManager
lspLinter.vlogLinterManager.start(client);
lspLinter.vhdlLinterManager.start(client);
lspLinter.svlogLinterManager.start(client);
// 对应配置文件的变动需要修改全局的相关变量
vscode.workspace.onDidChangeConfiguration(async event => {
if (event.affectsConfiguration(Linter.getLinterConfigurationName(HdlLangID.Verilog))) {
await lspLinter.vlogLinterManager.updateCurrentLinterItem(client);
lspLinter.vlogLinterManager.updateStatusBar();
}
if (event.affectsConfiguration(Linter.getLinterConfigurationName(HdlLangID.SystemVerilog))) {
await lspLinter.svlogLinterManager.updateCurrentLinterItem(client);
lspLinter.svlogLinterManager.updateStatusBar();
}
if (event.affectsConfiguration(Linter.getLinterConfigurationName(HdlLangID.Vhdl))) {
await lspLinter.vhdlLinterManager.updateCurrentLinterItem(client);
lspLinter.vhdlLinterManager.updateStatusBar();
}
});
}
/**
* @description 更新所有诊断器的路径信息到后端
*/
async function updateLinterInstallPathConfiguration(
client: LanguageClient,
configurationName: string
) {
for (const linterName of Linter.SupportLinters) {
await updateLinterConfiguration(client, configurationName, linterName);
}
}
/**
* @description 更新当前诊断器的所有信息到后端
*/
async function updateLinterConfiguration(
client: LanguageClient,
configurationName: string,
linterName: Linter.SupportLinterName
) {
const linterPath = Linter.getLinterInstallPath(linterName);
await client.sendRequest(UpdateConfigurationType, {
configs: [
{ name: configurationName, value: linterName },
{ name: 'path', value: linterPath }
],
configType: 'linter'
});
}