293 lines
9.1 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 * as vscode from 'vscode';
import * as fs from 'fs';
import * as fspath from 'path';
import { AbsPath, opeParam, MainOutput, ReportType } from '../../global';
import { hdlParam, HdlModule } from '../../hdlParser/core';
import { HdlModulePort, HdlModuleParam } from '../../hdlParser/common';
import { MarkdownString, RenderString, RenderType,
mergeSortByLine, getWavedromsFromFile, Count, WavedromString } from './common';
import { hdlPath, hdlFile } from '../../hdlFs';
import { getSymbolComments } from '../lsp/util/feature';
import { HdlLangID, ThemeType } from '../../global/enum';
import { makeDiagram } from './diagram';
function makeSVGElementByLink(link: AbsPath, caption?: string) {
let mainHtml;
if (caption) {
mainHtml = `<div align=center><img src="${link}"></img><p class="ImgCaption">${caption}</p></div>`;
} else {
mainHtml = `<div align=center><img src="${link}"></img></div>`;
}
return '<br>' + mainHtml + '<br><br>\n';
}
function selectFieldValue(obj: any, subName: string, ws: string, name: string): string {
if (subName === 'empty') {
return '——';
}
let value = obj[subName];
if (subName === 'instModPath' && value) {
value = value.replace(ws, '');
}
if (value && value.trim().length === 0) {
return '——';
}
// TODO : 1 not known
if (name === 'ports' && value === '1') {
return '——';
}
return value;
}
function makeTableFromObjArray(md: MarkdownString, array: any[], name: string, fieldNames: string[], displayNames: string[]) {
const ws = hdlPath.toSlash(opeParam.workspacePath) + '/';
console.log('enter showhtml');
if (array.length === 0) {
md.addText(`no ${name} info`);
} else {
const rows = [];
for (const obj of array) {
const data = [];
for (const subName of fieldNames) {
const value = selectFieldValue(obj, subName, ws, name);
data.push(value);
}
rows.push(data);
}
if (displayNames) {
md.addTable(displayNames, rows);
} else {
md.addTable(fieldNames, rows);
}
}
}
/**
* @description add attribute description to each port/param
* @param {string} path
* @param {Array<ModPort|ModParam>} ports
*/
async function patchComment(path: AbsPath, ports: (HdlModulePort | HdlModuleParam)[]) {
if (!ports || !ports.length) {
return;
}
const ranges = ports.map(port => port.range);
const comments = await getSymbolComments(path, ranges);
console.log(ranges);
for (let i = 0; i < ports.length; ++ i) {
let inlineComment = comments[i].replace(/\n/, ' ');
if (inlineComment.startsWith('//') || inlineComment.startsWith('--')) {
inlineComment = inlineComment.substring(2);
}
ports[i].desc = inlineComment;
}
}
/**
* @description get basedoc obj from a module
* @param module
*/
async function getDocsFromModule(module: HdlModule): Promise<MarkdownString> {
const moduleName = module.name;
const portNum = module.ports.length;
const paramNum = module.params.length;
// add desc can optimizer in the future version
const paramPP = patchComment(module.path, module.params);
const portPP = patchComment(module.path, module.ports);
let topModuleDesc = '';
if (hdlParam.isTopModule(module.path, module.name)) {
topModuleDesc = '√';
} else {
topModuleDesc = '×';
}
const md = new MarkdownString(module.range.start.line);
if (module.languageId === HdlLangID.Vhdl) {
md.addTitle('Entity: `' + moduleName + '`', 1);
} else if (module.languageId === HdlLangID.Verilog) {
md.addTitle('Module: `' + moduleName + '`', 1);
} else if (module.languageId === HdlLangID.SystemVerilog) {
md.addTitle('Module: `' + moduleName + '`', 1);
}
// add module name
md.addTitle('Basic Info', 2);
const infos = [
`**File:** ${fspath.basename(module.file.path)}`,
`${paramNum} params, ${portNum} ports`,
'top module ' + topModuleDesc
];
md.addUnorderedList(infos);
md.addEnter();
const diagram = makeDiagram(module.params, module.ports);
md.addText(diagram);
// wait param and port patch
await paramPP;
await portPP;
// param section
md.addTitle('Params', 2);
makeTableFromObjArray(md, module.params, 'params',
['name', 'init', 'empty', 'desc'],
['Param Name', 'Init', 'Range', 'Description']);
md.addEnter();
// port section
md.addTitle('Ports', 2);
makeTableFromObjArray(md, module.ports, 'ports',
['name', 'type', 'width', 'desc'],
['Port Name', 'Direction', 'Range', 'Description']);
md.addEnter();
// dependency section
md.addTitle('Dependency', 2);
const insts = [];
for (const inst of module.getAllInstances()) {
insts.push(inst);
}
makeTableFromObjArray(md, insts, 'Dependencies',
['name', 'type', 'instModPath'],
['name', 'module', 'path']);
md.addEnter();
return md;
}
/**
* @description get basedoc obj according to a file
* @param path absolute path of the file
*/
async function getDocsFromFile(path: AbsPath): Promise<MarkdownString[] | undefined> {
const moduleFile = hdlParam.getHdlFile(path);
if (!moduleFile) {
MainOutput.report('Fail to export documentation of ' + path,
ReportType.Error);
const errorMsg = `${path} is not a valid hdl file in our parse list, check your property.json to see if arch.hardware.src is set correctly!
\ncurrent parse list: \n${opeParam.prjInfo.hardwareSrcPath}\n${opeParam.prjInfo.hardwareSimPath}`;
vscode.window.showErrorMessage(errorMsg);
return undefined;
}
const markdownStringPromises = [];
for (const module of moduleFile.getAllHdlModules()) {
const markdownStringPromise = getDocsFromModule(module);
markdownStringPromises.push(markdownStringPromise);
}
const fileDocs = [];
for (const p of markdownStringPromises) {
const markdownString = await p;
fileDocs.push(markdownString);
}
return fileDocs;
}
/**
* @description get render list of path
* @param path
*/
async function getRenderList(path: AbsPath): Promise<RenderString[] | undefined> {
if (!hdlFile.isHDLFile(path)) {
vscode.window.showErrorMessage('Please use the command in a HDL file!');
return [];
}
const docs = await getDocsFromFile(path);
const svgs = await getWavedromsFromFile(path);
if (docs && svgs) {
const renderList = mergeSortByLine(docs, svgs);
return renderList;
}
return undefined;
}
/**
* @description return render list of current file
*/
async function getCurrentRenderList(): Promise<RenderString[] | undefined> {
const editor = vscode.window.activeTextEditor;
if (editor) {
const currentFilePath = hdlPath.toSlash(editor.document.fileName);
return await getRenderList(currentFilePath);
}
return;
}
async function exportCurrentFileDocAsMarkdown() {
const editor = vscode.window.activeTextEditor;
if (!editor) {
return;
}
const currentFilePath = hdlPath.toSlash(editor.document.fileName);
const hdlFileName = hdlPath.basename(currentFilePath);
const renderList = await getRenderList(currentFilePath);
if (!renderList || renderList.length === 0) {
return;
}
const wsPath = opeParam.workspacePath;
const markdownFolderPath = hdlPath.join(wsPath, 'markdown');
if (!fs.existsSync(markdownFolderPath)) {
fs.mkdirSync(markdownFolderPath);
}
const currentRoot = hdlPath.join(markdownFolderPath, hdlFileName);
if (fs.existsSync(currentRoot)) {
hdlFile.rmSync(currentRoot);
}
fs.mkdirSync(currentRoot);
const figureFolder = hdlPath.join(currentRoot, 'figure');
fs.mkdirSync(figureFolder);
let markdown = '';
for (const r of renderList) {
if (r instanceof MarkdownString) {
markdown += r.renderMarkdown() + '\n';
} else if (r instanceof WavedromString) {
const svgString = r.render();
const svgName = 'wavedrom-' + Count.svgMakeTimes + '.svg';
const svgPath = hdlPath.join(figureFolder, svgName);
fs.writeFileSync(svgPath, svgString);
const relatePath = hdlPath.join('./figure', svgName);
const svgHtml = makeSVGElementByLink(relatePath);
markdown += '\n\n' + svgHtml + '\n\n';
}
}
const markdownName = 'index.md';
const markdownPath = hdlPath.join(currentRoot, markdownName);
Count.svgMakeTimes = 0;
fs.writeFileSync(markdownPath, markdown);
}
async function exportProjectDocAsMarkdown() {
vscode.window.showInformationMessage('this is exportProjectDocAsMarkdown');
}
export {
getDocsFromFile,
getRenderList,
getCurrentRenderList,
exportCurrentFileDocAsMarkdown,
exportProjectDocAsMarkdown
};