216 lines
7.7 KiB
TypeScript

/* eslint-disable @typescript-eslint/naming-convention */
import { opeParam } from "../../global";
import { ThemeType } from "../../global/enum";
import { hdlFile, hdlPath } from "../../hdlFs";
import { HdlModuleParam, HdlModulePort, HdlModulePortType } from "../../hdlParser/common";
import { getThemeColorKind } from "./common";
const lightArrowSvgCache: Record<string, string> = {
'left': '',
'right': '',
'left-right': '',
'left-dot': '',
'right-dot': ''
};
const darkArrowSvgCache: Record<string, string> = {
'left': '',
'right': '',
'left-right': '',
'left-dot': '',
'right-dot': ''
};
function getArrowSvgString(name: 'left' | 'right' | 'left-right' | 'left-dot' | 'right-dot'): string {
const themeType = getThemeColorKind();
const arrowSvgCache = (themeType === ThemeType.Light) ? lightArrowSvgCache: darkArrowSvgCache;
let svgString = arrowSvgCache[name];
if (svgString.length === 0) {
const iconFile = name + '-arrow.svg';
const svgDir = hdlPath.join(opeParam.extensionPath, 'images', 'svg');
const svgPath = hdlPath.join(svgDir, themeType, iconFile);
const readSvgString = hdlFile.readFile(svgPath);
if (readSvgString) {
svgString = readSvgString;
arrowSvgCache[name] = readSvgString;
}
}
return svgString;
}
/**
* @description 生成文档化中用于描述一个 module 的简易 diagram
* @param params
* @param ports
* @returns
*/
function makeDiagram(params: HdlModuleParam[], ports: HdlModulePort[]): string {
// make params block
const diagramParamWrapper = makeDiagramParamWrapper(params);
// make ports block
const diagramPortWrapper = makeDiagramPortWrapper(ports);
const diagram = `<div class="diagram-container"><div class="diagram">${diagramParamWrapper}${diagramPortWrapper}</div></div>`;
return diagram;
}
function makeDiagramParamWrapper(params: HdlModuleParam[]): string {
if (params.length === 0) {
return '';
}
let diagramParams = '';
for (const param of params) {
let diagramParam = '<div>' + param.name;
if (param.init && param.init.length > 0) {
diagramParam += `(${param.init})`;
}
diagramParam += '</div>';
diagramParams += diagramParam;
}
const diagramParamWrapper = `<div class="diagram-ports-wrapper"><div style="width: 55px;"></div><div class="diagram-params"><div></div><div align="left">${diagramParams}</div></div></div>`;
return diagramParamWrapper;
}
function makeDiagramPortWrapper(ports: HdlModulePort[]): string {
if (ports.length === 0) {
return '';
}
const leftPorts = ports.filter(port =>
port.type === HdlModulePortType.Input ||
port.type === HdlModulePortType.Inout ||
port.type === HdlModulePortType.VhdlInput
);
const rightPorts = ports.filter(port =>
port.type === HdlModulePortType.Output ||
port.type === HdlModulePortType.VhdlOutput
);
const leftDirection = makeLeftDirection(leftPorts);
const diagramPorts = makeDiagramPorts(leftPorts, rightPorts);
const rightDirection = makeRightDirection(rightPorts);
const diagramPortWrapper = `<div class="diagram-ports-wrapper">${leftDirection}${diagramPorts}${rightDirection}</div>`;
return diagramPortWrapper;
}
function isValidWidth(portWidth: string | undefined): boolean {
if (portWidth === undefined || portWidth === '' || portWidth === '1') {
return false;
}
return true;
}
function makePortCaption(port: HdlModulePort, direction: 'left' | 'right'): string {
if (!isValidWidth(port.width)) {
return '';
}
return `<div class="port-width-${direction}-caption">${port.width}</div>`;
}
function makePortArrow(port: HdlModulePort, direction: 'left' | 'right'): string {
if (port.type === HdlModulePortType.Inout) {
return getArrowSvgString('left-right');
}
if (direction === 'left') {
if (port.type === HdlModulePortType.Input || port.type === HdlModulePortType.VhdlInput) {
if (isValidWidth(port.width)) {
return getArrowSvgString('right-dot');
} else {
return getArrowSvgString('right');
}
} else if (port.type === HdlModulePortType.Output || port.type === HdlModulePortType.VhdlOutput) {
if (isValidWidth(port.width)) {
return getArrowSvgString('left-dot');
} else {
return getArrowSvgString('left');
}
}
} else if (direction === 'right') {
if (port.type === HdlModulePortType.Input || port.type === HdlModulePortType.VhdlInput) {
if (isValidWidth(port.width)) {
return getArrowSvgString('left-dot');
} else {
return getArrowSvgString('left');
}
} else if (port.type === HdlModulePortType.Output || port.type === HdlModulePortType.VhdlOutput) {
if (isValidWidth(port.width)) {
return getArrowSvgString('right-dot');
} else {
return getArrowSvgString('right');
}
}
}
return '';
}
function makeLeftDirection(leftPorts: HdlModulePort[]): string {
let leftDirection = '';
for (const port of leftPorts) {
const portCaption = makePortCaption(port, 'left');
const portArrow = makePortArrow(port, 'left');
const arrow = `<div class="arrow-wrapper">${portCaption}${portArrow}</div>`;
leftDirection += arrow;
}
return `<div class="left-direction">${leftDirection}</div>`;
}
function makePortName(port: HdlModulePort): string {
let portClass = '';
if (port.type === HdlModulePortType.Input || port.type === HdlModulePortType.VhdlInput) {
portClass = 'i-port-name';
} else if (port.type === HdlModulePortType.Output || port.type === HdlModulePortType.VhdlOutput) {
portClass = 'o-port-name';
} else {
portClass = 'io-port-name';
}
return `<div class="${portClass}">${port.name}</div>`;
}
function makeDiagramPorts(leftPorts: HdlModulePort[], rightPorts: HdlModulePort[]): string {
let leftIndex = 0;
let rightIndex = 0;
let diagramePorts = '';
while (leftIndex < leftPorts.length && rightIndex < rightPorts.length) {
const leftPortName = makePortName(leftPorts[leftIndex ++]);
const rightPortName = makePortName(rightPorts[rightIndex ++]);
const diagramPortItem = `<div class="digrame-port-item">${leftPortName}${rightPortName}</div>`;
diagramePorts += diagramPortItem;
}
while (leftIndex < leftPorts.length) {
const leftPortName = makePortName(leftPorts[leftIndex ++]);
const diagramPortItem = `<div class="digrame-port-item">${leftPortName}<div></div></div>`;
diagramePorts += diagramPortItem;
}
while (rightIndex < rightPorts.length) {
const rightPortName = makePortName(rightPorts[rightIndex ++]);
const diagramPortItem = `<div class="digrame-port-item"><div></div>${rightPortName}</div>`;
diagramePorts += diagramPortItem;
}
return `<div class="diagram-ports">${diagramePorts}</div>`;
}
function makeRightDirection(rightPorts: HdlModulePort[]): string {
let rightDirection = '';
for (const port of rightPorts) {
const portCaption = makePortCaption(port, 'right');
let portArrow = makePortArrow(port, 'right');
portArrow = portArrow.replace('-0.5 -0.5 125 45', '20 -0.5 125 45');
const arrow = `<div class="arrow-wrapper">${portCaption}${portArrow}</div>`;
rightDirection += arrow;
}
return `<div class="right-direction">${rightDirection}</div>`;
}
export {
makeDiagram
};