finish testbench, instance | finish doc | move all the none-ts file to resources
This commit is contained in:
parent
a02620cf53
commit
01f44548ea
71
README.md
71
README.md
@ -1,71 +1,4 @@
|
|||||||
# digital-ide README
|
# Digital-IDE
|
||||||
|
|
||||||
This is the README for your extension "digital-ide". After writing up a brief description, we recommend including the following sections.
|

|
||||||
|
|
||||||
## Features
|
|
||||||
|
|
||||||
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
|
|
||||||
|
|
||||||
For example if there is an image subfolder under your extension project workspace:
|
|
||||||
|
|
||||||
\!\[feature X\]\(images/feature-x.png\)
|
|
||||||
|
|
||||||
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
|
|
||||||
|
|
||||||
## Requirements
|
|
||||||
|
|
||||||
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
|
|
||||||
|
|
||||||
## Extension Settings
|
|
||||||
|
|
||||||
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
This extension contributes the following settings:
|
|
||||||
|
|
||||||
* `myExtension.enable`: Enable/disable this extension.
|
|
||||||
* `myExtension.thing`: Set to `blah` to do something.
|
|
||||||
|
|
||||||
## Known Issues
|
|
||||||
|
|
||||||
Calling out known issues can help limit users opening duplicate issues against your extension.
|
|
||||||
|
|
||||||
## Release Notes
|
|
||||||
|
|
||||||
Users appreciate release notes as you update your extension.
|
|
||||||
|
|
||||||
### 1.0.0
|
|
||||||
|
|
||||||
Initial release of ...
|
|
||||||
|
|
||||||
### 1.0.1
|
|
||||||
|
|
||||||
Fixed issue #.
|
|
||||||
|
|
||||||
### 1.1.0
|
|
||||||
|
|
||||||
Added features X, Y, and Z.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Following extension guidelines
|
|
||||||
|
|
||||||
Ensure that you've read through the extensions guidelines and follow the best practices for creating your extension.
|
|
||||||
|
|
||||||
* [Extension Guidelines](https://code.visualstudio.com/api/references/extension-guidelines)
|
|
||||||
|
|
||||||
## Working with Markdown
|
|
||||||
|
|
||||||
You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
|
|
||||||
|
|
||||||
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux).
|
|
||||||
* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux).
|
|
||||||
* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets.
|
|
||||||
|
|
||||||
## For more information
|
|
||||||
|
|
||||||
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
|
|
||||||
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
|
|
||||||
|
|
||||||
**Enjoy!**
|
|
||||||
|
178
css/documentation.backup.css
Normal file
178
css/documentation.backup.css
Normal file
@ -0,0 +1,178 @@
|
|||||||
|
:root {
|
||||||
|
--title-font : "Cascadia code", "Microsoft YaHei", "Times", serif;
|
||||||
|
--base-font : "Roboto Slab", "Microsoft YaHei", serif;
|
||||||
|
--monospace: "Cascadia code", "Microsoft YaHei", "Courier New", monospace;
|
||||||
|
--main-font-size : 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error-out {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.error {
|
||||||
|
color: red;
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Roboto Slab";
|
||||||
|
src: url("../font/RobotoSlab-Regular-2.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Cascadia code";
|
||||||
|
src: url("../font/Cascadia-Code-Regular-2.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Open Sans";
|
||||||
|
src: url("../font/Open-Sans-2.ttf");
|
||||||
|
}
|
||||||
|
|
||||||
|
@font-face {
|
||||||
|
font-family: "Glow Sans";
|
||||||
|
src: url("../font/GlowSansSC-Normal-Book.woff2") format('woff2');
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: "Roboto Slab", "SimHei", serif;
|
||||||
|
/* background-color: rgb(255, 255, 255); */
|
||||||
|
-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;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
text-rendering: optimizelegibility;
|
||||||
|
-webkit-font-smoothing: initial;
|
||||||
|
}
|
||||||
|
|
||||||
|
.octicon {
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: text-top;
|
||||||
|
fill: currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
border-style: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#write h1, h2, h3, h4, h5, h6 {
|
||||||
|
font-family: var(--title-font);
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.5;
|
||||||
|
margin: 0 0 1em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#write h1 {
|
||||||
|
font-size: 2em;
|
||||||
|
margin: 0.67em 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#write {
|
||||||
|
position: static;
|
||||||
|
/* width: 90%; */
|
||||||
|
max-width: 1000px;
|
||||||
|
min-height: calc(100vh - 6rem);
|
||||||
|
min-width: calc(100vw - 45rem);
|
||||||
|
line-height: 1.6;
|
||||||
|
transform: none;
|
||||||
|
height: auto;
|
||||||
|
caret-color: var(--main-color);
|
||||||
|
}
|
||||||
|
|
||||||
|
#write h2 {
|
||||||
|
font-size: 28px;
|
||||||
|
border-radius: .5em;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
#write h3 {
|
||||||
|
font-size: 24px;
|
||||||
|
border-radius: .3em;
|
||||||
|
width: fit-content;
|
||||||
|
}
|
||||||
|
|
||||||
|
#write h4 {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#write h5 {
|
||||||
|
font-size: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
#write hr {
|
||||||
|
width: 60%;
|
||||||
|
text-align:center;
|
||||||
|
margin: 4.5em auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* table */
|
||||||
|
#write table
|
||||||
|
{
|
||||||
|
width: 95%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
text-align: center;
|
||||||
|
font-family: var(--monospace);
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
#write table td, table th
|
||||||
|
{
|
||||||
|
border: 1px solid;
|
||||||
|
padding: 5px;
|
||||||
|
border-radius: .5em;
|
||||||
|
}
|
||||||
|
#write table td {
|
||||||
|
font-family: var(--title-font);
|
||||||
|
}
|
||||||
|
#write table thead th
|
||||||
|
{
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: bolder;
|
||||||
|
text-align: center;
|
||||||
|
vertical-align: middle;
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* table tr:nth-child(odd)
|
||||||
|
{
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
table tr:nth-child(even)
|
||||||
|
{
|
||||||
|
background: var(--light-color);
|
||||||
|
} */
|
||||||
|
|
||||||
|
/* main element consisting of your text */
|
||||||
|
p {
|
||||||
|
margin: 0 0 2em 0;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 1.6;
|
||||||
|
font-size: var(--main-font-size);
|
||||||
|
font-family: var(--base-font);
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
font-weight: 500;
|
||||||
|
text-decoration: none;
|
||||||
|
text-decoration-style: none;
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0 3px 0 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* list */
|
||||||
|
ol, ul {
|
||||||
|
font-size: var(--main-font-size);
|
||||||
|
padding-left: 2em;
|
||||||
|
line-height: 2;
|
||||||
|
font-family: var(--base-font);
|
||||||
|
}
|
520
css/documentation.css
Normal file
520
css/documentation.css
Normal file
@ -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;
|
||||||
|
}
|
128
images/icons/iconfont.json
Normal file
128
images/icons/iconfont.json
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
{
|
||||||
|
"id": "3826523",
|
||||||
|
"name": "draft",
|
||||||
|
"font_family": "iconfont",
|
||||||
|
"css_prefix_text": "icon-",
|
||||||
|
"description": "",
|
||||||
|
"glyphs": [
|
||||||
|
{
|
||||||
|
"icon_id": "7569441",
|
||||||
|
"name": "天气-未知",
|
||||||
|
"font_class": "help-unknown",
|
||||||
|
"unicode": "e62a",
|
||||||
|
"unicode_decimal": 58922
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "6989868",
|
||||||
|
"name": "module-fill",
|
||||||
|
"font_class": "module-fill",
|
||||||
|
"unicode": "e622",
|
||||||
|
"unicode_decimal": 58914
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "6989870",
|
||||||
|
"name": "module",
|
||||||
|
"font_class": "module",
|
||||||
|
"unicode": "e623",
|
||||||
|
"unicode_decimal": 58915
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "1126",
|
||||||
|
"name": "文件夹",
|
||||||
|
"font_class": "wenjianjia",
|
||||||
|
"unicode": "e600",
|
||||||
|
"unicode_decimal": 58880
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "1478582",
|
||||||
|
"name": "ic_input",
|
||||||
|
"font_class": "ic_input",
|
||||||
|
"unicode": "e908",
|
||||||
|
"unicode_decimal": 59656
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "17397810",
|
||||||
|
"name": "output",
|
||||||
|
"font_class": "output",
|
||||||
|
"unicode": "e7b0",
|
||||||
|
"unicode_decimal": 59312
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "18171148",
|
||||||
|
"name": "交换,双箭头,平行",
|
||||||
|
"font_class": "exchange-full",
|
||||||
|
"unicode": "ea19",
|
||||||
|
"unicode_decimal": 59929
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "13553191",
|
||||||
|
"name": "markdown-line",
|
||||||
|
"font_class": "markdown-line",
|
||||||
|
"unicode": "ee68",
|
||||||
|
"unicode_decimal": 61032
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "10168298",
|
||||||
|
"name": "html-1",
|
||||||
|
"font_class": "html-",
|
||||||
|
"unicode": "e633",
|
||||||
|
"unicode_decimal": 58931
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "16432310",
|
||||||
|
"name": "PDF",
|
||||||
|
"font_class": "PDF",
|
||||||
|
"unicode": "e684",
|
||||||
|
"unicode_decimal": 59012
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "15378918",
|
||||||
|
"name": "v",
|
||||||
|
"font_class": "v",
|
||||||
|
"unicode": "ecf7",
|
||||||
|
"unicode_decimal": 60663
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "23306741",
|
||||||
|
"name": "chip",
|
||||||
|
"font_class": "chip1",
|
||||||
|
"unicode": "e7a8",
|
||||||
|
"unicode_decimal": 59304
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "31357424",
|
||||||
|
"name": "模块",
|
||||||
|
"font_class": "mokuai",
|
||||||
|
"unicode": "e60b",
|
||||||
|
"unicode_decimal": 58891
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "3851337",
|
||||||
|
"name": "参数",
|
||||||
|
"font_class": "canshu",
|
||||||
|
"unicode": "e655",
|
||||||
|
"unicode_decimal": 58965
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "11520228",
|
||||||
|
"name": "接口",
|
||||||
|
"font_class": "jiekou",
|
||||||
|
"unicode": "e638",
|
||||||
|
"unicode_decimal": 58936
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "24698418",
|
||||||
|
"name": "chip",
|
||||||
|
"font_class": "chip",
|
||||||
|
"unicode": "e749",
|
||||||
|
"unicode_decimal": 59209
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"icon_id": "13304138",
|
||||||
|
"name": "verilog",
|
||||||
|
"font_class": "verilog",
|
||||||
|
"unicode": "e6b3",
|
||||||
|
"unicode_decimal": 59059
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
BIN
images/icons/iconfont.woff2
Normal file
BIN
images/icons/iconfont.woff2
Normal file
Binary file not shown.
9450
package-lock.json
generated
9450
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
255
package.json
255
package.json
@ -29,6 +29,71 @@
|
|||||||
"type": "string",
|
"type": "string",
|
||||||
"default": "",
|
"default": "",
|
||||||
"description": "path of the dictionary of \"custom\" in library"
|
"description": "path of the dictionary of \"custom\" in library"
|
||||||
|
},
|
||||||
|
"function.doc.webview.backgroundImage": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "",
|
||||||
|
"description": "url of the background image"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.scale": {
|
||||||
|
"type": "number",
|
||||||
|
"default": 1,
|
||||||
|
"description": "scale of the exported pdf"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.printBackground": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": true,
|
||||||
|
"description": "whether print background"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.landscape": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "whether export pdf as a landscape style"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.format": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "A4",
|
||||||
|
"description": "format of pdf size"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.displayHeaderFooter": {
|
||||||
|
"type": "boolean",
|
||||||
|
"default": false,
|
||||||
|
"description": "display header and footer in the exported pdf"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.browserPath": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe",
|
||||||
|
"description": "the absolute path of edge or chrome, we need browser to render pdf"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.margin.top": {
|
||||||
|
"type": "number",
|
||||||
|
"default": 0.5,
|
||||||
|
"description": "top margin of exported pdf, unit cm"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.margin.right": {
|
||||||
|
"type": "number",
|
||||||
|
"default": 0.5,
|
||||||
|
"description": "top margin of exported pdf, unit cm"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.margin.bottom": {
|
||||||
|
"type": "number",
|
||||||
|
"default": 0.5,
|
||||||
|
"description": "top margin of exported pdf, unit cm"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.margin.left": {
|
||||||
|
"type": "number",
|
||||||
|
"default": 0.5,
|
||||||
|
"description": "top margin of exported pdf, unit cm"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.headerTemplate": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "<div style=\"font-size: 9px; margin-left: 1cm;\"> <span class='title'></span></div> <div style=\"font-size: 9px; margin-left: auto; margin-right: 1cm; \"> <span class='date'></span></div>",
|
||||||
|
"description": "html template of header, if displayHeaderFooter is set to false, this setting will be ignored"
|
||||||
|
},
|
||||||
|
"function.doc.pdf.footerTemplate": {
|
||||||
|
"type": "string",
|
||||||
|
"default": "<div style=\"font-size: 9px; margin-left: 1cm;\"> <span class='title'></span></div> <div style=\"font-size: 9px; margin-left: auto; margin-right: 1cm; \"> <span class='date'></span></div>",
|
||||||
|
"description": "<div style=\"font-size: 9px; margin: 0 auto;\"> <span class='pageNumber'></span> / <span class='totalPages'></span></div>"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -42,8 +107,60 @@
|
|||||||
"command": "digital-ide.property-json.overwrite",
|
"command": "digital-ide.property-json.overwrite",
|
||||||
"title": "%digital-ide.property-json.overwrite.title%",
|
"title": "%digital-ide.property-json.overwrite.title%",
|
||||||
"category": "Digital-IDE"
|
"category": "Digital-IDE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "digital-ide.hdlDoc.exportFile",
|
||||||
|
"title": "%digital-ide.hdlDoc.exportFile.title%",
|
||||||
|
"category": "Digital-IDE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "digital-ide.hdlDoc.exportProject",
|
||||||
|
"title": "%digital-ide.hdlDoc.exportProject.title%",
|
||||||
|
"category": "Digital-IDE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "digital-ide.hdlDoc.showWebview",
|
||||||
|
"title": "%digital-ide.hdlDoc.showWebview.title%",
|
||||||
|
"category": "Digital-IDE",
|
||||||
|
"icon": {
|
||||||
|
"light": "images/svg/light/documentation.svg",
|
||||||
|
"dark": "images/svg/dark/documentation.svg"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "digital-ide.tool.instance",
|
||||||
|
"title": "%digital-ide.tool.instance.title%",
|
||||||
|
"category": "Digital-IDE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "digital-ide.tool.testbench",
|
||||||
|
"title": "%digital-ide.tool.testbench.title%",
|
||||||
|
"category": "Digital-IDE"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
"menus": {
|
||||||
|
"editor/title": [
|
||||||
|
{
|
||||||
|
"when": "editorLangId == verilog || editorLangId == systemverilog || editorLangId == vhdl",
|
||||||
|
"command": "digital-ide.hdlDoc.showWebview",
|
||||||
|
"group": "navigation@4"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"keybindings": [
|
||||||
|
{
|
||||||
|
"command": "digital-ide.tool.instance",
|
||||||
|
"key": "alt+i",
|
||||||
|
"mac": "alt+i",
|
||||||
|
"when": "editorTextFocus"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "digital-ide.tool.testbench",
|
||||||
|
"key": "alt+t",
|
||||||
|
"mac": "alt+t",
|
||||||
|
"when": "editorTextFocus"
|
||||||
|
}
|
||||||
|
],
|
||||||
"languages": [
|
"languages": [
|
||||||
{
|
{
|
||||||
"id": "tcl",
|
"id": "tcl",
|
||||||
@ -188,7 +305,128 @@
|
|||||||
"language": "systemverilog",
|
"language": "systemverilog",
|
||||||
"path": "snippets/svlog.json"
|
"path": "snippets/svlog.json"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"icons": {
|
||||||
|
"instance-verilog": {
|
||||||
|
"description": "icon of verilog in TOOL.instance",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e7a8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instance-vhdl": {
|
||||||
|
"description": "icon of verilog in TOOL.instance",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e6b3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instance-port": {
|
||||||
|
"description": "port of verilog in TOOL.instance",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e638"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instance-param": {
|
||||||
|
"description": "param of verilog in TOOL.instance",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e655"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instance-module": {
|
||||||
|
"description": "module of verilog in TOOL.instance",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e60b"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instance-input": {
|
||||||
|
"description": "input",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e908"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instance-output": {
|
||||||
|
"description": "output",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e7b0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"instance-inout": {
|
||||||
|
"description": "inout",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\ea19"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"export-html": {
|
||||||
|
"description": "export html",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e633"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"export-markdown": {
|
||||||
|
"description": "export markdown",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\ee68"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"export-pdf": {
|
||||||
|
"description": "export pdf",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e684"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libpick-folder": {
|
||||||
|
"description": "libpick folder",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e600"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libpick-verilog": {
|
||||||
|
"description": "libpick verilog",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e7a8"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libpick-vhdl": {
|
||||||
|
"description": "libpick vhdl",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e6b3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libpick-common": {
|
||||||
|
"description": "libpick common",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e622"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libpick-custom": {
|
||||||
|
"description": "libpick custom",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e623"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"libpick-unknown": {
|
||||||
|
"description": "libpick unknown",
|
||||||
|
"default": {
|
||||||
|
"fontPath": "./images/icons/iconfont.woff2",
|
||||||
|
"fontCharacter": "\\e62a"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"vscode:prepublish": "npm run compile",
|
"vscode:prepublish": "npm run compile",
|
||||||
@ -199,16 +437,25 @@
|
|||||||
"test": "node ./out/test/runTest.js"
|
"test": "node ./out/test/runTest.js"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@types/vscode": "^1.74.0",
|
|
||||||
"@types/glob": "^8.0.0",
|
"@types/glob": "^8.0.0",
|
||||||
"@types/mocha": "^10.0.0",
|
"@types/mocha": "^10.0.0",
|
||||||
"@types/node": "16.x",
|
"@types/node": "16.x",
|
||||||
|
"@types/showdown": "^2.0.0",
|
||||||
|
"@types/vscode": "^1.74.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^5.42.0",
|
"@typescript-eslint/eslint-plugin": "^5.42.0",
|
||||||
"@typescript-eslint/parser": "^5.42.0",
|
"@typescript-eslint/parser": "^5.42.0",
|
||||||
|
"@vscode/test-electron": "^2.2.0",
|
||||||
"eslint": "^8.26.0",
|
"eslint": "^8.26.0",
|
||||||
"glob": "^8.0.3",
|
"glob": "^8.0.3",
|
||||||
"mocha": "^10.1.0",
|
"mocha": "^10.1.0",
|
||||||
"typescript": "^4.8.4",
|
"typescript": "^4.8.4"
|
||||||
"@vscode/test-electron": "^2.2.0"
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"chokidar": "^3.5.3",
|
||||||
|
"puppeteer-core": "^19.4.1",
|
||||||
|
"showdown": "^2.1.0",
|
||||||
|
"state-machine-cat": "^9.2.5",
|
||||||
|
"temp": "^0.9.4",
|
||||||
|
"wavedrom": "^2.9.1"
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,4 +1,9 @@
|
|||||||
{
|
{
|
||||||
"digital-ide.property-json.generate.title": "generate property.json",
|
"digital-ide.property-json.generate.title": "generate property.json",
|
||||||
"digital-ide.property-json.overwrite.title": "overwrite property.json template"
|
"digital-ide.property-json.overwrite.title": "overwrite property.json template",
|
||||||
|
"digital-ide.hdlDoc.exportFile.title": "export the document of current file",
|
||||||
|
"digital-ide.hdlDoc.exportProject.title": "export the document of current project",
|
||||||
|
"digital-ide.hdlDoc.showWebview.title": "show the document of current file in a webview",
|
||||||
|
"digital-ide.tool.instance.title": "generate instance template from selected module",
|
||||||
|
"digital-ide.tool.testbench.title": "generate testbench template from current file"
|
||||||
}
|
}
|
@ -1,4 +1,9 @@
|
|||||||
{
|
{
|
||||||
"digital-ide.property-json.generate.title": "生成 property.json 配置文件",
|
"digital-ide.property-json.generate.title": "生成 property.json 配置文件",
|
||||||
"digital-ide.property-json.overwrite.title": "修改默认的 property.json 模板文件"
|
"digital-ide.property-json.overwrite.title": "修改默认的 property.json 模板文件",
|
||||||
|
"digital-ide.hdlDoc.exportFile.title": "导出当前文件的文档",
|
||||||
|
"digital-ide.hdlDoc.exportProject.title": "导出当前项目的文档",
|
||||||
|
"digital-ide.hdlDoc.showWebview.title": "在webview中展示文档",
|
||||||
|
"digital-ide.tool.instance.title": "生成选中module的例化模板",
|
||||||
|
"digital-ide.tool.testbench.title": "从当前文件中选择module生成testbench"
|
||||||
}
|
}
|
@ -1,4 +1,9 @@
|
|||||||
{
|
{
|
||||||
"digital-ide.property-json.generate.title": "",
|
"digital-ide.property-json.generate.title": "",
|
||||||
"digital-ide.property-json.overwrite.title": ""
|
"digital-ide.property-json.overwrite.title": "",
|
||||||
|
"digital-ide.hdlDoc.exportFile.title": "",
|
||||||
|
"digital-ide.hdlDoc.exportProject.title": "",
|
||||||
|
"digital-ide.hdlDoc.showWebview.title": "",
|
||||||
|
"digital-ide.tool.instance.title": "",
|
||||||
|
"digital-ide.tool.testbench.title": ""
|
||||||
}
|
}
|
@ -23,5 +23,9 @@ interface All {
|
|||||||
macro: Macro
|
macro: Macro
|
||||||
}
|
}
|
||||||
|
|
||||||
export function vlogFast(path: AbsPath): Promise<Fast>;
|
export function vlogFast(path: AbsPath): Promise<Fast | undefined>;
|
||||||
export function vlogAll(path: AbsPath): Promise<All>;
|
export function vlogAll(path: AbsPath): Promise<All | undefined>;
|
||||||
|
export function vhdlFast(path: AbsPath): Promise<Fast | undefined>;
|
||||||
|
export function vhdlAll(path: AbsPath): Promise<All | undefined>;
|
||||||
|
export function svFast(path: AbsPath): Promise<Fast | undefined>;
|
||||||
|
export function svAll(path: AbsPath): Promise<All | undefined>;
|
@ -1,4 +1,5 @@
|
|||||||
const hdlParser = require('./parser');
|
const hdlParser = require('./parser');
|
||||||
|
const fs = require('fs');
|
||||||
|
|
||||||
const _hdlParser = {
|
const _hdlParser = {
|
||||||
module: null,
|
module: null,
|
||||||
@ -17,22 +18,60 @@ const _hdlParser = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
async function vlogFast(path) {
|
async function vlogFast(path) {
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
const wasmModule = await _hdlParser.acquire();
|
const wasmModule = await _hdlParser.acquire();
|
||||||
const source = fs.readFileSync(path, 'utf-8');
|
const source = fs.readFileSync(path, 'utf-8') + '\n';
|
||||||
wasmModule.FS.writeFile(_hdlParser.tempPath, source, { encoding: 'utf8' });
|
wasmModule.FS.writeFile(_hdlParser.tempPath, source, { encoding: 'utf8' });
|
||||||
const res = wasmModule.ccall('vlog_fast', 'string', ['string'], [_hdlParser.tempPath]);
|
const res = wasmModule.ccall('vlog_fast', 'string', ['string'], [_hdlParser.tempPath]);
|
||||||
return JSON.parse(res);
|
return JSON.parse(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
async function vlogAll(path) {
|
async function vlogAll(path) {
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
const wasmModule = await _hdlParser.acquire();
|
const wasmModule = await _hdlParser.acquire();
|
||||||
const source = fs.readFileSync(path, 'utf-8');
|
const source = fs.readFileSync(path, 'utf-8') + '\n';
|
||||||
wasmModule.FS.writeFile(_hdlParser.tempPath, source, { encoding: 'utf8' });
|
wasmModule.FS.writeFile(_hdlParser.tempPath, source, { encoding: 'utf8' });
|
||||||
const res = wasmModule.ccall('vlog_all', 'string', ['string'], [_hdlParser.tempPath]);
|
const res = wasmModule.ccall('vlog_all', 'string', ['string'], [_hdlParser.tempPath]);
|
||||||
return JSON.parse(res);
|
return JSON.parse(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function vhdlFast(path) {
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function vhdlAll(path) {
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function svFast(path) {
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
async function svAll(path) {
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
vlogFast,
|
vlogFast,
|
||||||
vlogAll
|
vlogAll,
|
||||||
|
vhdlFast,
|
||||||
|
vhdlAll,
|
||||||
|
svFast,
|
||||||
|
svAll
|
||||||
};
|
};
|
7
resources/json5/index.d.ts
vendored
Normal file
7
resources/json5/index.d.ts
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
// It seems that webpack cannot package the json5 correctly
|
||||||
|
|
||||||
|
declare module JSON5 {
|
||||||
|
export function parse(text: string): any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export = JSON5;
|
1
resources/json5/index.js
Normal file
1
resources/json5/index.js
Normal file
File diff suppressed because one or more lines are too long
5
resources/wavedrom/index.d.ts
vendored
Normal file
5
resources/wavedrom/index.d.ts
vendored
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
declare module Wavedrom {
|
||||||
|
export function renderWaveDrom(id: number, json: any, style: any): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export = Wavedrom;
|
34
resources/wavedrom/index.js
Normal file
34
resources/wavedrom/index.js
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
const renderAny = require('wavedrom/lib/render-any');
|
||||||
|
const onmlStringify = require('onml/stringify.js');
|
||||||
|
const darkSkin = require('wavedrom/skins/dark');
|
||||||
|
const lightSkin = require('wavedrom/skins/default');
|
||||||
|
|
||||||
|
function selectSkin(skin) {
|
||||||
|
if (skin === 'dark') {
|
||||||
|
return darkSkin;
|
||||||
|
} else if (skin === 'light') {
|
||||||
|
return lightSkin;
|
||||||
|
}
|
||||||
|
return darkSkin;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {number} id
|
||||||
|
* @param {any} json
|
||||||
|
* @param {any} style 'dark' or 'light'
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function renderWaveDrom(id, json, style) {
|
||||||
|
const skin = selectSkin(style);
|
||||||
|
const renderObj = renderAny(id, json, skin);
|
||||||
|
const svgString = onmlStringify(renderObj);
|
||||||
|
return svgString;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Wavedrom = {
|
||||||
|
renderWaveDrom
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = Wavedrom;
|
@ -1,18 +1,30 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
import { opeParam } from './global';
|
import { opeParam, MainOutput, ReportType } from './global';
|
||||||
|
import { hdlParam } from './hdlParser';
|
||||||
import { prjManage } from './manager';
|
import { prjManage } from './manager';
|
||||||
import { hdlPath } from './hdlFs';
|
|
||||||
|
|
||||||
function launch(context: vscode.ExtensionContext) {
|
import { registerAllCommands } from './function';
|
||||||
|
|
||||||
|
async function registerCommand(context: vscode.ExtensionContext) {
|
||||||
|
registerAllCommands(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function launch(context: vscode.ExtensionContext) {
|
||||||
|
console.time('launch');
|
||||||
prjManage.initOpeParam(context);
|
prjManage.initOpeParam(context);
|
||||||
console.log(opeParam.prjInfo);
|
console.log(opeParam.prjInfo);
|
||||||
|
const hdlFiles = prjManage.getPrjHardwareFiles();
|
||||||
|
await hdlParam.initialize(hdlFiles);
|
||||||
|
console.timeLog('launch');
|
||||||
|
|
||||||
|
await registerCommand(context);
|
||||||
|
MainOutput.report('Digital-IDE has launched, version: 0.3.0');
|
||||||
|
MainOutput.report('OS: ' + opeParam.os);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export function activate(context: vscode.ExtensionContext) {
|
||||||
console.log('Digital-IDE 0.3.0 is launched');
|
|
||||||
launch(context);
|
launch(context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function deactivate() {}
|
export function deactivate() {}
|
372
src/function/hdlDoc/common.ts
Normal file
372
src/function/hdlDoc/common.ts
Normal file
@ -0,0 +1,372 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import * as assert from 'assert';
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as readline from 'readline';
|
||||||
|
|
||||||
|
import * as JSON5 from '../../../resources/json5';
|
||||||
|
import * as Wavedrom from '../../../resources/wavedrom';
|
||||||
|
import * as showdown from 'showdown';
|
||||||
|
|
||||||
|
import { ThemeType } from '../../global/enum';
|
||||||
|
import { MainOutput, ReportType } from '../../global';
|
||||||
|
|
||||||
|
const Count = {
|
||||||
|
svgMakeTimes: 0
|
||||||
|
};
|
||||||
|
|
||||||
|
const converter = new showdown.Converter({
|
||||||
|
tables : true,
|
||||||
|
literalMidWordUnderscores : true,
|
||||||
|
strikethrough : true,
|
||||||
|
simpleLineBreaks : true
|
||||||
|
});
|
||||||
|
|
||||||
|
enum MarkdownTag {
|
||||||
|
Title = '#',
|
||||||
|
Quote = '>',
|
||||||
|
Bold = '**',
|
||||||
|
Italic = '*',
|
||||||
|
InlineCode = '`',
|
||||||
|
UnorderedList = '-'
|
||||||
|
};
|
||||||
|
|
||||||
|
enum MarkdownAlign { Left, Center, Right };
|
||||||
|
enum RenderType { Wavedrom, Markdown };
|
||||||
|
|
||||||
|
function getAlignSpliter(align: MarkdownAlign): string {
|
||||||
|
switch (align) {
|
||||||
|
case MarkdownAlign.Left: return ':---';
|
||||||
|
case MarkdownAlign.Center: return ':---:';
|
||||||
|
case MarkdownAlign.Right: return '---:';
|
||||||
|
default: return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function joinString(...strings: string[]): string {
|
||||||
|
return strings.join(' ');
|
||||||
|
}
|
||||||
|
|
||||||
|
function catString(...strings: string[]): string {
|
||||||
|
return strings.join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
function getThemeColorKind(): ThemeType {
|
||||||
|
const currentColorKind = vscode.window.activeColorTheme.kind;
|
||||||
|
if (currentColorKind === vscode.ColorThemeKind.Dark ||
|
||||||
|
currentColorKind === vscode.ColorThemeKind.HighContrast) {
|
||||||
|
return ThemeType.Dark;
|
||||||
|
} else {
|
||||||
|
return ThemeType.Light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract class BaseDoc {
|
||||||
|
value: string;
|
||||||
|
constructor(value: string) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Text extends BaseDoc {
|
||||||
|
constructor(value: string) {
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Title extends BaseDoc {
|
||||||
|
level: number;
|
||||||
|
constructor(value: string, level: number) {
|
||||||
|
super(value);
|
||||||
|
this.level = level;
|
||||||
|
const prefix = MarkdownTag.Title.repeat(level);
|
||||||
|
this.value = joinString(prefix, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class UnorderedList {
|
||||||
|
value: string;
|
||||||
|
constructor(values: string[]) {
|
||||||
|
this.value = '';
|
||||||
|
for (const v of values) {
|
||||||
|
this.value += joinString(MarkdownTag.UnorderedList, v, '\n');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class OrderedList {
|
||||||
|
value: string = '';
|
||||||
|
constructor(values: string[]) {
|
||||||
|
values.forEach((v, i) => {
|
||||||
|
const id = i + 1;
|
||||||
|
this.value += joinString(id + '.', v, '\n');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Quote extends BaseDoc {
|
||||||
|
/**
|
||||||
|
* @description quote, tag > in markdown
|
||||||
|
* @param {string} value
|
||||||
|
*/
|
||||||
|
constructor(value: string) {
|
||||||
|
super(value);
|
||||||
|
this.value = joinString(MarkdownTag.Quote, value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Bold extends BaseDoc {
|
||||||
|
constructor(value: string) {
|
||||||
|
super(value);
|
||||||
|
this.value = catString(MarkdownTag.Bold, value, MarkdownTag.Bold);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Italic extends BaseDoc {
|
||||||
|
constructor(value: string) {
|
||||||
|
super(value);
|
||||||
|
this.value = catString(MarkdownTag.Italic, value, MarkdownTag.Italic);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class InlineCode extends BaseDoc {
|
||||||
|
constructor(value: string) {
|
||||||
|
super(value);
|
||||||
|
this.value = catString(MarkdownTag.InlineCode, value, MarkdownTag.InlineCode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class Split extends BaseDoc {
|
||||||
|
constructor() {
|
||||||
|
super('---');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class Table extends BaseDoc {
|
||||||
|
|
||||||
|
constructor(fieldNames: string[], rows: string[][], align: MarkdownAlign = MarkdownAlign.Left) {
|
||||||
|
const colNum = fieldNames.length;
|
||||||
|
const rowNum = rows.length;
|
||||||
|
const alignString = getAlignSpliter(align);
|
||||||
|
|
||||||
|
let value = catString('| ', fieldNames.join(' | '), ' |', '\n');
|
||||||
|
const alignUnit = catString('| ', alignString, ' ');
|
||||||
|
value += catString(alignUnit.repeat(colNum), '|', '\n');
|
||||||
|
for (let row = 0; row < rowNum; ++ row) {
|
||||||
|
const data = rows[row];
|
||||||
|
value += catString('| ', data.join(' | '), '|');
|
||||||
|
if (row < rowNum - 1) {
|
||||||
|
value += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super(value);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
abstract class RenderString {
|
||||||
|
line: number;
|
||||||
|
type: RenderType;
|
||||||
|
|
||||||
|
constructor(line: number, type: RenderType) {
|
||||||
|
this.line = line;
|
||||||
|
this.type = type;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract render(): string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface MarkdownStringValue {
|
||||||
|
tag: BaseDoc
|
||||||
|
end: string
|
||||||
|
};
|
||||||
|
|
||||||
|
class MarkdownString extends RenderString {
|
||||||
|
values: MarkdownStringValue[];
|
||||||
|
constructor(line: number) {
|
||||||
|
super(line, RenderType.Markdown);
|
||||||
|
this.values = [];
|
||||||
|
}
|
||||||
|
addText(value: string, end: string='\n') {
|
||||||
|
const tag = new Text(value);
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addTitle(value: string, level: number, end: string='\n') {
|
||||||
|
const tag = new Title(value, level);
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addQuote(value: string, end: string='\n') {
|
||||||
|
const tag = new Quote(value);
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addBold(value: string, end: string='\n') {
|
||||||
|
const tag = new Bold(value);
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addEnter() {
|
||||||
|
const tag = {value : ''};
|
||||||
|
const end = '\n';
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addItalic(value: string, end='\n') {
|
||||||
|
const tag = new Italic(value);
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addInlineCode(value: string, end='\n') {
|
||||||
|
const tag = new InlineCode(value);
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addUnorderedList(values: string[]) {
|
||||||
|
const end = '';
|
||||||
|
const tag = new UnorderedList(values);
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addOrderedList(values: string[]) {
|
||||||
|
const end = '';
|
||||||
|
const tag = new OrderedList(values);
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addSplit(value: string) {
|
||||||
|
const end = '\n';
|
||||||
|
const tag = new Split();
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
addTable(fieldNames: string[], rows: string[][], align=MarkdownAlign.Left, end='\n') {
|
||||||
|
const tag = new Table(fieldNames, rows, align);
|
||||||
|
this.values.push({tag, end});
|
||||||
|
}
|
||||||
|
renderMarkdown() {
|
||||||
|
let markdown = '';
|
||||||
|
for (const md of this.values) {
|
||||||
|
markdown += md.tag.value + md.end;
|
||||||
|
}
|
||||||
|
return markdown;
|
||||||
|
}
|
||||||
|
render() {
|
||||||
|
const rawMD = this.renderMarkdown();
|
||||||
|
return converter.makeHtml(rawMD);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class WavedromString extends RenderString {
|
||||||
|
value: string;
|
||||||
|
desc: string;
|
||||||
|
|
||||||
|
constructor(line: number, desc: string) {
|
||||||
|
super(line, RenderType.Wavedrom);
|
||||||
|
this.value = '';
|
||||||
|
this.desc = desc;
|
||||||
|
}
|
||||||
|
add(text: string) {
|
||||||
|
this.value += text;
|
||||||
|
}
|
||||||
|
render(): string {
|
||||||
|
const style = getThemeColorKind();
|
||||||
|
return makeWaveDromSVG(this.value, style);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function parseJson5(text: string): any {
|
||||||
|
let json = null;
|
||||||
|
try {
|
||||||
|
json = JSON5.parse(text);
|
||||||
|
} catch (error) {
|
||||||
|
MainOutput.report('error happen when parse json ', ReportType.Error);
|
||||||
|
MainOutput.report(error, ReportType.Error);
|
||||||
|
}
|
||||||
|
return json;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function makeWaveDromSVG(wavedromComment: string, style: ThemeType): string {
|
||||||
|
const json = parseJson5(wavedromComment);
|
||||||
|
try {
|
||||||
|
if (!json) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const svgString = Wavedrom.renderWaveDrom(Count.svgMakeTimes, json, style);
|
||||||
|
Count.svgMakeTimes += 1;
|
||||||
|
return svgString;
|
||||||
|
} catch (error) {
|
||||||
|
MainOutput.report('error happen when render ' + wavedromComment, ReportType.Error);
|
||||||
|
MainOutput.report(error, ReportType.Error);
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* extract wavedrom comment from hdl file
|
||||||
|
* @param path
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
|
async function getWavedromsFromFile(path: string): Promise<WavedromString[] | undefined> {
|
||||||
|
let lineID = 0;
|
||||||
|
let findWavedrom = false;
|
||||||
|
const wavedroms: WavedromString[] = [];
|
||||||
|
|
||||||
|
const fileStream = fs.createReadStream(path, 'utf-8');
|
||||||
|
const rl = readline.createInterface({
|
||||||
|
input: fileStream,
|
||||||
|
crlfDelay: Infinity
|
||||||
|
});
|
||||||
|
|
||||||
|
for await (const line of rl) {
|
||||||
|
lineID += 1;
|
||||||
|
if (findWavedrom) {
|
||||||
|
if (/\*\//g.test(line)) {
|
||||||
|
findWavedrom = false;
|
||||||
|
} else {
|
||||||
|
const currentWav = wavedroms[wavedroms.length - 1];
|
||||||
|
currentWav.add(line.trim());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (/\/\*[\s\S]*(@wavedrom)/g.test(line)) {
|
||||||
|
findWavedrom = true;
|
||||||
|
let spliters = line.trim().split('@wavedrom');
|
||||||
|
let desc = spliters[spliters.length - 1];
|
||||||
|
const newWavedrom = new WavedromString(lineID, desc);
|
||||||
|
wavedroms.push(newWavedrom);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return wavedroms;
|
||||||
|
}
|
||||||
|
|
||||||
|
function mergeSortByLine(docs: MarkdownString[], svgs: WavedromString[]): RenderString[] {
|
||||||
|
const renderList = [];
|
||||||
|
let i = 0, j = 0;
|
||||||
|
while (i < docs.length && j < svgs.length) {
|
||||||
|
if (docs[i].line < svgs[j].line) {
|
||||||
|
renderList.push(docs[i]);
|
||||||
|
i ++;
|
||||||
|
} else {
|
||||||
|
renderList.push(svgs[j]);
|
||||||
|
j ++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
while (i < docs.length) {
|
||||||
|
renderList.push(docs[i]);
|
||||||
|
i ++;
|
||||||
|
}
|
||||||
|
while (j < svgs.length) {
|
||||||
|
renderList.push(svgs[j]);
|
||||||
|
j ++;
|
||||||
|
}
|
||||||
|
return renderList;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
converter,
|
||||||
|
mergeSortByLine,
|
||||||
|
RenderType,
|
||||||
|
BaseDoc,
|
||||||
|
MarkdownString,
|
||||||
|
WavedromString,
|
||||||
|
RenderString,
|
||||||
|
makeWaveDromSVG,
|
||||||
|
getWavedromsFromFile,
|
||||||
|
Count
|
||||||
|
};
|
227
src/function/hdlDoc/html.ts
Normal file
227
src/function/hdlDoc/html.ts
Normal file
@ -0,0 +1,227 @@
|
|||||||
|
import * as assert from 'assert';
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
import { opeParam, MainOutput, AbsPath } from '../../global';
|
||||||
|
|
||||||
|
import { Count, MarkdownString, WavedromString } from './common';
|
||||||
|
import { getRenderList, getCurrentRenderList } from './markdown';
|
||||||
|
import { hdlPath, hdlIcon, hdlFile } from '../../hdlFs';
|
||||||
|
|
||||||
|
const _cache = {
|
||||||
|
css : ''
|
||||||
|
};
|
||||||
|
|
||||||
|
function makeFinalHTML(body: string, style: string): string {
|
||||||
|
return `<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<div id="write">
|
||||||
|
${body}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
<style>
|
||||||
|
${style}
|
||||||
|
</style>
|
||||||
|
</html>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function makeExportHTML(cssHref: string, body: string): string {
|
||||||
|
return `<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Document</title>
|
||||||
|
<link rel="stylesheet" type="text/css" href="${cssHref}"></link>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="wrapper">
|
||||||
|
<div id="write">
|
||||||
|
${body}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeCommonElement(renderResult: string): string {
|
||||||
|
return renderResult + '<br>\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeSVGElement(renderResult: string, caption: string): string {
|
||||||
|
let mainHtml;
|
||||||
|
if (caption) {
|
||||||
|
mainHtml = '<div align=center>' + renderResult + `<p class="ImgCaption">${caption}</p>` + '</div>';
|
||||||
|
} else {
|
||||||
|
mainHtml = '<div align=center>' + renderResult + '</div>';
|
||||||
|
}
|
||||||
|
return '<br>' + mainHtml + '<br><br>\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
function makeSVGElementByLink(link: AbsPath, caption: string): 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 getDocCssString() {
|
||||||
|
if (_cache.css) {
|
||||||
|
return _cache.css;
|
||||||
|
} else {
|
||||||
|
const cssPath = hdlPath.join(opeParam.extensionPath, 'css/documentation.css');
|
||||||
|
const cssString = fs.readFileSync(cssPath, 'utf-8');
|
||||||
|
_cache.css = cssString;
|
||||||
|
return cssString;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function makeWavedromRenderErrorHTML() {
|
||||||
|
return `<div class="error-out">
|
||||||
|
<p class="error">Error Render</p>
|
||||||
|
</div><br>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description make the html string of a finial display style
|
||||||
|
* @param usage in whick module is used
|
||||||
|
*/
|
||||||
|
async function makeShowHTML(usage: string): Promise<string> {
|
||||||
|
const renderList = await getCurrentRenderList();
|
||||||
|
if (!renderList || renderList.length === 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
// start to render the real html
|
||||||
|
let body = '';
|
||||||
|
for (const r of renderList) {
|
||||||
|
const renderResult = r.render();
|
||||||
|
if (renderResult) {
|
||||||
|
if (r instanceof MarkdownString) {
|
||||||
|
body += makeCommonElement(renderResult);
|
||||||
|
} else if (r instanceof WavedromString) {
|
||||||
|
body += makeSVGElement(renderResult, r.desc);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
body += makeWavedromRenderErrorHTML();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add css
|
||||||
|
let cssString = getDocCssString();
|
||||||
|
if (usage === 'webview') { // if invoked by webview, change background image
|
||||||
|
const webviewConfig = vscode.workspace.getConfiguration("function.doc.webview");
|
||||||
|
const imageUrl = webviewConfig.get('backgroundImage', '');
|
||||||
|
cssString = cssString.replace("--backgroundImage", imageUrl);
|
||||||
|
} else if (usage === 'pdf') { // if invoked by pdf, transform .vscode-light to #write
|
||||||
|
cssString = cssString.replace(/\.vscode-light/g, '#write');
|
||||||
|
}
|
||||||
|
const html = makeFinalHTML(body, cssString);
|
||||||
|
return html;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function showDocWebview() {
|
||||||
|
const htmlPromise = makeShowHTML("webview");
|
||||||
|
const webview = vscode.window.createWebviewPanel(
|
||||||
|
'TOOL.doc.webview.show',
|
||||||
|
'document',
|
||||||
|
vscode.ViewColumn.Two,
|
||||||
|
{
|
||||||
|
enableScripts: true, // enable JS
|
||||||
|
retainContextWhenHidden: true, // unchange webview when hidden, prevent extra refresh
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
webview.iconPath = hdlIcon.getIconConfig('documentation');
|
||||||
|
webview.webview.html = await htmlPromise;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function exportCurrentFileDocAsHTML() {
|
||||||
|
if (vscode.window.activeColorTheme.kind !== vscode.ColorThemeKind.Light) {
|
||||||
|
vscode.window.showErrorMessage('Please export html in a light theme!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
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, 'html');
|
||||||
|
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);
|
||||||
|
|
||||||
|
const cssFolder = hdlPath.join(currentRoot, 'css');
|
||||||
|
fs.mkdirSync(cssFolder);
|
||||||
|
const relateCssPath = './css/index.css';
|
||||||
|
const cssPath = hdlPath.join(cssFolder, 'index.css');
|
||||||
|
let cssString = getDocCssString();
|
||||||
|
|
||||||
|
// only support export in the ligth theme
|
||||||
|
cssString = cssString.replace(/\.vscode-light/g, '#write');
|
||||||
|
fs.writeFileSync(cssPath, cssString);
|
||||||
|
|
||||||
|
let body = '';
|
||||||
|
for (const r of renderList) {
|
||||||
|
const renderResult = r.render();
|
||||||
|
if (r instanceof MarkdownString) {
|
||||||
|
body += makeCommonElement(renderResult);
|
||||||
|
} else if (r instanceof WavedromString) {
|
||||||
|
const svgName = 'wavedrom-' + Count.svgMakeTimes + '.svg';
|
||||||
|
const svgPath = hdlPath.join(figureFolder, svgName);
|
||||||
|
fs.writeFileSync(svgPath, renderResult);
|
||||||
|
const relatePath = hdlPath.join('./figure', svgName);
|
||||||
|
body += makeSVGElementByLink(relatePath, r.desc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const html = makeExportHTML(relateCssPath, body);
|
||||||
|
const htmlName = 'index.html';
|
||||||
|
const htmlPath = hdlPath.join(currentRoot, htmlName);
|
||||||
|
Count.svgMakeTimes = 0;
|
||||||
|
fs.writeFileSync(htmlPath, html);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exportProjectDocAsHTML() {
|
||||||
|
vscode.window.showInformationMessage('this is exportProjectDocAsHTML');
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
showDocWebview,
|
||||||
|
exportCurrentFileDocAsHTML,
|
||||||
|
exportProjectDocAsHTML,
|
||||||
|
makeShowHTML,
|
||||||
|
makeSVGElementByLink
|
||||||
|
};
|
70
src/function/hdlDoc/index.ts
Normal file
70
src/function/hdlDoc/index.ts
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
import { hdlIcon } from "../../hdlFs";
|
||||||
|
import { exportCurrentFileDocAsMarkdown, exportProjectDocAsMarkdown } from './markdown';
|
||||||
|
import { exportCurrentFileDocAsHTML, exportProjectDocAsHTML, showDocWebview } from './html';
|
||||||
|
import { exportCurrentFileDocAsPDF, exportProjectDocAsPDF } from './pdf';
|
||||||
|
|
||||||
|
const availableFormat = [
|
||||||
|
'markdown', 'pdf', 'html'
|
||||||
|
];
|
||||||
|
|
||||||
|
class ExportFunctionItem {
|
||||||
|
label: string;
|
||||||
|
format: string;
|
||||||
|
exportFunc: Function;
|
||||||
|
detail: string;
|
||||||
|
|
||||||
|
constructor(format: string, title: string, detail: string, exportFunc: Function) {
|
||||||
|
// TODO : 等到sv的解析做好后,写入对于不同hdl的图标
|
||||||
|
let iconID = '$(export-' + format + ') ';
|
||||||
|
this.label = iconID + title;
|
||||||
|
this.format = format;
|
||||||
|
this.exportFunc = exportFunc;
|
||||||
|
this.detail = detail;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function registerFileDocExport(context: vscode.ExtensionContext) {
|
||||||
|
vscode.commands.registerCommand('digital-ide.hdlDoc.exportFile', () => {
|
||||||
|
const option = {
|
||||||
|
placeHolder: 'Select an Export Format'
|
||||||
|
};
|
||||||
|
const items = [
|
||||||
|
new ExportFunctionItem('markdown', ' markdown', 'export markdown folder', exportCurrentFileDocAsMarkdown),
|
||||||
|
new ExportFunctionItem('pdf', ' pdf', 'only support light theme', exportCurrentFileDocAsPDF),
|
||||||
|
new ExportFunctionItem('html', ' html', 'only support light theme', exportCurrentFileDocAsHTML)
|
||||||
|
];
|
||||||
|
|
||||||
|
vscode.window.showQuickPick(items, option).then(item => {
|
||||||
|
if (item) {
|
||||||
|
item.exportFunc();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerProjectDocExport(context: vscode.ExtensionContext) {
|
||||||
|
vscode.commands.registerCommand('digital-ide.hdlDoc.exportProject', () => {
|
||||||
|
const option = {
|
||||||
|
placeHolder: 'Select an Export Format'
|
||||||
|
};
|
||||||
|
const items = [
|
||||||
|
new ExportFunctionItem('markdown',' markdown', 'export markdown folder', exportProjectDocAsMarkdown),
|
||||||
|
new ExportFunctionItem('pdf', ' pdf', 'only support light theme', exportProjectDocAsPDF),
|
||||||
|
new ExportFunctionItem('html', ' html', 'only support light theme', exportProjectDocAsHTML)
|
||||||
|
];
|
||||||
|
|
||||||
|
vscode.window.showQuickPick(items, option).then(item => {
|
||||||
|
if (item) {
|
||||||
|
item.exportFunc();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
registerFileDocExport,
|
||||||
|
registerProjectDocExport,
|
||||||
|
showDocWebview
|
||||||
|
};
|
252
src/function/hdlDoc/markdown.ts
Normal file
252
src/function/hdlDoc/markdown.ts
Normal file
@ -0,0 +1,252 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
|
||||||
|
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';
|
||||||
|
|
||||||
|
|
||||||
|
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 makeTableFromObjArray(md: MarkdownString, array: any[], name: string, fieldNames: string[], displayNames: string[]) {
|
||||||
|
const ws = hdlPath.toSlash(opeParam.workspacePath) + '/';
|
||||||
|
if (array.length === 0) {
|
||||||
|
md.addText(`no ${name} info`);
|
||||||
|
} else {
|
||||||
|
const rows = [];
|
||||||
|
for (const obj of array) {
|
||||||
|
const data = [];
|
||||||
|
for (const name of fieldNames) {
|
||||||
|
let value = obj[name];
|
||||||
|
if (name === 'instModPath' && value) {
|
||||||
|
value = value.replace(ws, '');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (value && value.trim().length === 0) {
|
||||||
|
value = ' ';
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
for (let i = 0; i < ports.length; ++ i) {
|
||||||
|
const inlineComment = comments[i].replace(/\n/, ' ');
|
||||||
|
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);
|
||||||
|
// add module name
|
||||||
|
md.addTitle(moduleName, 1);
|
||||||
|
md.addTitle('Basic Info', 2);
|
||||||
|
const infos = [
|
||||||
|
`${portNum} params, ${paramNum} ports`,
|
||||||
|
'top module ' + topModuleDesc
|
||||||
|
];
|
||||||
|
md.addUnorderedList(infos);
|
||||||
|
md.addEnter();
|
||||||
|
|
||||||
|
// wait param and port patch
|
||||||
|
await paramPP;
|
||||||
|
await portPP;
|
||||||
|
|
||||||
|
// param section
|
||||||
|
md.addTitle('params', 2);
|
||||||
|
makeTableFromObjArray(md, module.params, 'params',
|
||||||
|
['name', 'init', 'desc'],
|
||||||
|
['name', 'init', 'description']);
|
||||||
|
md.addEnter();
|
||||||
|
|
||||||
|
|
||||||
|
// port section
|
||||||
|
md.addTitle('ports', 2);
|
||||||
|
makeTableFromObjArray(md, module.ports, 'ports',
|
||||||
|
['name', 'type', 'width', 'desc'],
|
||||||
|
['name', 'type', 'width', '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);
|
||||||
|
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
|
||||||
|
};
|
115
src/function/hdlDoc/pdf.ts
Normal file
115
src/function/hdlDoc/pdf.ts
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as puppeteer from 'puppeteer-core';
|
||||||
|
|
||||||
|
import { makeShowHTML } from './html';
|
||||||
|
import { hdlFile, hdlPath } from '../../hdlFs';
|
||||||
|
import { AbsPath, MainOutput, opeParam, ReportType } from '../../global';
|
||||||
|
|
||||||
|
// TODO : finish it in each platform
|
||||||
|
function getDefaultBrowerPath(): AbsPath {
|
||||||
|
switch (opeParam.os) {
|
||||||
|
case 'win32': return 'C:/Program Files (x86)/Microsoft/Edge/Application/msedge.exe';
|
||||||
|
case 'linux': return '';
|
||||||
|
default: return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description transform a html file to pdf file
|
||||||
|
* @param htmlPath absolute path of input html
|
||||||
|
* @param pdfPath output path of pdf
|
||||||
|
*/
|
||||||
|
async function htmlFile2PdfFile(htmlPath: AbsPath, pdfPath: AbsPath) {
|
||||||
|
const pdfConfig = vscode.workspace.getConfiguration("function.doc.pdf");
|
||||||
|
const platformDefaultBrowerPath = getDefaultBrowerPath();
|
||||||
|
const browserPath = pdfConfig.get('browserPath', platformDefaultBrowerPath);
|
||||||
|
|
||||||
|
if (!fs.existsSync(browserPath)) {
|
||||||
|
vscode.window.showErrorMessage("Path " + browserPath + " is not a valid browser path!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const browser = await puppeteer.launch({
|
||||||
|
executablePath: browserPath,
|
||||||
|
args: ['--lang=' + vscode.env.language, '--no-sandbox', '--disable-setuid-sandbox']
|
||||||
|
});
|
||||||
|
|
||||||
|
const page = await browser.newPage();
|
||||||
|
const uriFilePath = vscode.Uri.file(htmlPath).toString();
|
||||||
|
|
||||||
|
await page.goto(uriFilePath, { waitUntil: 'networkidle0' });
|
||||||
|
|
||||||
|
const options = {
|
||||||
|
path: pdfPath,
|
||||||
|
scale: pdfConfig.scale,
|
||||||
|
displayHeaderFooter: pdfConfig.displayHeaderFooter,
|
||||||
|
headerTemplate: pdfConfig.headerTemplate,
|
||||||
|
footerTemplate: pdfConfig.footerTemplate,
|
||||||
|
printBackground: pdfConfig.printBackground,
|
||||||
|
landscape: pdfConfig.landscape,
|
||||||
|
format: pdfConfig.format,
|
||||||
|
margin: {
|
||||||
|
top: pdfConfig.margin.top + 'cm',
|
||||||
|
right: pdfConfig.margin.right + 'cm',
|
||||||
|
bottom: pdfConfig.margin.bottom + 'cm',
|
||||||
|
left: pdfConfig.margin.left + 'cm'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
await page.pdf(options);
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
async function exportCurrentFileDocAsPDF() {
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (!editor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentFilePath = hdlPath.toSlash(editor.document.fileName);
|
||||||
|
const hdlFileName = hdlPath.basename(currentFilePath);
|
||||||
|
const wsPath = opeParam.workspacePath;
|
||||||
|
|
||||||
|
return vscode.window.withProgress({
|
||||||
|
location: vscode.ProgressLocation.Notification,
|
||||||
|
title: '[Digital-IDE]: Export ' + currentFilePath + '...'
|
||||||
|
}, async progress => {
|
||||||
|
try {
|
||||||
|
const html = await makeShowHTML("pdf");
|
||||||
|
|
||||||
|
if (!html) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const pdfFolderPath = hdlPath.join(wsPath, 'pdf');
|
||||||
|
if (!fs.existsSync(pdfFolderPath)) {
|
||||||
|
fs.mkdirSync(pdfFolderPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const pdfName = hdlFileName + '.pdf';
|
||||||
|
const pdfPath = hdlPath.join(pdfFolderPath, pdfName);
|
||||||
|
if (fs.existsSync(pdfPath)) {
|
||||||
|
hdlFile.rmSync(pdfPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tempHtmlName = hdlFileName + '.tmp.html';
|
||||||
|
const tempHtmlPath = hdlPath.join(pdfFolderPath, tempHtmlName);
|
||||||
|
if (fs.existsSync(tempHtmlPath)) {
|
||||||
|
hdlFile.rmSync(tempHtmlPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
fs.writeFileSync(tempHtmlPath, html);
|
||||||
|
await htmlFile2PdfFile(tempHtmlPath, pdfPath);
|
||||||
|
hdlFile.rmSync(tempHtmlPath);
|
||||||
|
} catch (error) {
|
||||||
|
MainOutput.report("error happen in export pdf: " + error, ReportType.Error);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function exportProjectDocAsPDF() {
|
||||||
|
vscode.window.showInformationMessage('this is exportProjectDocAsPDF');
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
exportCurrentFileDocAsPDF,
|
||||||
|
exportProjectDocAsPDF
|
||||||
|
};
|
26
src/function/index.ts
Normal file
26
src/function/index.ts
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
import * as hdlDoc from './hdlDoc';
|
||||||
|
import * as Sim from './sim';
|
||||||
|
|
||||||
|
function registerDocumentation(context: vscode.ExtensionContext) {
|
||||||
|
vscode.commands.registerCommand('digital-ide.hdlDoc.showWebview', hdlDoc.showDocWebview);
|
||||||
|
hdlDoc.registerFileDocExport(context);
|
||||||
|
hdlDoc.registerProjectDocExport(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function registerSimulation(context: vscode.ExtensionContext) {
|
||||||
|
vscode.commands.registerCommand('digital-ide.tool.instance', Sim.instantiation);
|
||||||
|
vscode.commands.registerCommand('digital-ide.tool.testbench', Sim.testbench);
|
||||||
|
}
|
||||||
|
|
||||||
|
function registerAllCommands(context: vscode.ExtensionContext) {
|
||||||
|
registerDocumentation(context);
|
||||||
|
registerSimulation(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
registerAllCommands
|
||||||
|
};
|
203
src/function/lsp/util/completion.js
Normal file
203
src/function/lsp/util/completion.js
Normal file
@ -0,0 +1,203 @@
|
|||||||
|
const vscode = require('vscode');
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
|
||||||
|
const HDLPath = require('../../../HDLfilesys/operation/path');
|
||||||
|
const { HDLParam, Module, SymbolResult, Instance } = require('../../../HDLparser');
|
||||||
|
const { positionAfterEqual } = require('./index');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} folderPath
|
||||||
|
* @param {string} currentPath
|
||||||
|
* @returns {Array<vscode.CompletionItem>}
|
||||||
|
*/
|
||||||
|
function filterIncludeFiles(folderPath, currentPath) {
|
||||||
|
if (fs.existsSync(folderPath)) {
|
||||||
|
const suggestFiles = [];
|
||||||
|
for (const fileName of fs.readdirSync(folderPath)) {
|
||||||
|
const filePath = HDLPath.join(folderPath, fileName);
|
||||||
|
if (filePath == currentPath) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const stat = fs.statSync(filePath);
|
||||||
|
const clItem = new vscode.CompletionItem(fileName);
|
||||||
|
if (stat.isDirectory()) {
|
||||||
|
clItem.kind = vscode.CompletionItemKind.Folder;
|
||||||
|
} else if (stat.isFile()) {
|
||||||
|
clItem.kind = vscode.CompletionItemKind.File;
|
||||||
|
}
|
||||||
|
suggestFiles.push(clItem);
|
||||||
|
}
|
||||||
|
return suggestFiles;
|
||||||
|
}
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {vscode.TextDocument} document
|
||||||
|
* @param {vscode.Position} position
|
||||||
|
* @returns {Array<vscode.CompletionItem>}
|
||||||
|
*/
|
||||||
|
function provideIncludeFiles(document, position) {
|
||||||
|
if (position.character == 0) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const filePath = HDLPath.toSlash(document.fileName);
|
||||||
|
const lineText = document.lineAt(position).text;
|
||||||
|
|
||||||
|
let firstQIndex = lineText.lastIndexOf('"', position.character - 1);
|
||||||
|
let lastQIndex = lineText.indexOf('"', position.character);
|
||||||
|
|
||||||
|
if (firstQIndex != -1 && lastQIndex != -1) {
|
||||||
|
const currentPath = lineText.substring(firstQIndex + 1, lastQIndex);
|
||||||
|
const folderName = currentPath.length == 0 ? '.' : currentPath;
|
||||||
|
const folderAbsPath = HDLPath.rel2abs(filePath, folderName);
|
||||||
|
return filterIncludeFiles(folderAbsPath, filePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} singleWord
|
||||||
|
* @param {object} defines
|
||||||
|
* @returns {Promise<Array<vscode.CompletionItem>>}
|
||||||
|
*/
|
||||||
|
function provideMacros(singleWord, defines) {
|
||||||
|
const suggestMacros = [];
|
||||||
|
if (!defines) {
|
||||||
|
return suggestMacros;
|
||||||
|
}
|
||||||
|
for (const macro of Object.keys(defines)) {
|
||||||
|
const value = defines[macro].value;
|
||||||
|
const name = '`' + macro;
|
||||||
|
const clItem = new vscode.CompletionItem('`' + macro, vscode.CompletionItemKind.Constant)
|
||||||
|
clItem.detail = 'macro ' + value;
|
||||||
|
if (singleWord[0] == '`') {
|
||||||
|
clItem.insertText = macro;
|
||||||
|
} else {
|
||||||
|
clItem.insertText = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
suggestMacros.push(clItem);
|
||||||
|
}
|
||||||
|
return suggestMacros;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {vscode.Position} position cursor position
|
||||||
|
* @param {Instance} currentInst
|
||||||
|
* @returns {Promise<Array<vscode.CompletionItem>>}
|
||||||
|
*/
|
||||||
|
function providePositionPorts(position, currentInst) {
|
||||||
|
const params = currentInst.instparams;
|
||||||
|
const ports = currentInst.instports;
|
||||||
|
console.log(position);
|
||||||
|
console.log(params);
|
||||||
|
console.log(ports);
|
||||||
|
|
||||||
|
if (params &&
|
||||||
|
positionAfterEqual(position, params.start) &&
|
||||||
|
positionAfterEqual(params.end, position)) {
|
||||||
|
|
||||||
|
return currentInst.module.params.map(param => {
|
||||||
|
const clItem = new vscode.CompletionItem(param.name, vscode.CompletionItemKind.Constant);
|
||||||
|
clItem.detail = 'param';
|
||||||
|
return clItem;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
if (ports &&
|
||||||
|
positionAfterEqual(position, ports.start) &&
|
||||||
|
positionAfterEqual(ports.end, position)) {
|
||||||
|
|
||||||
|
return currentInst.module.ports.map(port => {
|
||||||
|
const clItem = new vscode.CompletionItem(port.name, vscode.CompletionItemKind.Interface);
|
||||||
|
clItem.detail = 'port';
|
||||||
|
return clItem;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description provide module of the current module and include module
|
||||||
|
* @param {string} filePath
|
||||||
|
* @param {object} includes {path: range}
|
||||||
|
* @returns {Promise<Array<vscode.CompletionItem>>}
|
||||||
|
*/
|
||||||
|
async function provideModules(filePath, includes) {
|
||||||
|
// support include of all the module
|
||||||
|
// use command property to auto add include path
|
||||||
|
const suggestModules = [];
|
||||||
|
|
||||||
|
if (!includes) {
|
||||||
|
return suggestModules;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const module of HDLParam.getAllModules()) {
|
||||||
|
const clItem = new vscode.CompletionItem(module.name, vscode.CompletionItemKind.Class);
|
||||||
|
clItem.detail = 'module';
|
||||||
|
suggestModules.push(clItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
return suggestModules;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Module} module
|
||||||
|
* @returns {Promise<Array<vscode.CompletionItem>>}
|
||||||
|
*/
|
||||||
|
async function provideParamsPorts(module) {
|
||||||
|
if (!module) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const suggestParamsPorts = [];
|
||||||
|
for (const param of module.params) {
|
||||||
|
const clItem = new vscode.CompletionItem(param.name, vscode.CompletionItemKind.Constant);
|
||||||
|
clItem.detail = 'param';
|
||||||
|
suggestParamsPorts.push(clItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const port of module.ports) {
|
||||||
|
const clItem = new vscode.CompletionItem(port.name, vscode.CompletionItemKind.Interface);
|
||||||
|
clItem.detail = 'port';
|
||||||
|
suggestParamsPorts.push(clItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
return suggestParamsPorts;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Array<SymbolResult>} symbols
|
||||||
|
* @returns {Promise<Array<vscode.CompletionItem>>}
|
||||||
|
*/
|
||||||
|
async function provideNets(symbols) {
|
||||||
|
if (!symbols) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
const suggestNets = [];
|
||||||
|
for (const symbol of symbols) {
|
||||||
|
if (symbol.type == 'net') {
|
||||||
|
const clItem = new vscode.CompletionItem(symbol.name, vscode.CompletionItemKind.Variable);
|
||||||
|
clItem.detail = 'net';
|
||||||
|
suggestNets.push(clItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return suggestNets;
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
provideIncludeFiles,
|
||||||
|
provideMacros,
|
||||||
|
providePositionPorts,
|
||||||
|
provideModules,
|
||||||
|
provideParamsPorts,
|
||||||
|
provideNets
|
||||||
|
};
|
321
src/function/lsp/util/feature.ts
Normal file
321
src/function/lsp/util/feature.ts
Normal file
@ -0,0 +1,321 @@
|
|||||||
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import { AbsPath } from '../../../global';
|
||||||
|
import { HdlLangID } from '../../../global/enum';
|
||||||
|
import { hdlPath, hdlFile } from '../../../hdlFs';
|
||||||
|
import { Range } from '../../../hdlParser/common';
|
||||||
|
|
||||||
|
const vlogNumberReg = {
|
||||||
|
'h' : /[0-9]+?'h([0-9a-fA-F_]+)/g,
|
||||||
|
'b' : /[0-9]+?'b([0-1_]+)/g,
|
||||||
|
'o' : /[0-9]+?'o([0-7_]+)/g,
|
||||||
|
};
|
||||||
|
|
||||||
|
const vhdlNumberReg = {
|
||||||
|
'h' : /x"([0-9a-fA-F_]+)"/g,
|
||||||
|
'b' : /([0-1_]+)"/g,
|
||||||
|
};
|
||||||
|
|
||||||
|
interface vlogNumber {
|
||||||
|
unsigned: number
|
||||||
|
signed: number
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description recognize and transfer number
|
||||||
|
* @param lineText
|
||||||
|
* @param character
|
||||||
|
*/
|
||||||
|
function transferVlogNumber(lineText: string, character: number): vlogNumber | undefined {
|
||||||
|
let numberReg = /[0-9]/;
|
||||||
|
let opt = null;
|
||||||
|
let numberString = null;
|
||||||
|
|
||||||
|
if (numberReg.test(lineText[character])) {
|
||||||
|
const leftPart = [];
|
||||||
|
const rightPart = [];
|
||||||
|
const length = lineText.length;
|
||||||
|
for (let i = character - 1; i >= 0; -- i) {
|
||||||
|
const ch = lineText[i];
|
||||||
|
if (numberReg.test(ch)) {
|
||||||
|
leftPart.push(ch);
|
||||||
|
} else if (Object.keys(vlogNumberReg).includes(ch)) {
|
||||||
|
if (i === 0) {
|
||||||
|
return undefined;
|
||||||
|
} else if (lineText[i - 1] === "'") {
|
||||||
|
opt = ch;
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = character + 1; i < length; ++ i) {
|
||||||
|
const ch = lineText[i];
|
||||||
|
if (numberReg.test(ch)) {
|
||||||
|
rightPart.push(ch);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftWord = leftPart.reverse().join('');
|
||||||
|
const rightWord = rightPart.join('');
|
||||||
|
numberString = leftWord + lineText[character] + rightWord;
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (opt && numberString) {
|
||||||
|
return string2num(numberString, opt);
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 将数字字符串转数字(包括有符号与无符号)
|
||||||
|
* @param str 数字字符串
|
||||||
|
* @param opt 需要转换的进制 hex | bin | oct
|
||||||
|
*/
|
||||||
|
function string2num(str: string, opt: string): vlogNumber {
|
||||||
|
let optNumber = -1;
|
||||||
|
switch (opt) {
|
||||||
|
case 'h':
|
||||||
|
optNumber = 16;
|
||||||
|
break;
|
||||||
|
case 'b':
|
||||||
|
optNumber = 2;
|
||||||
|
break;
|
||||||
|
case 'o':
|
||||||
|
optNumber = 8;
|
||||||
|
break;
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
let unsigned = parseInt(str, optNumber);
|
||||||
|
let pow = Math.pow(optNumber, str.length);
|
||||||
|
|
||||||
|
let signed = unsigned;
|
||||||
|
if (unsigned >= pow >> 1) {
|
||||||
|
signed = unsigned - pow;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
'unsigned' : unsigned,
|
||||||
|
'signed' : signed,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 将二进制字符串转浮点数
|
||||||
|
* @param bin
|
||||||
|
* @param exp
|
||||||
|
* @param fra
|
||||||
|
*/
|
||||||
|
function bin2float(bin: string, exp: number, fra: number): number | undefined {
|
||||||
|
if (bin.length < exp + fra +1) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
const bais = Math.pow(2, (exp-1))-1;
|
||||||
|
exp = exp - bais;
|
||||||
|
return exp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getFullSymbolInfo(document: vscode.TextDocument, range: Range, nonblank: RegExp, l_comment_symbol: string, l_comment_regExp: RegExp, needDefinition=true) {
|
||||||
|
const comments = [];
|
||||||
|
if (needDefinition) {
|
||||||
|
const startPosition = new vscode.Position(range.start.line, range.start.character);
|
||||||
|
const endPosition = new vscode.Position(range.end.line, range.end.character);
|
||||||
|
const definitionString = document.getText(new vscode.Range(startPosition, endPosition));
|
||||||
|
comments.push(definitionString);
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = '';
|
||||||
|
let is_b_comment = false;
|
||||||
|
let line = range.start.line + 1;
|
||||||
|
|
||||||
|
while (line) {
|
||||||
|
line--;
|
||||||
|
content = document.lineAt(line).text;
|
||||||
|
// 首先判断该行是否是空白
|
||||||
|
let isblank = content.match(nonblank);
|
||||||
|
if (!isblank) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_b_comment) {
|
||||||
|
let b_comment_begin_index = content.indexOf('/*');
|
||||||
|
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);
|
||||||
|
if (content.match(nonblank)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断该行是否存在行注释
|
||||||
|
let l_comment_index = content.indexOf(l_comment_symbol);
|
||||||
|
if (l_comment_index >= 0) {
|
||||||
|
let before_l_comment = content.slice(0, l_comment_index);
|
||||||
|
// before_l_comment = del_comments(before_l_comment, b_comment_end_index);
|
||||||
|
if (before_l_comment.match(nonblank)) {
|
||||||
|
// 如果去除块注释之后还有字符则认为该注释不属于所要的
|
||||||
|
if (line === range.start.line) {
|
||||||
|
// let b_comment_last_index = content.lastIndexOf('*/');
|
||||||
|
// b_comment_last_index = (b_comment_last_index == -1) ? 0 : (b_comment_last_index + 2);
|
||||||
|
// comments.push(content.slice(b_comment_last_index, l_comment_index) + '\n');
|
||||||
|
comments.push(content.slice(l_comment_index, content.length) + '\n');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则该行全为该定义的注释
|
||||||
|
comments.push(content + '\n');
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 判断该行是否存在块注释
|
||||||
|
let b_comment_end_index = content.indexOf('*/');
|
||||||
|
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);
|
||||||
|
if (behind_b_comment.match(nonblank)) {
|
||||||
|
// 如果去除块注释之后还有字符则认为该注释不属于所要的
|
||||||
|
if (line === range.start.line) {
|
||||||
|
comments.push(content.slice(0, b_comment_end_index) + '\n');
|
||||||
|
is_b_comment = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
comments.push(content + '\n');
|
||||||
|
is_b_comment = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 说明既不是块注释又不是行注释所以就是到了代码块
|
||||||
|
if (line !== range.start.line) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return comments.reverse().join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description get definition and comment of a range
|
||||||
|
* @param path
|
||||||
|
* @param range
|
||||||
|
*/
|
||||||
|
async function getSymbolComment(path: AbsPath, range: Range) {
|
||||||
|
let languageId = hdlFile.getLanguageId(path);
|
||||||
|
const uri = vscode.Uri.file(path);
|
||||||
|
const documentPromise = vscode.workspace.openTextDocument(uri);
|
||||||
|
|
||||||
|
// get comment reg util
|
||||||
|
const nonblank = /\S+/g;
|
||||||
|
const l_comment = getCommentUtilByLanguageId(languageId);
|
||||||
|
if (l_comment) {
|
||||||
|
let l_comment_symbol = l_comment.l_comment_symbol;
|
||||||
|
let l_comment_regExp = l_comment.l_comment_regExp;
|
||||||
|
|
||||||
|
// add definition first
|
||||||
|
const document = await documentPromise;
|
||||||
|
return await getFullSymbolInfo(document, range, nonblank, l_comment_symbol, l_comment_regExp);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description get definition and comment of a range
|
||||||
|
* @param path
|
||||||
|
* @param ranges
|
||||||
|
*/
|
||||||
|
async function getSymbolComments(path: string, ranges: Range[]): Promise<string[]> {
|
||||||
|
let languageId = hdlFile.getLanguageId(path);
|
||||||
|
const uri = vscode.Uri.file(path);
|
||||||
|
const documentPromise = vscode.workspace.openTextDocument(uri);
|
||||||
|
|
||||||
|
// get comment reg util
|
||||||
|
const nonblank = /\S+/g;
|
||||||
|
const l_comment = getCommentUtilByLanguageId(languageId);
|
||||||
|
if (!l_comment) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
let l_comment_symbol = l_comment.l_comment_symbol;
|
||||||
|
let l_comment_regExp = l_comment.l_comment_regExp;
|
||||||
|
|
||||||
|
// add definition first
|
||||||
|
const document = await documentPromise;
|
||||||
|
const commentPromises = [];
|
||||||
|
const comments = [];
|
||||||
|
for (const range of ranges) {
|
||||||
|
const commentP = getFullSymbolInfo(document, range, nonblank, l_comment_symbol, l_comment_regExp, false);
|
||||||
|
commentPromises.push(commentP);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const cp of commentPromises) {
|
||||||
|
comments.push(await cp);
|
||||||
|
}
|
||||||
|
return comments;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
interface CommentUtil {
|
||||||
|
l_comment_symbol: string
|
||||||
|
l_comment_regExp: RegExp
|
||||||
|
}
|
||||||
|
|
||||||
|
function getCommentUtilByLanguageId(languageId: HdlLangID): CommentUtil | undefined {
|
||||||
|
switch (languageId) {
|
||||||
|
case "verilog":
|
||||||
|
case "systemverilog":
|
||||||
|
return {
|
||||||
|
l_comment_symbol: '//',
|
||||||
|
l_comment_regExp: /\/\/.*/g
|
||||||
|
};
|
||||||
|
case "vhdl":
|
||||||
|
return {
|
||||||
|
l_comment_symbol: '--',
|
||||||
|
l_comment_regExp: /--.*/g
|
||||||
|
};
|
||||||
|
default: return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description delete all comment form verilog code
|
||||||
|
* @param {string} text Verilog code input
|
||||||
|
* @returns Verilog code output after deleting all comment content
|
||||||
|
*/
|
||||||
|
function del_comments(text: string, regExp: RegExp): string {
|
||||||
|
let match = text.match(regExp);
|
||||||
|
if (match !== null) {
|
||||||
|
for (let i = 0; i < match.length; i++) {
|
||||||
|
const element = match[i];
|
||||||
|
const newElement = ' '.repeat(element.length);
|
||||||
|
text = text.replace(element,newElement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
transferVlogNumber,
|
||||||
|
getSymbolComment,
|
||||||
|
getSymbolComments
|
||||||
|
};
|
570
src/function/lsp/util/index.js
Normal file
570
src/function/lsp/util/index.js
Normal file
@ -0,0 +1,570 @@
|
|||||||
|
const vscode = require('vscode');
|
||||||
|
|
||||||
|
const { transferVlogNumber, getSymbolComment, getSymbolComments } = require('./feature');
|
||||||
|
|
||||||
|
const { SymbolResult, Position, CommentResult, Range, Module, Instance,
|
||||||
|
HDLParam, ModPort, ModParam } = require('../../../HDLparser');
|
||||||
|
|
||||||
|
const vlogKeyword = new Set([
|
||||||
|
'`include', '`define', 'input', 'output', 'inout', 'module', 'endmodule',
|
||||||
|
'wire', 'reg', 'parameter', 'always', 'assign', 'if', 'else', 'begin', 'end',
|
||||||
|
'case', 'endcase', 'posedge', 'negedge', 'or', 'default', 'while', 'and', '`timescale',
|
||||||
|
'or', 'xor', 'initial', 'function', 'endfunction', 'force', 'pulldown'
|
||||||
|
]);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {Array<vscode.CompletionItem>}
|
||||||
|
*/
|
||||||
|
function getVlogKeywordItem() {
|
||||||
|
const vlogKeywordItem = [];
|
||||||
|
for (const keyword of vlogKeyword) {
|
||||||
|
const clItem = new vscode.CompletionItem(keyword, vscode.CompletionItemKind.Keyword);
|
||||||
|
clItem.detail = "keyword";
|
||||||
|
vlogKeywordItem.push(clItem);
|
||||||
|
}
|
||||||
|
return vlogKeywordItem;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {string} singleWord
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function isVlogKeyword(singleWord) {
|
||||||
|
return vlogKeyword.has(singleWord);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description get the last single word in current line
|
||||||
|
* @param {string} prefixString
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function getLastSingleWord(prefixString) {
|
||||||
|
prefixString = prefixString.trim();
|
||||||
|
const length = prefixString.length;
|
||||||
|
if (length == 0) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
const wordCharacters = [];
|
||||||
|
let alphaReg = /[`_0-9A-Za-z]/;
|
||||||
|
for (let i = length - 1; i >= 0; -- i) {
|
||||||
|
const ch = prefixString[i];
|
||||||
|
if (alphaReg.test(ch)) {
|
||||||
|
wordCharacters.push(ch);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return wordCharacters.reverse().join('');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description get the single word at hover
|
||||||
|
* @param {string} lineText
|
||||||
|
* @param {number} character
|
||||||
|
*/
|
||||||
|
function getSingleWordAtCurrentPosition(lineText, character) {
|
||||||
|
let alphaReg = /[`_0-9A-Za-z]/;
|
||||||
|
if (alphaReg.test(lineText[character])) {
|
||||||
|
const leftPart = [];
|
||||||
|
const rightPart = [];
|
||||||
|
const length = lineText.length;
|
||||||
|
for (let i = character - 1; i >= 0; -- i) {
|
||||||
|
const ch = lineText[i];
|
||||||
|
if (alphaReg.test(ch)) {
|
||||||
|
leftPart.push(ch);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = character + 1; i < length; ++ i) {
|
||||||
|
const ch = lineText[i];
|
||||||
|
if (alphaReg.test(ch)) {
|
||||||
|
rightPart.push(ch);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const leftWord = leftPart.reverse().join('');
|
||||||
|
const rightWord = rightPart.join('');
|
||||||
|
return leftWord + lineText[character] + rightWord;
|
||||||
|
} else {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Position} position_a
|
||||||
|
* @param {Position} position_b
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function positionAfter(position_a, position_b) {
|
||||||
|
return position_a.line > position_b.line || (
|
||||||
|
position_a.line == position_b.line &&
|
||||||
|
position_a.character > position_b.character);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Position} position_a
|
||||||
|
* @param {Position} position_b
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function positionEqual(position_a, position_b) {
|
||||||
|
return position_a.line == position_b.line &&
|
||||||
|
position_a.character == position_b.character;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description position_a behind or equal to position_b
|
||||||
|
* @param {Position} position_a
|
||||||
|
* @param {Position} position_b
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function positionAfterEqual(position_a, position_b) {
|
||||||
|
return positionAfter(position_a, position_b) ||
|
||||||
|
positionEqual(position_a, position_b);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description filter the symbol result item that exceed the scope
|
||||||
|
* @param {vscode.Position} position
|
||||||
|
* @param {Array<SymbolResult>} symbolResults
|
||||||
|
* @returns {{module : SymbolResult, symbols : Array<SymbolResult>}}
|
||||||
|
*/
|
||||||
|
function filterSymbolScope(position, symbolResults) {
|
||||||
|
if (!symbolResults) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const parentModules = symbolResults.filter(item =>
|
||||||
|
item.type == 'module' &&
|
||||||
|
positionAfterEqual(position, item.start) &&
|
||||||
|
positionAfterEqual(item.end, position)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (parentModules.length == 0) {
|
||||||
|
// TODO : macro
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parentModule = parentModules[0];
|
||||||
|
const symbols = symbolResults.filter(item =>
|
||||||
|
item != parentModule &&
|
||||||
|
positionAfterEqual(item.start, parentModule.start) &&
|
||||||
|
positionAfterEqual(parentModule.end, item.end));
|
||||||
|
|
||||||
|
return {
|
||||||
|
module : parentModule,
|
||||||
|
symbols : symbols
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {vscode.TextDocument} document
|
||||||
|
* @param {Position} position
|
||||||
|
* @param {Array<CommentResult>} comments
|
||||||
|
*/
|
||||||
|
function isInComment(document, position, comments) {
|
||||||
|
if (!comments) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// remove the situation that <cursor> // comment
|
||||||
|
const lineText = document.lineAt(position).text;
|
||||||
|
const singleCommentIndex = lineText.indexOf('//');
|
||||||
|
if (singleCommentIndex != -1) {
|
||||||
|
return position.character >= singleCommentIndex;
|
||||||
|
}
|
||||||
|
|
||||||
|
const currentLine = position.line + 1;
|
||||||
|
for (const comment of comments) {
|
||||||
|
const commentLine = comment.start.line;
|
||||||
|
if (commentLine > currentLine) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const startPosition = new vscode.Position(commentLine, 0);
|
||||||
|
const startOffset = document.offsetAt(startPosition);
|
||||||
|
const endPosition = document.positionAt(startOffset + comment.length);
|
||||||
|
|
||||||
|
const originalPosition = new Position(currentLine, position.character);
|
||||||
|
|
||||||
|
if (positionAfterEqual(originalPosition, startPosition) &&
|
||||||
|
positionAfterEqual(endPosition, originalPosition)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {vscode.Position} position
|
||||||
|
* @param {object} includes
|
||||||
|
* @returns {{name: string, start: Position, end: Position}}
|
||||||
|
*/
|
||||||
|
function matchInclude(position, includes) {
|
||||||
|
if (!includes) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (const includeString of Object.keys(includes)) {
|
||||||
|
const range = includes[includeString];
|
||||||
|
// TODO : remove - 1 if bug is fixed
|
||||||
|
range.start.line -= 1;
|
||||||
|
range.end.line -= 1;
|
||||||
|
if (positionAfterEqual(position, range.start) &&
|
||||||
|
positionAfterEqual(range.end, position)) {
|
||||||
|
|
||||||
|
return {
|
||||||
|
name : includeString,
|
||||||
|
start: range.start,
|
||||||
|
end: range.end
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {vscode.Position} position
|
||||||
|
* @param {string} singleWord
|
||||||
|
* @param {object} defines
|
||||||
|
* @returns {{name: string, value: any, range: Range}}
|
||||||
|
*/
|
||||||
|
function matchDefine(position, defines) {
|
||||||
|
if (!defines) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const macro of Object.keys(defines)) {
|
||||||
|
const range = defines[macro].range;
|
||||||
|
range.start.line -= 1;
|
||||||
|
range.end.line -= 1;
|
||||||
|
if (positionAfterEqual(position, range.start) &&
|
||||||
|
positionAfterEqual(range.end, position)) {
|
||||||
|
return {
|
||||||
|
name : macro,
|
||||||
|
value: defines[macro].value,
|
||||||
|
range: range
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {vscode.Position} position
|
||||||
|
* @param {string} singleWord
|
||||||
|
* @param {object} defines
|
||||||
|
* @returns {{name: string, value: any, range: Range}}
|
||||||
|
*/
|
||||||
|
function matchDefineMacro(position, singleWord, defines) {
|
||||||
|
if (!defines) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (singleWord[0] != '`' || singleWord.length <= 1) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const targetMacro = singleWord.substring(1);
|
||||||
|
for (const macro of Object.keys(defines)) {
|
||||||
|
if (macro == targetMacro) {
|
||||||
|
const range = defines[macro].range;
|
||||||
|
const value = defines[macro].value;
|
||||||
|
// TODO : remove - 1 if bug is fixed
|
||||||
|
range.start.line -= 1;
|
||||||
|
range.end.line -= 1;
|
||||||
|
return {
|
||||||
|
name : macro,
|
||||||
|
value : value,
|
||||||
|
range : range
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} singleWord single word to be matched
|
||||||
|
* @param {Module} module
|
||||||
|
* @returns {Instance}
|
||||||
|
*/
|
||||||
|
function matchInstance(singleWord, module) {
|
||||||
|
if (!module) {
|
||||||
|
console.log('warning, cannot locate module', singleWord);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const inst of module.getInstances()) {
|
||||||
|
if (singleWord == inst.type) {
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {vscode.Position} position current cursor position
|
||||||
|
* @param {Array<SymbolResult>} symbols all the symbols in the wrapper module
|
||||||
|
* @param {Module} module wrapper module
|
||||||
|
* @param {Instance}
|
||||||
|
*/
|
||||||
|
function filterInstanceByPosition(position, symbols, module) {
|
||||||
|
if (!symbols) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (const symbol of symbols) {
|
||||||
|
const inst = module.findInstance(symbol.name);
|
||||||
|
if (positionAfterEqual(position, symbol.start) &&
|
||||||
|
positionAfterEqual(symbol.end, position) &&
|
||||||
|
inst) {
|
||||||
|
return inst;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Instance} inst
|
||||||
|
* @param {vscode.Position} position
|
||||||
|
* @param {string} singleWord
|
||||||
|
* @returns {Promise<ModPort>}
|
||||||
|
*/
|
||||||
|
async function getInstPortByPosition(inst, position, singleWord) {
|
||||||
|
if (!inst.module || !inst.instports) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if (positionAfterEqual(position, inst.instports.start) &&
|
||||||
|
positionAfterEqual(inst.instports.end, position)) {
|
||||||
|
for (const port of inst.module.ports) {
|
||||||
|
if (port.name == singleWord) {
|
||||||
|
return port;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {Instance} inst
|
||||||
|
* @param {vscode.Position} position
|
||||||
|
* @param {string} singleWord
|
||||||
|
* @returns {Promise<ModParam>}
|
||||||
|
*/
|
||||||
|
async function getInstParamByPosition(inst, position, singleWord) {
|
||||||
|
if (!inst.module || !inst.instparams) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (positionAfterEqual(position, inst.instparams.start) &&
|
||||||
|
positionAfterEqual(inst.instparams.end, position)) {
|
||||||
|
for (const param of inst.module.params) {
|
||||||
|
if (param.name == singleWord) {
|
||||||
|
return param;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} lineText
|
||||||
|
* @param {number} character
|
||||||
|
* @returns {boolean}
|
||||||
|
*/
|
||||||
|
function isPositionInput(lineText, character) {
|
||||||
|
let alphaReg = /[_0-9A-Za-z]/;
|
||||||
|
for (let i = character; i >= 0; -- i) {
|
||||||
|
const ch = lineText[i];
|
||||||
|
if (alphaReg.test(ch)) {
|
||||||
|
continue;
|
||||||
|
} else if (ch == '.') {
|
||||||
|
if (i == 0) {
|
||||||
|
return true;
|
||||||
|
} else if (lineText[i - 1] == ' ') {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} singleWord
|
||||||
|
* @param {Module} module
|
||||||
|
* @returns {ModPort}
|
||||||
|
*/
|
||||||
|
function matchPorts(singleWord, module) {
|
||||||
|
if (!module || module.ports.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const targetPorts = module.ports.filter(port => port.name == singleWord);
|
||||||
|
if (targetPorts.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return targetPorts[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} singleWord
|
||||||
|
* @param {Module} module
|
||||||
|
* @returns {ModParam}
|
||||||
|
*/
|
||||||
|
function matchParams(singleWord, module) {
|
||||||
|
if (!module || module.params.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const targetParams = module.params.filter(param => param.name == singleWord);
|
||||||
|
if (targetParams.length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return targetParams[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {ModPort} port
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function makePortDesc(port) {
|
||||||
|
let portDesc = port.type;
|
||||||
|
if (port.width) {
|
||||||
|
portDesc += ' ' + port.width;
|
||||||
|
}
|
||||||
|
portDesc += ' ' + port.name;
|
||||||
|
return portDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {ModParam} param
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
function makeParamDesc(param) {
|
||||||
|
let paramDesc = 'parameter ' + param.name;
|
||||||
|
if (param.init) {
|
||||||
|
paramDesc += ' = ' + param.init;
|
||||||
|
}
|
||||||
|
return paramDesc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} singleWord
|
||||||
|
* @param {Array<SymbolResult>} symbols
|
||||||
|
* @returns {SymbolResult}
|
||||||
|
*/
|
||||||
|
function matchNormalSymbol(singleWord, symbols) {
|
||||||
|
if (!symbols || Object.keys(symbols).length == 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
for (const symbol of symbols) {
|
||||||
|
if (singleWord == symbol.name) {
|
||||||
|
return symbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {vscode.MarkdownString} content
|
||||||
|
* @param {Module} module
|
||||||
|
*/
|
||||||
|
async function makeVlogHoverContent(content, module) {
|
||||||
|
const portNum = module.ports.length;
|
||||||
|
const paramNum = module.params.length;
|
||||||
|
const instNum = module.getInstanceNum();
|
||||||
|
|
||||||
|
const moduleUri = vscode.Uri.file(module.path);
|
||||||
|
const thenableFileDocument = vscode.workspace.openTextDocument(moduleUri);
|
||||||
|
|
||||||
|
const portDesc = paramNum + ' $(instance-param) ' +
|
||||||
|
portNum + ' $(instance-port) ' +
|
||||||
|
instNum + ' $(instance-module)';
|
||||||
|
|
||||||
|
|
||||||
|
content.appendCodeblock('module ' + module.name, 'verilog');
|
||||||
|
content.appendText('\n');
|
||||||
|
content.appendMarkdown(portDesc);
|
||||||
|
content.appendText(' | ');
|
||||||
|
|
||||||
|
const count = {
|
||||||
|
input: 0,
|
||||||
|
output: 0,
|
||||||
|
inout: 0
|
||||||
|
};
|
||||||
|
for (const port of module.ports) {
|
||||||
|
count[port.type] += 1;
|
||||||
|
}
|
||||||
|
const ioDesc = count.input + ' $(instance-input) ' +
|
||||||
|
count.output + ' $(instance-output) ' +
|
||||||
|
count.inout + ' $(instance-inout)';
|
||||||
|
content.appendMarkdown(ioDesc);
|
||||||
|
content.appendText('\n');
|
||||||
|
|
||||||
|
content.appendMarkdown('---');
|
||||||
|
|
||||||
|
// make document
|
||||||
|
const fileDocument = await thenableFileDocument;
|
||||||
|
const range = new vscode.Range(module.range.start, module.range.end);
|
||||||
|
const moduleDefinitionCode = fileDocument.getText(range);
|
||||||
|
content.appendCodeblock(moduleDefinitionCode, 'verilog');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async function searchCommentAround(uri, range) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getVlogKeywordItem,
|
||||||
|
getLastSingleWord,
|
||||||
|
getSingleWordAtCurrentPosition,
|
||||||
|
filterSymbolScope,
|
||||||
|
filterInstanceByPosition,
|
||||||
|
isPositionInput,
|
||||||
|
isInComment,
|
||||||
|
matchInclude,
|
||||||
|
matchDefine,
|
||||||
|
matchDefineMacro,
|
||||||
|
matchInstance,
|
||||||
|
matchPorts,
|
||||||
|
matchParams,
|
||||||
|
matchNormalSymbol,
|
||||||
|
isVlogKeyword,
|
||||||
|
makeVlogHoverContent,
|
||||||
|
positionAfterEqual,
|
||||||
|
getInstPortByPosition,
|
||||||
|
getInstParamByPosition,
|
||||||
|
makePortDesc,
|
||||||
|
makeParamDesc,
|
||||||
|
transferVlogNumber,
|
||||||
|
getSymbolComment,
|
||||||
|
getSymbolComments
|
||||||
|
};
|
8
src/function/sim/index.ts
Normal file
8
src/function/sim/index.ts
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
import { instantiation } from './instance';
|
||||||
|
import { testbench } from './testbench';
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
instantiation,
|
||||||
|
testbench
|
||||||
|
};
|
272
src/function/sim/instance.ts
Normal file
272
src/function/sim/instance.ts
Normal file
@ -0,0 +1,272 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
import { HdlLangID } from '../../global/enum';
|
||||||
|
import { hdlParam } from '../../hdlParser';
|
||||||
|
import { HdlModulePort, HdlModuleParam } from '../../hdlParser/common';
|
||||||
|
import { HdlModule } from '../../hdlParser/core';
|
||||||
|
|
||||||
|
class ModuleInfoItem {
|
||||||
|
label: string;
|
||||||
|
description: string;
|
||||||
|
detail: string;
|
||||||
|
module: HdlModule;
|
||||||
|
/**
|
||||||
|
* @param module
|
||||||
|
*/
|
||||||
|
constructor(module: HdlModule) {
|
||||||
|
// TODO : 等到sv的解析做好后,写入对于不同hdl的图标
|
||||||
|
let iconID = '$(instance-' + module.file.languageId + ') ';
|
||||||
|
this.label = iconID + module.name;
|
||||||
|
this.description = module.params.length + ' $(instance-param) ' +
|
||||||
|
module.ports.length + ' $(instance-port) ' +
|
||||||
|
module.getInstanceNum() + ' $(instance-module)';
|
||||||
|
this.detail = module.path;
|
||||||
|
this.module = module;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description verilog模式下生成整个例化的内容
|
||||||
|
* @param module 模块信息
|
||||||
|
*/
|
||||||
|
function instanceVlogCode(module: HdlModule) {
|
||||||
|
let vlogPortStr = vlogPort(module.ports);
|
||||||
|
let vlogParamStr = vlogParam(module.params);
|
||||||
|
|
||||||
|
let instContent = '';
|
||||||
|
instContent += vlogPortStr.wireStr;
|
||||||
|
instContent += module.name + ' ';
|
||||||
|
|
||||||
|
if (vlogParamStr !== '') {
|
||||||
|
instContent += `#(\n${vlogParamStr})\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
instContent += `u_${module.name}(\n`;
|
||||||
|
instContent += vlogPortStr.portStr;
|
||||||
|
instContent += ');\n';
|
||||||
|
|
||||||
|
return instContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description vhdl模式下生成整个例化的内容
|
||||||
|
* @param module 模块信息
|
||||||
|
*/
|
||||||
|
function instanceVhdlCode(module: HdlModule) {
|
||||||
|
// module 2001 style
|
||||||
|
let port = vhdlPort(module.ports);
|
||||||
|
let param = vhdlParam(module.params);
|
||||||
|
|
||||||
|
let instContent = `u_${module.name} : ${module.name}\n`;
|
||||||
|
|
||||||
|
if (param !== '') {
|
||||||
|
instContent += `generic map(\n${param})\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
instContent += `port map(\n${port});\n`;
|
||||||
|
|
||||||
|
return instContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description verilog模式下对端口信息生成要例化的内容
|
||||||
|
* @param ports 端口信息列表
|
||||||
|
*/
|
||||||
|
function vlogPort(ports: HdlModulePort[]) : { wireStr: string, portStr: string} {
|
||||||
|
let nmax = getlmax(ports, 'name');
|
||||||
|
let wmax = getlmax(ports, 'width');
|
||||||
|
|
||||||
|
let portStr = `\t// ports\n`;
|
||||||
|
let wireStr = '// outports wire\n';
|
||||||
|
for (let i = 0; i < ports.length; i++) {
|
||||||
|
const port = ports[i];
|
||||||
|
|
||||||
|
if (port.type === 'output') {
|
||||||
|
let width = port.width;
|
||||||
|
let wpadding = wmax - width.length + 1;
|
||||||
|
width += ' '.repeat(wpadding);
|
||||||
|
// TODO: vhdl type
|
||||||
|
wireStr += `wire ${width}\t${port.name};\n`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let name = port.name;
|
||||||
|
let npadding = nmax - name.length + 1;
|
||||||
|
name += ' '.repeat(npadding);
|
||||||
|
portStr += `\t.${name}\t( ${name} )`;
|
||||||
|
if (i !== ports.length - 1) {
|
||||||
|
portStr += ',';
|
||||||
|
}
|
||||||
|
portStr += '\n';
|
||||||
|
}
|
||||||
|
|
||||||
|
return { wireStr, portStr };
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description verilog模式下对参数信息生成要例化的内容
|
||||||
|
* @param params 参数信息列表
|
||||||
|
*/
|
||||||
|
function vlogParam(params: HdlModuleParam[]): string {
|
||||||
|
let paramStr = '';
|
||||||
|
let nmax = getlmax(params, 'name');
|
||||||
|
let imax = getlmax(params, 'init');
|
||||||
|
|
||||||
|
// .NAME ( INIT ),
|
||||||
|
for (let i = 0; i < params.length; i++) {
|
||||||
|
let name = params[i].name;
|
||||||
|
let init = params[i].init;
|
||||||
|
|
||||||
|
let namePadding = nmax - name.length + 1;
|
||||||
|
let initPadding = imax - init.length + 1;
|
||||||
|
|
||||||
|
name +=' '.repeat(namePadding);
|
||||||
|
init +=' '.repeat(initPadding);
|
||||||
|
|
||||||
|
paramStr += `\t.${name}\t( ${init} )`;
|
||||||
|
if (i !== (params.length - 1)) {
|
||||||
|
paramStr += ',';
|
||||||
|
paramStr += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return paramStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description vhdl模式下对端口信息生成要例化的内容
|
||||||
|
* @param ports 端口信息列表
|
||||||
|
*/
|
||||||
|
function vhdlPort(ports: HdlModulePort[]): string {
|
||||||
|
let nmax = getlmax(ports, 'name');
|
||||||
|
|
||||||
|
// NAME => NAME,
|
||||||
|
let portStr = `\n\t-- ports\n`;
|
||||||
|
for (let i = 0; i < ports.length; i++) {
|
||||||
|
let name = ports[i].name;
|
||||||
|
let padding = nmax - name.length + 1;
|
||||||
|
name += ' '.repeat(padding);
|
||||||
|
portStr += `\t${name} => ${name}`;
|
||||||
|
if (i !== (ports.length - 1)) {
|
||||||
|
portStr += ',';
|
||||||
|
}
|
||||||
|
portStr += '\n';
|
||||||
|
}
|
||||||
|
return portStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description vhdl模式下对参数信息生成要例化的内容
|
||||||
|
* @param params 参数信息列表
|
||||||
|
*/
|
||||||
|
function vhdlParam(params: HdlModuleParam[]): string {
|
||||||
|
let paramStr = '';
|
||||||
|
let nmax = getlmax(params, 'name');
|
||||||
|
|
||||||
|
// NAME => NAME,
|
||||||
|
for (let i = 0; i < params.length; i++) {
|
||||||
|
let name = params[i].name;
|
||||||
|
const init = params[i].init;
|
||||||
|
|
||||||
|
let npadding = nmax - name.length + 1;
|
||||||
|
name += ' '.repeat(npadding);
|
||||||
|
|
||||||
|
paramStr += `\t${name} => ${init}`;
|
||||||
|
if (i !== (params.length - 1)) {
|
||||||
|
paramStr += ',';
|
||||||
|
paramStr += '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return paramStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 在arr中找到pro属性的最大字符长度
|
||||||
|
* @param {Array} arr 待查找的数组
|
||||||
|
* @param {String} pro 指定属性
|
||||||
|
* @returns {Number} 该数组中的pro属性的最大字符长度
|
||||||
|
*/
|
||||||
|
function getlmax(arr: any[], pro: string): number {
|
||||||
|
let lmax = 0;
|
||||||
|
for (let i = 0; i < arr.length; i++) {
|
||||||
|
const len = arr[i][pro].length;
|
||||||
|
if (len <= lmax) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
lmax = len;
|
||||||
|
}
|
||||||
|
return lmax;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 向光标处插入内容
|
||||||
|
* @param content 需要插入的内容
|
||||||
|
* @param editor 通过 vscode.window.activeTextEditor 获得
|
||||||
|
*/
|
||||||
|
function selectInsert(content: string, editor: vscode.TextEditor): boolean {
|
||||||
|
if (editor === undefined) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
let selections = editor.selections;
|
||||||
|
editor.edit((editBuilder) => {
|
||||||
|
selections.forEach((selection) => {
|
||||||
|
// position, content
|
||||||
|
editBuilder.insert(selection.active, content);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getSelectItem(modules: HdlModule[]) {
|
||||||
|
// make ModuleInfoList
|
||||||
|
const items = [];
|
||||||
|
for (const module of modules) {
|
||||||
|
items.push(new ModuleInfoItem(module));
|
||||||
|
}
|
||||||
|
return items;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description 调用vscode的窗体,让用户从所有的Module中选择模块(为后续的例化准备)
|
||||||
|
*/
|
||||||
|
async function selectModuleFromAll() {
|
||||||
|
const option = {
|
||||||
|
placeHolder: 'Select a Module'
|
||||||
|
};
|
||||||
|
|
||||||
|
const selectModuleInfo = await vscode.window.showQuickPick(
|
||||||
|
getSelectItem(hdlParam.getAllHdlModules()), option
|
||||||
|
);
|
||||||
|
|
||||||
|
if (selectModuleInfo) {
|
||||||
|
return selectModuleInfo.module;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function instanceByLangID(module: HdlModule): string {
|
||||||
|
switch (module.languageId) {
|
||||||
|
case HdlLangID.Verilog: return instanceVlogCode(module);
|
||||||
|
case HdlLangID.Vhdl: return instanceVhdlCode(module);
|
||||||
|
// TODO : add support for svlog
|
||||||
|
case HdlLangID.SystemVerilog: return instanceVlogCode(module);
|
||||||
|
default: return '';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function instantiation() {
|
||||||
|
const module = await selectModuleFromAll();
|
||||||
|
if (module) {
|
||||||
|
const code = instanceByLangID(module);
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (editor) {
|
||||||
|
selectInsert(code, editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
instantiation,
|
||||||
|
instanceByLangID,
|
||||||
|
getSelectItem
|
||||||
|
};
|
82
src/function/sim/testbench.ts
Normal file
82
src/function/sim/testbench.ts
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
|
|
||||||
|
import { MainOutput, opeParam } from '../../global';
|
||||||
|
import { hdlPath, hdlFile} from '../../hdlFs';
|
||||||
|
import { HdlModule, hdlParam } from '../../hdlParser/core';
|
||||||
|
import { instanceByLangID, getSelectItem } from './instance';
|
||||||
|
|
||||||
|
function overwrite() {
|
||||||
|
const options = {
|
||||||
|
preview: false,
|
||||||
|
viewColumn: vscode.ViewColumn.Active
|
||||||
|
};
|
||||||
|
const tbSrcPath = hdlPath.join(opeParam.extensionPath, 'lib', 'testbench.v');
|
||||||
|
const uri = vscode.Uri.file(tbSrcPath);
|
||||||
|
vscode.window.showTextDocument(uri, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
function generateTestbenchFile(module: HdlModule) {
|
||||||
|
const tbSrcPath = hdlPath.join(opeParam.extensionPath, 'lib', 'testbench.v');
|
||||||
|
const tbDisPath = hdlPath.join(opeParam.prjInfo.arch.hardware.sim, 'testbench.v');
|
||||||
|
|
||||||
|
if (!hdlFile.isFile(tbDisPath)) {
|
||||||
|
var temp = hdlFile.readFile(tbSrcPath);
|
||||||
|
} else {
|
||||||
|
var temp = hdlFile.readFile(tbDisPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!temp) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
let content = '';
|
||||||
|
const lines = temp.split('\n');
|
||||||
|
const len = lines.length;
|
||||||
|
for (let index = 0; index < len; index++) {
|
||||||
|
const line = lines[index];
|
||||||
|
content += line + '\n';
|
||||||
|
if (line.indexOf("//Instance ") !== -1) {
|
||||||
|
content += instanceByLangID(module) + '\n';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
hdlFile.writeFile(tbDisPath, content);
|
||||||
|
MainOutput.report("Generate testbench successed");
|
||||||
|
} catch (err) {
|
||||||
|
vscode.window.showErrorMessage("Generate testbench failed:" + err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function testbench() {
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (!editor) {
|
||||||
|
vscode.window.showErrorMessage('please select a editor!');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const uri = editor.document.uri;
|
||||||
|
const option = {
|
||||||
|
placeHolder: 'Select a Module to generate testbench'
|
||||||
|
};
|
||||||
|
const path = hdlPath.toSlash(uri.fsPath);
|
||||||
|
console.log(path);
|
||||||
|
|
||||||
|
if (!hdlFile.isHDLFile(path)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentHdlFile = hdlParam.getHdlFile(path);
|
||||||
|
if (!currentHdlFile) {
|
||||||
|
vscode.window.showErrorMessage('There is no hdlFile respect to ' + path);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const currentHdlModules = currentHdlFile.getAllHdlModules();
|
||||||
|
const items = getSelectItem(currentHdlModules);
|
||||||
|
const select = await vscode.window.showQuickPick(items, option);
|
||||||
|
if (select) {
|
||||||
|
generateTestbenchFile(items[0].module);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export {
|
||||||
|
testbench
|
||||||
|
};
|
@ -1,5 +1,6 @@
|
|||||||
import { opeParam, OpeParamDefaults } from './opeParam';
|
import { opeParam, OpeParamDefaults } from './opeParam';
|
||||||
import { PrjInfo, PrjInfoDefaults } from './prjInfo';
|
import { PrjInfo, PrjInfoDefaults } from './prjInfo';
|
||||||
|
import { MainOutput, YosysOutput, ReportType } from './outputChannel';
|
||||||
|
|
||||||
import * as Enum from './enum';
|
import * as Enum from './enum';
|
||||||
import * as Lang from './lang';
|
import * as Lang from './lang';
|
||||||
@ -15,5 +16,8 @@ export {
|
|||||||
Enum,
|
Enum,
|
||||||
Lang,
|
Lang,
|
||||||
AbsPath,
|
AbsPath,
|
||||||
RelPath
|
RelPath,
|
||||||
|
MainOutput,
|
||||||
|
YosysOutput,
|
||||||
|
ReportType
|
||||||
};
|
};
|
@ -24,7 +24,7 @@ class Output {
|
|||||||
return this._ignoreTypes.includes(type);
|
return this._ignoreTypes.includes(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
report(message: string, type: ReportType = ReportType.Debug) {
|
report(message: string | unknown, type: ReportType = ReportType.Info) {
|
||||||
if (!this.skipMessage(type) && message) {
|
if (!this.skipMessage(type) && message) {
|
||||||
this._output.show(true);
|
this._output.show(true);
|
||||||
this._output.appendLine('[' + type + '] ' + message);
|
this._output.appendLine('[' + type + '] ' + message);
|
||||||
|
@ -75,7 +75,8 @@ function isHDLFile(path: AbsPath): boolean {
|
|||||||
|
|
||||||
|
|
||||||
function getHDLFiles(path: AbsPath | AbsPath[] | Set<AbsPath>, ignores?: AbsPath[]) {
|
function getHDLFiles(path: AbsPath | AbsPath[] | Set<AbsPath>, ignores?: AbsPath[]) {
|
||||||
return pickFileRecursive(path, ignores, filePath => isHDLFile(filePath));
|
return pickFileRecursive(path, ignores,
|
||||||
|
filePath => isHDLFile(filePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -83,7 +84,7 @@ function pickFileRecursive(path: AbsPath | AbsPath[] | Set<AbsPath>, ignores?: A
|
|||||||
if ((path instanceof Array) ||
|
if ((path instanceof Array) ||
|
||||||
(path instanceof Set)) {
|
(path instanceof Set)) {
|
||||||
const hdlFiles: AbsPath[] = [];
|
const hdlFiles: AbsPath[] = [];
|
||||||
path.forEach(p => hdlFiles.push(...pickFileRecursive(p)));
|
path.forEach(p => hdlFiles.push(...pickFileRecursive(p, ignores, condition)));
|
||||||
return hdlFiles;
|
return hdlFiles;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,11 +125,11 @@ function getLanguageId(path: AbsPath | RelPath): HdlLangID {
|
|||||||
return HdlLangID.Unknown;
|
return HdlLangID.Unknown;
|
||||||
}
|
}
|
||||||
const ext = hdlPath.extname(path, false);
|
const ext = hdlPath.extname(path, false);
|
||||||
if (verilogExts.includes(path)) {
|
if (verilogExts.includes(ext)) {
|
||||||
return HdlLangID.Verilog;
|
return HdlLangID.Verilog;
|
||||||
} else if (vhdlExts.includes(path)) {
|
} else if (vhdlExts.includes(ext)) {
|
||||||
return HdlLangID.Vhdl;
|
return HdlLangID.Vhdl;
|
||||||
} else if (systemVerilogExts.includes(path)) {
|
} else if (systemVerilogExts.includes(ext)) {
|
||||||
return HdlLangID.SystemVerilog;
|
return HdlLangID.SystemVerilog;
|
||||||
} else {
|
} else {
|
||||||
return HdlLangID.Unknown;
|
return HdlLangID.Unknown;
|
||||||
|
@ -1,16 +1,17 @@
|
|||||||
|
import * as vscode from 'vscode';
|
||||||
import { opeParam, AbsPath, Enum } from '../global';
|
import { opeParam, AbsPath, Enum } from '../global';
|
||||||
import * as hdlPath from './path';
|
import * as hdlPath from './path';
|
||||||
|
|
||||||
interface IconConfig {
|
interface IconConfig {
|
||||||
light: AbsPath
|
readonly light: vscode.Uri
|
||||||
dark: AbsPath
|
readonly dark: vscode.Uri
|
||||||
};
|
};
|
||||||
|
|
||||||
function getIconPath(themeType: Enum.ThemeType, iconName: string): AbsPath {
|
function getIconPath(themeType: Enum.ThemeType, iconName: string): vscode.Uri {
|
||||||
const iconFile = iconName + '.svg';
|
const iconFile = iconName + '.svg';
|
||||||
const svgDir = hdlPath.join(opeParam.extensionPath, 'images', 'svg');
|
const svgDir = hdlPath.join(opeParam.extensionPath, 'images', 'svg');
|
||||||
const iconPath = hdlPath.join(svgDir, themeType, iconFile);
|
const iconPath = hdlPath.join(svgDir, themeType, iconFile);
|
||||||
return iconPath;
|
return vscode.Uri.file(iconPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
function getIconConfig(iconName: string): IconConfig {
|
function getIconConfig(iconName: string): IconConfig {
|
||||||
@ -20,7 +21,7 @@ function getIconConfig(iconName: string): IconConfig {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
export {
|
||||||
getIconPath,
|
getIconPath,
|
||||||
getIconConfig
|
getIconConfig
|
||||||
};
|
};
|
@ -72,6 +72,7 @@ interface HdlModulePort {
|
|||||||
type: HdlModulePortType
|
type: HdlModulePortType
|
||||||
width: string
|
width: string
|
||||||
range: Range
|
range: Range
|
||||||
|
desc?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
interface HdlModuleParam {
|
interface HdlModuleParam {
|
||||||
@ -80,6 +81,7 @@ interface HdlModuleParam {
|
|||||||
type: string
|
type: string
|
||||||
init: string
|
init: string
|
||||||
range: Range
|
range: Range
|
||||||
|
desc?: string
|
||||||
};
|
};
|
||||||
|
|
||||||
type InstRange = Range | null;
|
type InstRange = Range | null;
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { AbsPath } from '../global';
|
import { AbsPath } from '../global';
|
||||||
import { HdlLangID } from '../global/enum';
|
import { HdlLangID } from '../global/enum';
|
||||||
|
import { MainOutput, ReportType } from '../global/outputChannel';
|
||||||
|
|
||||||
import * as common from './common';
|
import * as common from './common';
|
||||||
import { hdlFile, hdlPath } from '../hdlFs';
|
import { hdlFile, hdlPath } from '../hdlFs';
|
||||||
|
import { HdlSymbol } from './util';
|
||||||
|
|
||||||
class HdlParam {
|
class HdlParam {
|
||||||
private readonly topModules : Set<HdlModule> = new Set<HdlModule>();
|
private readonly topModules : Set<HdlModule> = new Set<HdlModule>();
|
||||||
@ -57,6 +59,12 @@ class HdlParam {
|
|||||||
return hdlFile.getHdlModule(name);
|
return hdlFile.getHdlModule(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAllHdlModules(): HdlModule[] {
|
||||||
|
const hdlModules: HdlModule[] = [];
|
||||||
|
this.modules.forEach(m => hdlModules.push(m));
|
||||||
|
return hdlModules;
|
||||||
|
}
|
||||||
|
|
||||||
public addHdlModule(hdlModule: HdlModule) {
|
public addHdlModule(hdlModule: HdlModule) {
|
||||||
this.modules.add(hdlModule);
|
this.modules.add(hdlModule);
|
||||||
}
|
}
|
||||||
@ -73,6 +81,30 @@ class HdlParam {
|
|||||||
this.topModules.delete(hdlModule);
|
this.topModules.delete(hdlModule);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public getAllTopModules(global :boolean = false): HdlModule[] {
|
||||||
|
const topModules: HdlModule[] = [];
|
||||||
|
if (global) {
|
||||||
|
this.topModules.forEach(m => topModules.push(m));
|
||||||
|
} else {
|
||||||
|
this.srcTopModules.forEach(m => topModules.push(m));
|
||||||
|
this.simTopModules.forEach(m => topModules.push(m));
|
||||||
|
}
|
||||||
|
return topModules;
|
||||||
|
}
|
||||||
|
|
||||||
|
public isTopModule(path: AbsPath, name: string, global = false): boolean {
|
||||||
|
const module = this.getHdlModule(path, name);
|
||||||
|
if (!module) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (global) {
|
||||||
|
return this.topModules.has(module);
|
||||||
|
} else {
|
||||||
|
const sourceTopModule = this.selectTopModuleSourceByFileType(module);
|
||||||
|
return sourceTopModule.has(module);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public selectTopModuleSourceByFileType(hdlModule: HdlModule): Set<HdlModule> {
|
public selectTopModuleSourceByFileType(hdlModule: HdlModule): Set<HdlModule> {
|
||||||
switch (hdlModule.file.type) {
|
switch (hdlModule.file.type) {
|
||||||
case common.HdlFileType.Src: return this.srcTopModules;
|
case common.HdlFileType.Src: return this.srcTopModules;
|
||||||
@ -149,6 +181,29 @@ class HdlParam {
|
|||||||
this.unhandleInstances.delete(inst);
|
this.unhandleInstances.delete(inst);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async initHdlFiles(hdlFiles: AbsPath[] | Generator<AbsPath>) {
|
||||||
|
for (const path of hdlFiles) {
|
||||||
|
// TODO : only support verilog now
|
||||||
|
const langID = hdlFile.getLanguageId(path);
|
||||||
|
if (langID === HdlLangID.Verilog) {
|
||||||
|
const fast = await HdlSymbol.fast(path);
|
||||||
|
if (fast) {
|
||||||
|
new HdlFile(path,
|
||||||
|
fast.languageId,
|
||||||
|
fast.macro,
|
||||||
|
fast.content.modules);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async initialize(hdlFiles: AbsPath[] | Generator<AbsPath>) {
|
||||||
|
await this.initHdlFiles(hdlFiles);
|
||||||
|
for (const hdlFile of this.getAllHdlFiles()) {
|
||||||
|
hdlFile.makeInstance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const hdlParam = new HdlParam();
|
const hdlParam = new HdlParam();
|
||||||
@ -226,7 +281,7 @@ class HdlModule {
|
|||||||
range: common.Range;
|
range: common.Range;
|
||||||
params: common.HdlModuleParam[];
|
params: common.HdlModuleParam[];
|
||||||
ports: common.HdlModulePort[];
|
ports: common.HdlModulePort[];
|
||||||
private rawInstances: common.RawHdlInstance[];
|
private rawInstances: common.RawHdlInstance[] | undefined;
|
||||||
private nameToInstances: Map<string, HdlInstance>;
|
private nameToInstances: Map<string, HdlInstance>;
|
||||||
private unhandleInstances: Set<HdlInstance>;
|
private unhandleInstances: Set<HdlInstance>;
|
||||||
private globalRefers: Set<HdlInstance>;
|
private globalRefers: Set<HdlInstance>;
|
||||||
@ -272,6 +327,10 @@ class HdlModule {
|
|||||||
return this.file.path;
|
return this.file.path;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get languageId(): HdlLangID {
|
||||||
|
return this.file.languageId;
|
||||||
|
}
|
||||||
|
|
||||||
public getInstance(name: string): HdlInstance | undefined {
|
public getInstance(name: string): HdlInstance | undefined {
|
||||||
return this.nameToInstances.get(name);
|
return this.nameToInstances.get(name);
|
||||||
}
|
}
|
||||||
@ -309,6 +368,19 @@ class HdlModule {
|
|||||||
return hdlInstance;
|
return hdlInstance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public makeNameToInstances() {
|
||||||
|
if (this.rawInstances) {
|
||||||
|
this.nameToInstances.clear();
|
||||||
|
for (const inst of this.rawInstances) {
|
||||||
|
this.createHdlInstance(inst);
|
||||||
|
}
|
||||||
|
this.rawInstances = undefined;
|
||||||
|
} else {
|
||||||
|
MainOutput.report('call makeNameToInstances but this.rawInstances is undefined',
|
||||||
|
ReportType.Warn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public deleteInstanceByName(name: string) {
|
public deleteInstanceByName(name: string) {
|
||||||
const inst = this.getInstance(name);
|
const inst = this.getInstance(name);
|
||||||
this.deleteInstance(inst);
|
this.deleteInstance(inst);
|
||||||
@ -518,9 +590,17 @@ class HdlFile {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public makeInstance() {
|
||||||
|
for (const module of this.getAllHdlModules()) {
|
||||||
|
module.makeNameToInstances();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export {
|
export {
|
||||||
hdlParam
|
hdlParam,
|
||||||
|
HdlModule,
|
||||||
|
HdlInstance,
|
||||||
|
hdlFile
|
||||||
};
|
};
|
5
src/hdlParser/index.ts
Normal file
5
src/hdlParser/index.ts
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
import { hdlParam } from './core';
|
||||||
|
|
||||||
|
export {
|
||||||
|
hdlParam
|
||||||
|
};
|
@ -1,5 +1,30 @@
|
|||||||
import { vlogAll, vlogFast } from '../../wasm/hdlParser';
|
import { Fast, vlogAll, vlogFast, vhdlAll, svFast, svAll, vhdlFast, All } from '../../resources/hdlParser';
|
||||||
|
import { hdlFile } from '../hdlFs';
|
||||||
|
import { HdlLangID } from '../global/enum';
|
||||||
|
import { AbsPath } from '../global';
|
||||||
|
|
||||||
function hello(path: string) {
|
namespace HdlSymbol {
|
||||||
vlogAll(path);
|
export async function fast(path: AbsPath): Promise<Fast | undefined> {
|
||||||
|
const langID = hdlFile.getLanguageId(path);
|
||||||
|
switch (langID) {
|
||||||
|
case HdlLangID.Verilog: return vlogFast(path);
|
||||||
|
case HdlLangID.Vhdl: return vhdlFast(path);
|
||||||
|
case HdlLangID.SystemVerilog: return svFast(path);
|
||||||
|
default: return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function all(path: AbsPath): Promise<All | undefined> {
|
||||||
|
const langID = hdlFile.getLanguageId(path);
|
||||||
|
switch (langID) {
|
||||||
|
case HdlLangID.Verilog: return vlogAll(path);
|
||||||
|
case HdlLangID.Vhdl: return vhdlAll(path);
|
||||||
|
case HdlLangID.SystemVerilog: return svAll(path);
|
||||||
|
default: return undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
HdlSymbol
|
||||||
|
};
|
@ -23,7 +23,7 @@ interface PSConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @state finish-untest
|
* @state finish-untest
|
||||||
* @descriptionCn xilinx工具链下PS端的操作类
|
* @description xilinx工具链下PS端的操作类
|
||||||
*/
|
*/
|
||||||
class XilinxOperation {
|
class XilinxOperation {
|
||||||
public get config(): XilinxOperationConfig {
|
public get config(): XilinxOperationConfig {
|
||||||
|
@ -86,6 +86,7 @@ class PrjManage {
|
|||||||
searchPathSet.checkAdd(hardwareInfo.sim);
|
searchPathSet.checkAdd(hardwareInfo.sim);
|
||||||
|
|
||||||
const searchPaths = searchPathSet.files;
|
const searchPaths = searchPathSet.files;
|
||||||
|
|
||||||
return hdlFile.getHDLFiles(searchPaths, []);
|
return hdlFile.getHDLFiles(searchPaths, []);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
74
test.js
74
test.js
@ -1,20 +1,36 @@
|
|||||||
/* eslint-disable @typescript-eslint/naming-convention */
|
/* eslint-disable @typescript-eslint/naming-convention */
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const fspath = require('path');
|
||||||
|
|
||||||
const sysvlog_build = require('./wasm/hdlParser/parser');
|
const { vlogFast } = require('./resources/hdlParser');
|
||||||
|
|
||||||
const COMMON_PATH = path.resolve('./lib/common/Driver');
|
const COMMON_PATH = fspath.resolve('./lib/common/Driver');
|
||||||
|
|
||||||
const TEST_FILE = './parser_stuck.v';
|
const TEST_FILE = './parser_stuck.v';
|
||||||
const TEST_FILE2 = './src/test/vlog/dependence_test/parent.v';
|
const TEST_FILE2 = './src/test/vlog/dependence_test/parent.v';
|
||||||
const TEST_FILE3 = './src/test/vlog/formatter_test.v';
|
const TEST_FILE3 = './src/test/vlog/formatter_test.v';
|
||||||
|
|
||||||
|
|
||||||
|
function isFile(path) {
|
||||||
|
if (!fs.existsSync(path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const state = fs.statSync(path);
|
||||||
|
if (state.isDirectory()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* judge if the path represent a Dir
|
||||||
|
* @param path
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
function isDir(path) {
|
function isDir(path) {
|
||||||
if (!fs.existsSync(path)) {
|
if (!fs.existsSync(path)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const state = fs.statSync(path);
|
const state = fs.statSync(path);
|
||||||
if (state.isDirectory()) {
|
if (state.isDirectory()) {
|
||||||
return true;
|
return true;
|
||||||
@ -22,38 +38,38 @@ function isDir(path) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getHDLFiles(path) {
|
function* walk(path, condition) {
|
||||||
if (isDir(path)) {
|
if (isFile(path)) {
|
||||||
const hdlFiles = [];
|
if (!condition || condition(path)) {
|
||||||
|
yield path;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
for (const file of fs.readdirSync(path)) {
|
for (const file of fs.readdirSync(path)) {
|
||||||
const filePath = path + '/' + file;
|
const filePath = fspath.join(path, file);
|
||||||
if (isDir(filePath)) {
|
if (isDir(filePath)) {
|
||||||
const subHdlFiles = getHDLFiles(filePath);
|
for (const targetPath of walk(filePath, condition)) {
|
||||||
if (subHdlFiles.length > 0) {
|
yield targetPath;
|
||||||
hdlFiles.push(...subHdlFiles);
|
}
|
||||||
|
}
|
||||||
|
else if (isFile(filePath)) {
|
||||||
|
if (!condition || condition(filePath)) {
|
||||||
|
yield filePath;
|
||||||
}
|
}
|
||||||
} else if (filePath.endsWith('.v')) {
|
|
||||||
hdlFiles.push(filePath);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return hdlFiles;
|
|
||||||
} else if (path.endsWith('.v')) {
|
|
||||||
return [path];
|
|
||||||
} else {
|
|
||||||
return [];
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(async() => {
|
(async() => {
|
||||||
const Module = await sysvlog_build();
|
console.time('test');
|
||||||
console.log(Object.keys(Module).filter(name => name.startsWith('_') && !name.startsWith('__')));
|
for (const file of walk('./lib', f => f.endsWith('.v'))) {
|
||||||
const source = fs.readFileSync(TEST_FILE2, 'utf-8') + '\n';
|
console.log(file);
|
||||||
Module.FS.writeFile('/sysvlog_build', source, { encoding: 'utf8' });
|
try {
|
||||||
|
await vlogFast(file);
|
||||||
const start = Date.now();
|
} catch (err) {
|
||||||
|
console.log(err);
|
||||||
const fast = Module.ccall('vlog_fast', 'string', ['string'], ['/sysvlog_build']);
|
}
|
||||||
const costTime = (Date.now() - start) / 1000;
|
}
|
||||||
console.log(JSON.stringify(JSON.parse(fast), null, ' '));
|
console.timeEnd('test');
|
||||||
console.log('cost time', costTime);
|
|
||||||
})();
|
})();
|
@ -3,6 +3,7 @@
|
|||||||
"module": "commonjs",
|
"module": "commonjs",
|
||||||
"target": "ES2020",
|
"target": "ES2020",
|
||||||
"outDir": "out",
|
"outDir": "out",
|
||||||
|
"skipLibCheck": true,
|
||||||
"lib": [
|
"lib": [
|
||||||
"ES2020"
|
"ES2020"
|
||||||
],
|
],
|
||||||
|
Loading…
x
Reference in New Issue
Block a user