From 4592d85928643f9b3baf9b54d047b6ee59d47228 Mon Sep 17 00:00:00 2001 From: Kirigaya <1193466151@qq.com> Date: Sat, 17 Feb 2024 17:12:32 +0800 Subject: [PATCH] improve documentation --- CHANGELOG.md | 12 + css/documentation.backup.css | 520 ++++++++++++++++++++++++++ css/documentation.css | 184 +++++++-- images/svg/dark/left-arrow.svg | 10 + images/svg/dark/left-right-arrow.svg | 12 + images/svg/dark/right-arrow.svg | 10 + images/svg/dark/right-dot-arrow.svg | 12 + images/svg/light/left-arrow.svg | 10 + images/svg/light/left-right-arrow.svg | 12 + images/svg/light/right-arrow.svg | 10 + images/svg/light/right-dot-arrow.svg | 12 + package.nls.zh-cn.json | 12 +- package.nls.zh-tw.json | 4 +- src/function/hdlDoc/common.ts | 24 +- src/function/hdlDoc/diagram.ts | 191 ++++++++++ src/function/hdlDoc/html.ts | 2 + src/function/hdlDoc/markdown.ts | 66 ++-- src/function/lsp/completion/vlog.ts | 2 + src/function/lsp/util/feature.ts | 56 ++- src/function/sim/instance.ts | 5 +- 20 files changed, 1061 insertions(+), 105 deletions(-) create mode 100644 css/documentation.backup.css create mode 100644 images/svg/dark/left-arrow.svg create mode 100644 images/svg/dark/left-right-arrow.svg create mode 100644 images/svg/dark/right-arrow.svg create mode 100644 images/svg/dark/right-dot-arrow.svg create mode 100644 images/svg/light/left-arrow.svg create mode 100644 images/svg/light/left-right-arrow.svg create mode 100644 images/svg/light/right-arrow.svg create mode 100644 images/svg/light/right-dot-arrow.svg create mode 100644 src/function/hdlDoc/diagram.ts diff --git a/CHANGELOG.md b/CHANGELOG.md index a683bc5..57f10dc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,18 @@ All notable changes to the "digital-ide" extension will be documented in this fi Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file. +## [0.3.3] - 2024-02-05 + +Feature +- 重做了文档化功能,并且添加了参数和接口的 diagram 可视化的渲染模块 + + +Bug 修复 +- Verilog 参数例化位置错误 +- 文档化的部分问题 + + +--- ## [0.3.2] - 2023-11-01 Feature diff --git a/css/documentation.backup.css b/css/documentation.backup.css new file mode 100644 index 0000000..5547c86 --- /dev/null +++ b/css/documentation.backup.css @@ -0,0 +1,520 @@ +:root { + --dark-main-color : #df733d; + --light-main-color : #cc6633; +} + + +body { + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + line-height: 1.5; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol"; + font-size: 16px; + line-height: 1.5; + word-wrap: break-word; + background-attachment: fixed; + background-repeat: no-repeat; + background-size: cover; + -webkit-background-size: cover; + -o-background-size: cover; + background-position: center 0; + background-image: url(--backgroundImage); +} + +.octicon { + display: inline-block; + vertical-align: text-top; + fill: currentColor; +} + +a { + background-color: transparent; + -webkit-text-decoration-skip: objects; +} + +#wrapper { + justify-content: center; + display: flex; +} + +#write { + padding: 15px 30px; + width: 1000px; +} + +.ImgCaption { + padding-top: 0; + margin-top: 7px; + width: fit-content; +} + +.vscode-dark .ImgCaption { + border-bottom: 2px solid var(--dark-main-color); + color: white; +} + +.vscode-light .ImgCaption { + border-bottom: 2px solid var(--light-main-color); + color: black; +} + +a:active, +a:hover { + outline-width: 0; +} + +strong { + font-weight: inherit; +} + +strong { + font-weight: bolder; +} + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +.error-out { + display: flex; + justify-content: center; + align-items: center; +} + +.error { + color: rgb(227, 60, 60); + border-radius: 1em; + border: 1.5px solid rgb(227, 60, 60); + padding: 10px 20px; +} + +code, +kbd, +pre { + font-family: monospace, monospace; + font-size: 1em; +} + +hr { + box-sizing: content-box; + height: 0; + overflow: visible; +} + +input { + font: inherit; + margin: 0; +} + +input { + overflow: visible; +} + +[type="checkbox"] { + box-sizing: border-box; + padding: 0; +} + +* { + box-sizing: border-box; +} + +input { + font-family: inherit; + font-size: inherit; + line-height: inherit; +} + +a { + color: #4078c0; + text-decoration: none; +} + +a:hover, +a:active { + text-decoration: underline; +} + +strong { + font-weight: 600; +} + +hr { + height: 0; + margin: 15px 0; + overflow: hidden; + background: transparent; + border: 0; + border-bottom: 1px solid; +} + +hr::before { + display: table; + content: ""; +} + +hr::after { + display: table; + clear: both; + content: ""; +} + +table { + border-spacing: 0; + border-collapse: collapse; +} + +td, +th { + padding: 0; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + margin-top: 0; + margin-bottom: 0; +} + +h1 { + font-size: 32px; + font-weight: 600; +} + +h2 { + font-size: 24px; + font-weight: 600; +} + +h3 { + font-size: 20px; + font-weight: 600; +} + +h4 { + font-size: 16px; + font-weight: 600; +} + +h5 { + font-size: 14px; + font-weight: 600; +} + +h6 { + font-size: 12px; + font-weight: 600; +} + +p { + margin-top: 0; + margin-bottom: 10px; +} + +blockquote { + margin: 0; +} + +ul, +ol { + padding-left: 0; + margin-top: 0; + margin-bottom: 0; +} + +ol ol, +ul ol { + list-style-type: lower-roman; +} + +ul ul ol, +ul ol ol, +ol ul ol, +ol ol ol { + list-style-type: lower-alpha; +} + +dd { + margin-left: 0; +} + +code { + font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; + font-size: 12px; +} + +pre { + margin-top: 0; + margin-bottom: 0; + font: 12px Consolas, "Liberation Mono", Menlo, Courier, monospace; +} + +.octicon { + vertical-align: text-bottom; +} + +input { + -webkit-font-feature-settings: "liga" 0; + font-feature-settings: "liga" 0; +} + +.markdown-body::before { + display: table; + content: ""; +} + +.markdown-body::after { + display: table; + clear: both; + content: ""; +} + +.markdown-body>*:first-child { + margin-top: 0 !important; +} + +.markdown-body>*:last-child { + margin-bottom: 0 !important; +} + +a:not([href]) { + color: inherit; + text-decoration: none; +} + +.anchor { + float: left; + padding-right: 4px; + margin-left: -20px; + line-height: 1; +} + +.anchor:focus { + outline: none; +} + +p, +blockquote, +ul, +ol, +dl, +table, +pre { + margin-top: 0; + margin-bottom: 16px; +} + +hr { + height: 0.25em; + padding: 0; + margin: 24px 0; + border: 0; +} + +blockquote { + padding: 0 1em; +} + +blockquote>:first-child { + margin-top: 0; +} + +blockquote>:last-child { + margin-bottom: 0; +} + +kbd { + display: inline-block; + padding: 3px 5px; + font-size: 11px; + line-height: 10px; + vertical-align: middle; + border-radius: 3px; +} + +#write h1, +#write h2, +#write h3, +#write h4, +#write h5, +#write h6 { + margin-top: 24px; + margin-bottom: 16px; + font-weight: 600; + line-height: 1.25; +} + +.vscode-dark h1 { + color: #eee; + border-bottom: 3px solid #df733d; + width: fit-content; + margin: 0 0 1.0em 0; + line-height: 1.3; +} + +.vscode-dark h2 { + color: #eee; +} + +.vscode-dark h2::before { + content: 'H2'; + border-radius: .3em; + font-size: .8em; + padding: 3px 7px; + margin-right: 15px; + color: #eee; + background-color: #df733d; +} + +.vscode-light h1 { + color: #000; + border-bottom: 3px solid #cc6633; + width: fit-content; + margin: 0 0 1.0em 0; + line-height: 1.3; +} + +.vscode-light h2 { + color: #000; +} + +.vscode-light h2::before { + content: 'H2'; + border-radius: .3em; + font-size: .8em; + padding: 3px 7px; + margin-right: 15px; + color: #eee; + background-color: #cc6633; +} + +h1 { + padding-bottom: 0.3em; + font-size: 2em; +} + +h2 { + padding-bottom: 0.3em; + font-size: 1.5em; +} + +h3 { + font-size: 1.25em; +} + +h4 { + font-size: 1em; +} + +h5 { + font-size: 0.875em; +} + +h6 { + font-size: 0.85em; +} + +ul, +ol { + padding-left: 2em; +} + +ul ul, +ul ol, +ol ol, +ol ul { + margin-top: 0; + margin-bottom: 0; +} + +li>p { + margin-top: 16px; +} + +li+li { + margin-top: 0.25em; +} + +/* +table { + display: block; + width: 100%; + overflow: auto; +} + +table th { + font-weight: bold; +} + +table th, +table td { + padding: 6px 13px; + border: .7px solid; +} + +table tr { + border-top: .7px solid; +} */ + + +img { + max-width: 100%; + box-sizing: content-box; +} + +#write table +{ + width: 95%; + border-collapse: collapse; + text-align: center; + margin: 20px; + max-width: 750px; +} +#write table td, table th +{ + border: 1px solid transparent; + padding: 12px 10px; + border-radius: .5em; + word-wrap: break-word; +} + +#write table thead th +{ + background-color: var(--dark-main-color); + font-size: 20px; + font-weight: bolder; + width: 100px; + text-align: center; + vertical-align: middle; + padding: 10px; +} + +.vscode-dark table thead th { + color: white; +} + +.vscode-dark table td, table th { + color: rgb(234, 231, 231); +} + +.vscode-light table thead th { + color: white; +} + +.vscode-light table td, table th { + color: rgb(16, 16, 16); +} + +.vscode-dark table tr:nth-child(even) +{ + background: #20242b; +} + +.vscode-light table tr:nth-child(even) +{ + background: #e7e1e1; +} \ No newline at end of file diff --git a/css/documentation.css b/css/documentation.css index 5547c86..7dd68b2 100644 --- a/css/documentation.css +++ b/css/documentation.css @@ -18,7 +18,6 @@ body { -webkit-background-size: cover; -o-background-size: cover; background-position: center 0; - background-image: url(--backgroundImage); } .octicon { @@ -49,12 +48,12 @@ a { } .vscode-dark .ImgCaption { - border-bottom: 2px solid var(--dark-main-color); + /* border-bottom: 2px solid var(--dark-main-color); */ color: white; } .vscode-light .ImgCaption { - border-bottom: 2px solid var(--light-main-color); + /* border-bottom: 2px solid var(--light-main-color); */ color: black; } @@ -93,7 +92,6 @@ code, kbd, pre { font-family: monospace, monospace; - font-size: 1em; } hr { @@ -244,7 +242,6 @@ dd { code { font-family: Consolas, "Liberation Mono", Menlo, Courier, monospace; - font-size: 12px; } pre { @@ -350,7 +347,7 @@ kbd { .vscode-dark h1 { color: #eee; - border-bottom: 3px solid #df733d; + /* border-bottom: 3px solid #df733d; */ width: fit-content; margin: 0 0 1.0em 0; line-height: 1.3; @@ -360,7 +357,7 @@ kbd { color: #eee; } -.vscode-dark h2::before { +/* .vscode-dark h2::before { content: 'H2'; border-radius: .3em; font-size: .8em; @@ -368,11 +365,11 @@ kbd { margin-right: 15px; color: #eee; background-color: #df733d; -} +} */ .vscode-light h1 { color: #000; - border-bottom: 3px solid #cc6633; + /* border-bottom: 3px solid #cc6633; */ width: fit-content; margin: 0 0 1.0em 0; line-height: 1.3; @@ -382,7 +379,7 @@ kbd { color: #000; } -.vscode-light h2::before { +/* .vscode-light h2::before { content: 'H2'; border-radius: .3em; font-size: .8em; @@ -390,7 +387,7 @@ kbd { margin-right: 15px; color: #eee; background-color: #cc6633; -} +} */ h1 { padding-bottom: 0.3em; @@ -466,25 +463,23 @@ img { box-sizing: content-box; } -#write table -{ +#write table { width: 95%; border-collapse: collapse; text-align: center; margin: 20px; max-width: 750px; } -#write table td, table th -{ - border: 1px solid transparent; + +#write table td, table th { + border: 1px solid; padding: 12px 10px; - border-radius: .5em; + /* border-radius: .5em; */ word-wrap: break-word; } -#write table thead th -{ - background-color: var(--dark-main-color); +#write table thead th { + /* background-color: var(--dark-main-color); */ font-size: 20px; font-weight: bolder; width: 100px; @@ -493,28 +488,135 @@ img { padding: 10px; } -.vscode-dark table thead th { +.vscode-dark table {` + color: #F0F0F0; +} + +.vscode-light table { + color: #1F2329; +} + + +.vscode-dark #write table thead th { + background-color: rgb(76,55,114); +} + +.vscode-light #write table thead th { + background-color: rgb(236,226,254); +} + +.vscode-dark table tr:nth-child(even) { + background: #232323; +} + +.vscode-light table tr:nth-child(even) { + background: #F6F7F8; +} + + +/* TODO: Diagram CSS */ +.diagram-container { + width: 100%; + display: flex; + justify-content: center; +} + +.diagram-container .diagram-ports-wrapper { + display: flex; +} + +.diagram-container .diagram-params { + display: flex; + justify-content: space-between; + border-radius: 0.7em; + padding: 15px; + margin: 10px 60px; + width: 350px; + text-align: right; +} + +.diagram-container .diagram-ports { + border-radius: 0.7em; + padding: 20px 0px; + margin: 10px 0px 10px 0px; + width: 350px; +} + +.vscode-dark .diagram-params { + background-color: rgba(53,59,140); + border: solid 4.5px rgb(83,88,157); +} + +.vscode-light .diagram-params { + background-color: rgba(180,185,243); + border: solid 4.5px rgb(153,157,207); +} + +.vscode-dark .diagram-ports { + background-color: rgba(35,102,93); + border: solid 4.5px rgb(68,125,117); +} + +.vscode-light .diagram-ports { + background-color: rgb(169,239,230); + border: solid 4.5px rgb(144,203,196); +} + + +.diagram-container .digrame-port-item { + display: flex; + justify-content: space-between; + height: 60px; +} + +.diagram-container .i-port-name { + font-size: 20px; + padding: 3px 8px; +} + +.diagram-container .o-port-name { + font-size: 20px; + padding: 3px 8px; +} + +.diagram-container .io-port-name { + font-size: 20px; + padding: 3px 8px; + +} + +.diagram-container .left-direction { + padding-right: 0; + padding: 20px 0px; + margin: 10px 0 0 10px; + width: 105px; +} + +.diagram-container .right-direction { + padding-left: 0; + padding: 20px 0px; + margin: 10px 0 10px 0px; + width: 105px; +} + +.diagram-container .arrow-wrapper { + height: 60px; +} + +.diagram-container .port-width-left-caption { + position: absolute; + margin: -10px 35px; +} + +.diagram-container .port-width-right-caption { + position: absolute; + margin: -10px 10px; +} + +.vscode-dark .diagram-container { color: white; } -.vscode-dark table td, table th { - color: rgb(234, 231, 231); -} - -.vscode-light table thead th { - color: white; -} - -.vscode-light table td, table th { - color: rgb(16, 16, 16); -} - -.vscode-dark table tr:nth-child(even) -{ - background: #20242b; -} - -.vscode-light table tr:nth-child(even) -{ - background: #e7e1e1; +.vscode-light .diagram-container { + color: black; } \ No newline at end of file diff --git a/images/svg/dark/left-arrow.svg b/images/svg/dark/left-arrow.svg new file mode 100644 index 0000000..b89500f --- /dev/null +++ b/images/svg/dark/left-arrow.svg @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/images/svg/dark/left-right-arrow.svg b/images/svg/dark/left-right-arrow.svg new file mode 100644 index 0000000..239d918 --- /dev/null +++ b/images/svg/dark/left-right-arrow.svg @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/images/svg/dark/right-arrow.svg b/images/svg/dark/right-arrow.svg new file mode 100644 index 0000000..59c4b1a --- /dev/null +++ b/images/svg/dark/right-arrow.svg @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/images/svg/dark/right-dot-arrow.svg b/images/svg/dark/right-dot-arrow.svg new file mode 100644 index 0000000..e4df021 --- /dev/null +++ b/images/svg/dark/right-dot-arrow.svg @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/images/svg/light/left-arrow.svg b/images/svg/light/left-arrow.svg new file mode 100644 index 0000000..b5576cd --- /dev/null +++ b/images/svg/light/left-arrow.svg @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/images/svg/light/left-right-arrow.svg b/images/svg/light/left-right-arrow.svg new file mode 100644 index 0000000..f7cc752 --- /dev/null +++ b/images/svg/light/left-right-arrow.svg @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/images/svg/light/right-arrow.svg b/images/svg/light/right-arrow.svg new file mode 100644 index 0000000..8e87cb2 --- /dev/null +++ b/images/svg/light/right-arrow.svg @@ -0,0 +1,10 @@ + + + + + + + \ No newline at end of file diff --git a/images/svg/light/right-dot-arrow.svg b/images/svg/light/right-dot-arrow.svg new file mode 100644 index 0000000..878c5b5 --- /dev/null +++ b/images/svg/light/right-dot-arrow.svg @@ -0,0 +1,12 @@ + + + + + + + + \ No newline at end of file diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index 3e4cd00..e080306 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -28,10 +28,10 @@ "digital-ide.hard.gui.title": "打开界面", "digital-ide.hard.exit.title": "退出当前项目", "digital-ide.pickLibrary.title": "从自定义选择自由和普遍", - "digital-ide.pl.setSrcTop.title": "设置为src的top", - "digital-ide.pl.setSimTop.title": "设置为sim的top", - "digital-ide.pl.addDevice.title": "添加device", - "digital-ide.pl.delDevice.title": "删除device", + "digital-ide.pl.setSrcTop.title": "设置为 源文件(src)的顶层文件", + "digital-ide.pl.setSimTop.title": "设置为 测试文件(sim) 的顶层文件", + "digital-ide.pl.addDevice.title": "添加 device", + "digital-ide.pl.delDevice.title": "删除 device", "digital-ide.pl.addFile.title": "添加文件", "digital-ide.pl.delFile.title": "d删除文件", "digital-ide.netlist.title": "netlist", @@ -39,8 +39,8 @@ "digital-ide.lsp.tool.insertTextToUri.title": "插入文本uri", "digital-ide.lsp.tool.transformOldPropertyFile.title": "转换配置文件从先前版本新版本", "digital-ide.vhdl2vlog.title": "vhdl代码翻译为verilog代码", - "digital-ide.fsm.show.title": "显示当前文件的FSM图", - "digital-ide.netlist.show.title": "显示当前文件的netlist", + "digital-ide.fsm.show.title": "显示当前文件的 FSM", + "digital-ide.netlist.show.title": "显示当前文件的 Netlist", "digital-ide.lsp.vlog.linter.pick.title": "选择 Verilog 的诊断", "digital-ide.lsp.svlog.linter.pick.title": "选择 System Verilog 的诊断", "digital-ide.lsp.vhdl.linter.pick.title": "选择 VHDL 的诊断", diff --git a/package.nls.zh-tw.json b/package.nls.zh-tw.json index 5404e02..1fdbfd9 100644 --- a/package.nls.zh-tw.json +++ b/package.nls.zh-tw.json @@ -39,8 +39,8 @@ "digital-ide.lsp.tool.insertTextToUri.title": "插入文本uri", "digital-ide.lsp.tool.transformOldPropertyFile.title": "轉換配置文件從先前版本新版本", "digital-ide.vhdl2vlog.title": "vhdl代碼翻譯為verilog代碼", - "digital-ide.fsm.show.title": "顯示當前文件的FSM圖", - "digital-ide.netlist.show.title": "顯示當前文件的netlist", + "digital-ide.fsm.show.title": "顯示當前文件的 FSM", + "digital-ide.netlist.show.title": "顯示當前文件的 Netlist", "digital-ide.lsp.vlog.linter.pick.title": "選擇 Verilog 的診斷", "digital-ide.lsp.svlog.linter.pick.title": "選擇 System Verilog 的診斷", "digital-ide.lsp.vhdl.linter.pick.title": "選擇 VHDL 的診斷", diff --git a/src/function/hdlDoc/common.ts b/src/function/hdlDoc/common.ts index 144b621..ac499dd 100644 --- a/src/function/hdlDoc/common.ts +++ b/src/function/hdlDoc/common.ts @@ -10,6 +10,7 @@ import * as showdown from 'showdown'; import { ThemeType } from '../../global/enum'; import { MainOutput, ReportType } from '../../global'; +import { HdlModuleParam, HdlModulePort } from '../../hdlParser/common'; const Count = { svgMakeTimes: 0 @@ -32,7 +33,7 @@ enum MarkdownTag { }; enum MarkdownAlign { Left, Center, Right }; -enum RenderType { Wavedrom, Markdown }; +enum RenderType { Wavedrom, Markdown, Diagram }; function getAlignSpliter(align: MarkdownAlign): string { switch (align) { @@ -267,6 +268,26 @@ class WavedromString extends RenderString { } }; +class DiagramString extends RenderString { + params: HdlModuleParam[]; + ports: HdlModulePort[]; + + constructor(line: number) { + super(line, RenderType.Diagram); + this.params = []; + this.ports = []; + } + + add() { + + } + + render(): string { + + return ''; + } +} + function parseJson5(text: string): any { let json = null; try { @@ -368,5 +389,6 @@ export { RenderString, makeWaveDromSVG, getWavedromsFromFile, + getThemeColorKind, Count }; \ No newline at end of file diff --git a/src/function/hdlDoc/diagram.ts b/src/function/hdlDoc/diagram.ts new file mode 100644 index 0000000..e385fc8 --- /dev/null +++ b/src/function/hdlDoc/diagram.ts @@ -0,0 +1,191 @@ +/* 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 arrowSvgCache: Record = { + 'left': '', + 'right': '', + 'left-right': '', + 'left-dot': '', + 'right-dot': '' +}; + +function getArrowSvgString(name: 'left' | 'right' | 'left-right' | 'left-dot' | 'right-dot'): string { + let svgString = arrowSvgCache[name]; + if (svgString.length === 0) { + const themeType = getThemeColorKind(); + 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; +} + +function makeDiagram(params: HdlModuleParam[], ports: HdlModulePort[]): string { + // make params block + const diagramParamWrapper = makeDiagramParamWrapper(params); + + // make ports block + const diagramPortWrapper = makeDiagramPortWrapper(ports); + + const diagram = `
${diagramParamWrapper}${diagramPortWrapper}
`; + return diagram; +} + + +function makeDiagramParamWrapper(params: HdlModuleParam[]): string { + if (params.length === 0) { + return ''; + } + let diagramParams = ''; + for (const param of params) { + let diagramParam = '
' + param.name; + if (param.init && param.init.length > 0) { + diagramParam += `(${param.init})`; + } + diagramParam += '
'; + diagramParams += diagramParam; + } + const diagramParamWrapper = `
${diagramParams}
`; + 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); + const rightPorts = ports.filter(port => port.type === HdlModulePortType.Output); + + const leftDirection = makeLeftDirection(leftPorts); + const diagramPorts = makeDiagramPorts(leftPorts, rightPorts); + const rightDirection = makeRightDirection(rightPorts); + + const diagramPortWrapper = `
${leftDirection}${diagramPorts}${rightDirection}
`; + 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 `
${port.width}
`; +} + +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) { + if (isValidWidth(port.width)) { + return getArrowSvgString('right-dot'); + } else { + return getArrowSvgString('right'); + } + } else if (port.type === HdlModulePortType.Output) { + if (isValidWidth(port.width)) { + return getArrowSvgString('left-dot'); + } else { + return getArrowSvgString('left'); + } + } + } else if (direction === 'right') { + if (port.type === HdlModulePortType.Input) { + if (isValidWidth(port.width)) { + return getArrowSvgString('left-dot'); + } else { + return getArrowSvgString('left'); + } + } else if (port.type === HdlModulePortType.Output) { + 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 = `
${portCaption}${portArrow}
`; + leftDirection += arrow; + } + return `
${leftDirection}
`; +} + +function makePortName(port: HdlModulePort): string { + let portClass = ''; + if (port.type === HdlModulePortType.Input) { + portClass = 'i-port-name'; + } else if (port.type === HdlModulePortType.Output) { + portClass = 'o-port-name'; + } else { + portClass = 'io-port-name'; + } + return `
${port.name}
`; +} + +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 = `
${leftPortName}${rightPortName}
`; + diagramePorts += diagramPortItem; + } + while (leftIndex < leftPorts.length) { + const leftPortName = makePortName(leftPorts[leftIndex ++]); + const diagramPortItem = `
${leftPortName}
`; + diagramePorts += diagramPortItem; + } + while (rightIndex < rightPorts.length) { + const rightPortName = makePortName(leftPorts[leftIndex ++]); + const diagramPortItem = `
${rightPortName}
`; + diagramePorts += diagramPortItem; + } + return `
${diagramePorts}
`; +} + +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'); + console.log(portArrow); + + const arrow = `
${portCaption}${portArrow}
`; + rightDirection += arrow; + } + return `
${rightDirection}
`; +} + +export { + makeDiagram +}; \ No newline at end of file diff --git a/src/function/hdlDoc/html.ts b/src/function/hdlDoc/html.ts index 7b1e0a1..58ac321 100644 --- a/src/function/hdlDoc/html.ts +++ b/src/function/hdlDoc/html.ts @@ -110,6 +110,7 @@ async function makeShowHTML(usage: string): Promise { // start to render the real html let body = ''; + for (const r of renderList) { const renderResult = r.render(); if (renderResult) { @@ -150,6 +151,7 @@ async function showDocWebview() { webview.iconPath = hdlIcon.getIconConfig('documentation'); webview.webview.html = await htmlPromise; + } diff --git a/src/function/hdlDoc/markdown.ts b/src/function/hdlDoc/markdown.ts index df5ac17..0f6c484 100644 --- a/src/function/hdlDoc/markdown.ts +++ b/src/function/hdlDoc/markdown.ts @@ -1,5 +1,6 @@ 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'; @@ -10,6 +11,8 @@ import { MarkdownString, RenderString, RenderType, import { hdlPath, hdlFile } from '../../hdlFs'; import { getSymbolComments } from '../lsp/util/feature'; +import { HdlLangID } from '../../global/enum'; +import { makeDiagram } from './diagram'; function makeSVGElementByLink(link: AbsPath, caption?: string) { @@ -22,6 +25,26 @@ function makeSVGElementByLink(link: AbsPath, caption?: string) { return '
' + mainHtml + '

\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) + '/'; @@ -32,19 +55,7 @@ function makeTableFromObjArray(md: MarkdownString, array: any[], name: string, f for (const obj of array) { const data = []; for (const subName of fieldNames) { - let value = obj[subName]; - if (subName === 'instModPath' && value) { - value = value.replace(ws, ''); - } - - if (value && value.trim().length === 0) { - value = ' '; - } - - // TODO : 1 not known - if (name === 'ports' && value === 'Unknown') { - value = '1'; - } + const value = selectFieldValue(obj, subName, ws, name); data.push(value); } rows.push(data); @@ -63,7 +74,7 @@ function makeTableFromObjArray(md: MarkdownString, array: any[], name: string, f * @param {string} path * @param {Array} ports */ -async function patchComment(path: AbsPath, ports: (HdlModulePort | HdlModuleParam)[]) { +async function patchComment(path: AbsPath, ports: (HdlModulePort | HdlModuleParam)[]) { if (!ports || !ports.length) { return; } @@ -71,7 +82,7 @@ async function patchComment(path: AbsPath, ports: (HdlModulePort | HdlModulePara const comments = await getSymbolComments(path, ranges); for (let i = 0; i < ports.length; ++ i) { let inlineComment = comments[i].replace(/\n/, ' '); - if (inlineComment.startsWith('//')) { + if (inlineComment.startsWith('//') || inlineComment.startsWith('--')) { inlineComment = inlineComment.substring(2); } ports[i].desc = inlineComment; @@ -100,33 +111,46 @@ async function getDocsFromModule(module: HdlModule): Promise { } 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(moduleName, 1); md.addTitle('Basic Info', 2); + const infos = [ + `**File:** ${fspath.basename(module.file.path)}`, `${portNum} params, ${paramNum} 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); + md.addTitle('Params', 2); makeTableFromObjArray(md, module.params, 'params', - ['name', 'init', 'desc'], - ['name', 'init', 'description']); + ['name', 'init', 'empty', 'desc'], + ['Param Name', 'Init', 'Range', 'Description']); md.addEnter(); // port section - md.addTitle('ports', 2); + md.addTitle('Ports', 2); makeTableFromObjArray(md, module.ports, 'ports', ['name', 'type', 'width', 'desc'], - ['name', 'type', 'width', 'description']); + ['Port Name', 'Direction', 'Range', 'Description']); md.addEnter(); diff --git a/src/function/lsp/completion/vlog.ts b/src/function/lsp/completion/vlog.ts index e052f0d..981666f 100644 --- a/src/function/lsp/completion/vlog.ts +++ b/src/function/lsp/completion/vlog.ts @@ -195,6 +195,7 @@ class VlogCompletionProvider implements vscode.CompletionItemProvider { completions.push(...this.makeCompilerKeywordItems(document, position)); completions.push(...this.makeSystemKeywordItems(document, position)); + const symbolResult = await hdlSymbolStorage.getSymbol(filePath); if (!symbolResult) { return completions; @@ -215,6 +216,7 @@ class VlogCompletionProvider implements vscode.CompletionItemProvider { return completions; } + // 3. provide modules const suggestModulesPromise = this.provideModules(document, position, filePath, symbolResult.macro.includes); diff --git a/src/function/lsp/util/feature.ts b/src/function/lsp/util/feature.ts index 8fd5eb1..8c70c53 100644 --- a/src/function/lsp/util/feature.ts +++ b/src/function/lsp/util/feature.ts @@ -131,17 +131,17 @@ async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, no let content = ''; let is_b_comment = false; - let line = range.start.line + 1; - const firstLine = range.start.line - 1; - console.log('enter getFullSymbolInfo'); - + let line = range.start.line; + + // vscode 的行编号从 0 开始算 + const firstLine = range.start.line - 1; + while (line) { line --; content = document.lineAt(line).text; - + // 首先判断该行是否是空白 - let isblank = content.match(nonblank); - if (!isblank) { + if (content.trim().length === 0) { continue; } @@ -150,7 +150,7 @@ async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, no if (b_comment_begin_index === -1) { comments.push(content + '\n'); continue; - } + } comments.push(content.slice(b_comment_begin_index, content.length) + '\n'); is_b_comment = false; content = content.slice(0, b_comment_begin_index); @@ -161,24 +161,22 @@ async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, no } // 判断该行是否存在行注释 - let l_comment_index = content.indexOf(l_comment_symbol); - - if (l_comment_index >= 0) { - let before_l_comment = content.slice(0, l_comment_index); - if (before_l_comment.match(nonblank)) { - // TODO : check again if bug takes place - comments.push(content.slice(l_comment_index, content.length) + '\n'); - break; - } - - // 否则该行全为该定义的注释 - comments.push(content + '\n'); - continue; - } - + let l_comment_index = content.indexOf(l_comment_symbol); // 判断该行是否存在块注释 let b_comment_end_index = content.indexOf('*/'); - if (b_comment_end_index >= 0) { + + if (l_comment_index >= 0) { + let before_l_comment = content.slice(0, l_comment_index); + // 判断当前的行注释的注释前面是不是还有字符串 + if (!before_l_comment.match(nonblank) || line === firstLine) { + const l_comment = content.slice(l_comment_index, content.length) + '\n'; + comments.push(l_comment); + break; + } + // 否则该行全为该定义的注释 + comments.push(content + '\n'); + + } else if (b_comment_end_index >= 0) { b_comment_end_index += 2; let behind_b_comment = content.slice(b_comment_end_index, content.length); behind_b_comment = del_comments(behind_b_comment, l_comment_regExp); @@ -191,18 +189,12 @@ async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, no } break; } - + comments.push(content + '\n'); is_b_comment = true; - continue; - } - - // 说明既不是块注释又不是行注释所以就是到了代码块 - if (line !== firstLine) { - break; } } - + // 清除空前行 let resultComment = ''; for (const c of comments.reverse()) { diff --git a/src/function/sim/instance.ts b/src/function/sim/instance.ts index 07a0f59..f450b11 100644 --- a/src/function/sim/instance.ts +++ b/src/function/sim/instance.ts @@ -44,13 +44,14 @@ function instanceVlogCode(module: HdlModule, prefix: string = '', returnSnippetS } content.appendText(prefix + module.name + ' '); + makeVlogParamAssignments(content, module.params, prefix, returnSnippetString, needComment); + if (returnSnippetString) { content.appendPlaceholder('u_' + module.name); } else { content.appendText('u_' + module.name); } - makeVlogParamAssignments(content, module.params, prefix, returnSnippetString, needComment); makeVlogPortAssignments(content, module.ports, prefix, returnSnippetString, needComment); const instanceString = content.value; @@ -165,8 +166,8 @@ function makeVlogParamAssignments(content: vscode.SnippetString, params: HdlModu content.appendText(' '.repeat(maxInitLength - param.init.length + 1) + ' )'); if (i < params.length - 1) { content.appendText(','); + content.appendText('\n'); } - content.appendText('\n'); } content.appendText(prefix + ')\n'); }