('browserPath') || platformDefaultBrowerPath;
if (!fs.existsSync(browserPath)) {
- vscode.window.showErrorMessage("Path " + browserPath + " is not a valid browser path!");
+ const res = await vscode.window.showErrorMessage(
+ t('error.not-valid-browser', browserPath),
+ { title: t('info.config-browser-path'), value: true }
+ );
+
+ if (res?.value) {
+ await vscode.commands.executeCommand('workbench.action.openSettings', 'digital-ide.function.doc.pdf.browserPath');
+ }
return;
}
const browser = await puppeteer.launch({
@@ -48,7 +57,7 @@ async function htmlFile2PdfFile(htmlPath: AbsPath, pdfPath: AbsPath) {
scale: pdfConfig.scale,
displayHeaderFooter: pdfConfig.displayHeaderFooter,
headerTemplate: pdfConfig.headerTemplate,
- footerTemplate: pdfConfig.footerTemplate,
+ footerTemplate: `CodeDoc - Powered By Digital IDE
`,
printBackground: pdfConfig.printBackground,
landscape: pdfConfig.landscape,
format: pdfConfig.format,
@@ -74,7 +83,8 @@ async function exportCurrentFileDocAsPDF(uri: vscode.Uri) {
return vscode.window.withProgress({
location: vscode.ProgressLocation.Notification,
- title: '[Digital-IDE]: Export ' + currentFilePath + '...'
+ title: t('info.pdf.exporting', currentFilePath),
+ cancellable: true
}, async progress => {
try {
const html = await makeShowHTML(uri, "pdf");
@@ -102,15 +112,18 @@ async function exportCurrentFileDocAsPDF(uri: vscode.Uri) {
fs.writeFileSync(tempHtmlPath, html);
await htmlFile2PdfFile(tempHtmlPath, pdfPath);
- hdlFile.rmSync(tempHtmlPath);
+ // hdlFile.rmSync(tempHtmlPath);
// 在当前编辑器中打开生成的 pdf
- vscode.window.showInformationMessage('pdf generated at ' + pdfPath);
+ if (fs.existsSync(pdfPath)) {
+ vscode.window.showInformationMessage(t('info.generate-pdf-to', pdfFolderPath));
+ }
} catch (error) {
MainOutput.report("error happen in export pdf: " + error, {
level: ReportType.Error
});
+ return;
}
});
}
diff --git a/src/function/dide-netlist/api.ts b/src/function/dide-netlist/api.ts
index 46ba9df..d0817d5 100644
--- a/src/function/dide-netlist/api.ts
+++ b/src/function/dide-netlist/api.ts
@@ -170,7 +170,7 @@ async function html2pdf(htmlPath: string, pdfPath: string, moduleName: string, w
scale: 1,
displayHeaderFooter: true,
// headerTemplate: `module ${moduleName}
`,
- footerTemplate: `Netlist for ${moduleName}
- 由 Digital IDE 生成
`,
+ footerTemplate: `Netlist for ${moduleName}
- Powered By Digital IDE
`,
printBackground: true,
landscape: true,
width: width
diff --git a/src/function/dide-netlist/index.ts b/src/function/dide-netlist/index.ts
index bf3d2dc..661ecfc 100644
--- a/src/function/dide-netlist/index.ts
+++ b/src/function/dide-netlist/index.ts
@@ -20,7 +20,6 @@ interface SimpleOpe {
extensionPath: string
}
-const workerScriptPath = hdlPath.join(__dirname, 'worker.js');
class NetlistRender {
panel?: vscode.WebviewPanel;
@@ -177,6 +176,7 @@ function checkResource() {
export async function openNetlistViewer(context: vscode.ExtensionContext, uri: vscode.Uri, moduleName: string) {
checkResource();
+ const workerScriptPath = hdlPath.join(opeParam.extensionPath, 'out', 'function', 'dide-netlist', 'worker.js');
const worker = new Worker(workerScriptPath);
let success = true;
@@ -245,6 +245,7 @@ async function showErrorLogFile(data: any) {
export async function runYsScript(context: vscode.ExtensionContext, uri: vscode.Uri) {
checkResource();
+ const workerScriptPath = hdlPath.join(opeParam.extensionPath, 'out', 'function', 'dide-netlist', 'worker.js');
const worker = new Worker(workerScriptPath);
worker.on('message', message => {
diff --git a/src/function/dide-netlist/worker.ts b/src/function/dide-netlist/worker.ts
index 90c6ddf..9a439fd 100644
--- a/src/function/dide-netlist/worker.ts
+++ b/src/function/dide-netlist/worker.ts
@@ -311,6 +311,7 @@ class Netlist {
wasi_snapshot_preview1: wasi.wasiImport
});
+
try {
const exitCode = wasi.start(instance);
} catch (error) {
diff --git a/src/function/index.ts b/src/function/index.ts
index 0ba61db..ec70de7 100644
--- a/src/function/index.ts
+++ b/src/function/index.ts
@@ -16,7 +16,7 @@ import * as FSM from './fsm';
import * as Netlist from './dide-netlist';
import * as WaveView from './dide-viewer';
import { ModuleDataItem } from './treeView/tree';
-import { downloadLsp } from './lsp-client';
+import { downloadLsp, installLsp } from './lsp-client';
import { hdlPath } from '../hdlFs';
function registerDocumentation(context: vscode.ExtensionContext) {
@@ -101,6 +101,13 @@ function registerLsp(context: vscode.ExtensionContext, version: string) {
downloadLsp(context, version, versionFolderPath)
});
+ vscode.commands.registerCommand('digital-ide.digital-lsp.install', () => {
+ const versionFolderPath = context.asAbsolutePath(
+ path.join('resources', 'dide-lsp', 'server', version)
+ );
+ installLsp(context, version, versionFolderPath);
+ });
+
const vlogSelector: vscode.DocumentSelector = {scheme: 'file', language: 'verilog'};
const svlogSelector: vscode.DocumentSelector = {scheme: 'file', language: 'systemverilog'};
const vhdlSelector: vscode.DocumentSelector = {scheme: 'file', language: 'vhdl'};
diff --git a/src/function/lsp-client/cdn.ts b/src/function/lsp-client/cdn.ts
index a5bfe15..b35c8c5 100644
--- a/src/function/lsp-client/cdn.ts
+++ b/src/function/lsp-client/cdn.ts
@@ -1,16 +1,21 @@
import axios from 'axios';
import { performance } from 'perf_hooks';
+export function getLspFileName(version: string, signature: string) {
+ return `digital-lsp_${version}_${signature}.tar.gz`;
+}
// const link1 = 'https://gitee.com/Digital-IDE/Digital-IDE/releases/download/0.4.0/digital-lsp_0.4.0_darwin_aarch64.tar.gz';
// const link2 = 'https://github.com/Digital-EDA/Digital-IDE/releases/download/0.4.0/digital-lsp_0.4.0_darwin_aarch64.tar.gz';
export function getGithubDownloadLink(signature: string, version: string): string {
- return `https://github.com/Digital-EDA/Digital-IDE/releases/download/${version}/digital-lsp_${version}_${signature}.tar.gz`;
+ const filename = getLspFileName(version, signature);
+ return `https://github.com/Digital-EDA/Digital-IDE/releases/download/${version}/${filename}`;
}
export function getGiteeDownloadLink(signature: string, version: string): string {
- return `https://gitee.com/Digital-IDE/Digital-IDE/releases/download/${version}/digital-lsp_${version}_${signature}.tar.gz`;
+ const filename = getLspFileName(version, signature);
+ return `https://gitee.com/Digital-IDE/Digital-IDE/releases/download/${version}/${filename}`;
}
function measureRequestTimecost(url: string, timeout: number = 5): Promise {
diff --git a/src/function/lsp-client/index.ts b/src/function/lsp-client/index.ts
index 30f7812..4f1e314 100644
--- a/src/function/lsp-client/index.ts
+++ b/src/function/lsp-client/index.ts
@@ -13,7 +13,7 @@ import * as tar from 'tar';
import { platform } from "os";
import { IProgress, LspClient, opeParam } from '../../global';
import axios, { AxiosResponse } from "axios";
-import { chooseBestDownloadSource } from "./cdn";
+import { chooseBestDownloadSource, getLspFileName } from "./cdn";
import { hdlDir, hdlPath } from "../../hdlFs";
import { registerConfigurationUpdater, registerLinter } from "./config";
import { t } from "../../i18n";
@@ -115,7 +115,7 @@ export async function downloadLsp(context: vscode.ExtensionContext, version: str
console.log('choose download link: ' + downloadLink);
clearInterval(intervalHandler);
- return downloadLink
+ return downloadLink;
});
const tarGzFilePath = await vscode.window.withProgress({
@@ -142,6 +142,48 @@ export async function downloadLsp(context: vscode.ExtensionContext, version: str
return false;
}
+
+export async function installLsp(context: vscode.ExtensionContext, version: string, versionFolderPath: string): Promise {
+
+ const uri = await vscode.window.showOpenDialog({
+ title: t('info.choose.digital-lsp-targz'),
+ canSelectFiles: true,
+ canSelectFolders: false,
+ canSelectMany: false,
+ filters: {
+ [t('info.digital-lsp.targz')]: ['tar.gz'],
+ [t('info.vcd-viewer.all-file')]: ['*']
+ }
+ });
+
+ if (!uri) {
+ return false;
+ }
+
+ const tarGzFilePath = uri[0].fsPath;
+ const filename = path.basename(tarGzFilePath);
+ const signature = getPlatformPlatformSignature().toString();
+ const expectFilename = getLspFileName(version, signature);
+ if (expectFilename !== filename) {
+ vscode.window.showErrorMessage(t('error.digital-lsp.incorrect-filename', filename, expectFilename));
+ return false;
+ }
+
+ await vscode.window.withProgress({
+ location: vscode.ProgressLocation.Notification,
+ title: t('info.progress.extract-digital-lsp')
+ }, async (progress: vscode.Progress, token: vscode.CancellationToken) => {
+ if (fs.existsSync(tarGzFilePath)) {
+ console.log('check finish, begin to extract');
+ await extractTarGz(tarGzFilePath, versionFolderPath);
+ } else {
+ vscode.window.showErrorMessage(t('error.lsp.download-digital-lsp') + version);
+ }
+ });
+
+ return false;
+}
+
export async function activate(context: vscode.ExtensionContext, packageJson: any) {
const version = packageJson.version;
await checkAndDownload(context, version);
diff --git a/src/manager/PL/xilinx.ts b/src/manager/PL/xilinx.ts
index 0b792b9..a75e68f 100644
--- a/src/manager/PL/xilinx.ts
+++ b/src/manager/PL/xilinx.ts
@@ -444,6 +444,10 @@ class XilinxOperation {
* @param context
*/
public refresh(context: PLContext) {
+ vscode.window.showInformationMessage(
+ "Xilinx: Refresh",
+ { title: 'ok', value: true }
+ );
const cmd = this.getRefreshXprDesignSourceCommand();
context.process?.stdin.write(cmd + '\n');
}
@@ -477,6 +481,11 @@ class XilinxOperation {
}
public simulateGui(context: PLContext) {
+ vscode.window.showInformationMessage(
+ "Xilinx: Simulate GUI",
+ { title: 'ok', value: true }
+ );
+
const scriptPath = `${this.xilinxPath}/simulate.tcl`;
const script = `
@@ -508,6 +517,11 @@ file delete ${scriptPath} -force\n`;
}
public simulateCli(context: PLContext) {
+ vscode.window.showInformationMessage(
+ "Xilinx: Simulate CLI",
+ { title: 'ok', value: true }
+ );
+
const scriptPath = hdlPath.join(this.xilinxPath, 'simulate.tcl');
const script = `
if {[current_sim] != ""} {
@@ -536,6 +550,11 @@ file delete ${scriptPath} -force\n`;
}
public synth(context: PLContext) {
+ vscode.window.showInformationMessage(
+ "Xilinx: Synth",
+ { title: 'ok', value: true }
+ );
+
let quietArg = '';
if (opeParam.prjInfo.enableShowLog) {
quietArg = '-quiet';
@@ -550,6 +569,11 @@ file delete ${scriptPath} -force\n`;
}
impl(context: PLContext) {
+ vscode.window.showInformationMessage(
+ "Xilinx: Impl",
+ { title: 'ok', value: true }
+ );
+
let quietArg = '';
if (opeParam.prjInfo.enableShowLog) {
quietArg = '-quiet';
@@ -566,6 +590,10 @@ file delete ${scriptPath} -force\n`;
}
build(context: PLContext) {
+ vscode.window.showInformationMessage(
+ "Xilinx: Build",
+ { title: 'ok', value: true }
+ );
let quietArg = '';
if (this.prjConfig.enableShowLog) {
quietArg = '-quiet';
@@ -595,6 +623,11 @@ file delete ${scriptPath} -force\n`;
generateBit(context: PLContext) {
+ vscode.window.showInformationMessage(
+ "Xilinx: BitStream",
+ { title: 'ok', value: true }
+ );
+
let scripts: string[] = [];
let core = this.prjConfig.soc.core;
let sysdefPath = `${this.prjInfo.path}/${this.prjInfo.name}.runs` +
@@ -626,6 +659,11 @@ file delete ${scriptPath} -force\n`;
}
program(context: PLContext) {
+ vscode.window.showInformationMessage(
+ "Xilinx: Program",
+ { title: 'ok', value: true }
+ );
+
let scriptPath = `${this.xilinxPath}/program.tcl`;
let script = `
open_hw -quiet
@@ -672,6 +710,10 @@ file delete ${scriptPath} -force\n`;
}
tclProcess.stdin.write('start_gui -quiet\n');
+ vscode.window.showInformationMessage(
+ t('info.vivado-gui.started'),
+ { title: t('ok'), value: true }
+ );
HardwareOutput.report(t('info.pl.gui.report-title'), {
level: ReportType.Info
});
diff --git a/src/manager/prj.ts b/src/manager/prj.ts
index 52aefa7..8bb8e10 100644
--- a/src/manager/prj.ts
+++ b/src/manager/prj.ts
@@ -342,18 +342,53 @@ class PrjManage {
continue;
}
+ const sourcePath = hdlPath.join(workspace, file);
+
if (file.startsWith(plname)) {
const targetFolder = hdlPath.join(workspace, 'prj', 'xilinx');
- const sourcePath = hdlPath.join(workspace, file);
hdlFile.move(sourcePath, targetFolder);
} else {
+ // 排除非 hdl 文件
+ if (hdlFile.isFile(sourcePath) && !hdlFile.isHDLFile(sourcePath)) {
+ continue;
+ }
const targetFolder = hdlPath.join(workspace, 'user', 'src');
- const sourcePath = hdlPath.join(workspace, file);
hdlFile.move(sourcePath, targetFolder);
}
}
}
+ /**
+ * @description 搬移 Xilinx 项目中的 BD
+ *
+ * bd 一般在 ${workspace}/${plname}.srcs/sources_xxx/bd 里面
+ */
+ function transformBD(
+ matchPrefix: string,
+ workspace: string,
+ plname: string
+ ) {
+ const xilinxSrcsPath = hdlPath.join(workspace, plname + '.srcs');
+ const standardBdPath = hdlPath.join(workspace, 'user', 'bd');
+ if (!fs.existsSync(xilinxSrcsPath)) {
+ return;
+ }
+ const sourceNames = fs.readdirSync(xilinxSrcsPath).filter(filename => filename.startsWith(matchPrefix));
+ for (const sn of sourceNames) {
+ const bdPath = hdlPath.join(xilinxSrcsPath, sn, 'bd');
+ if (!hdlFile.isDir(bdPath)) {
+ continue;
+ }
+
+ for (const bdname of fs.readdirSync(bdPath)) {
+ const sourcePath = hdlPath.join(bdPath, bdname);
+ hdlDir.mvdir(sourcePath, standardBdPath, true);
+ }
+ hdlDir.rmdir(bdPath);
+ }
+ }
+
+
/**
* @description 搬移 Xilinx 项目中的 IP
*
@@ -481,11 +516,15 @@ class PrjManage {
// 创建标准项目结构基本文件夹
// xilinx prj
hdlDir.mkdir(hdlPath.join(workspacePath, 'prj', 'xilinx'));
+
// hardware
hdlDir.mkdir(hdlPath.join(workspacePath, 'user', 'src'));
hdlDir.mkdir(hdlPath.join(workspacePath, 'user', 'sim'));
hdlDir.mkdir(hdlPath.join(workspacePath, 'user', 'data'));
hdlDir.mkdir(hdlPath.join(workspacePath, 'user', 'ip'));
+
+ hdlDir.mkdir(hdlPath.join(workspacePath, 'user', 'bd'));
+
// software
hdlDir.mkdir(hdlPath.join(workspacePath, 'user', 'sdk'));
hdlDir.mkdir(hdlPath.join(workspacePath, 'user', 'sdk', 'data'));
@@ -498,6 +537,10 @@ class PrjManage {
transformIP('sources_', workspacePath, plname);
transformIP('sim_', workspacePath, plname);
+ // 迁移 BD
+ transformBD('sources_', workspacePath, plname);
+ transformBD('sim_', workspacePath, plname);
+
// 迁移文件夹 ${workspace}/${plname}.srcs
transformXilinxPL('src', 'sources_', workspacePath, plname);
transformXilinxPL('sim', 'sim_', workspacePath, plname);