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",
|
||||
"default": "",
|
||||
"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",
|
||||
"title": "%digital-ide.property-json.overwrite.title%",
|
||||
"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": [
|
||||
{
|
||||
"id": "tcl",
|
||||
@ -188,7 +305,128 @@
|
||||
"language": "systemverilog",
|
||||
"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": {
|
||||
"vscode:prepublish": "npm run compile",
|
||||
@ -199,16 +437,25 @@
|
||||
"test": "node ./out/test/runTest.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/vscode": "^1.74.0",
|
||||
"@types/glob": "^8.0.0",
|
||||
"@types/mocha": "^10.0.0",
|
||||
"@types/node": "16.x",
|
||||
"@types/showdown": "^2.0.0",
|
||||
"@types/vscode": "^1.74.0",
|
||||
"@typescript-eslint/eslint-plugin": "^5.42.0",
|
||||
"@typescript-eslint/parser": "^5.42.0",
|
||||
"@vscode/test-electron": "^2.2.0",
|
||||
"eslint": "^8.26.0",
|
||||
"glob": "^8.0.3",
|
||||
"mocha": "^10.1.0",
|
||||
"typescript": "^4.8.4",
|
||||
"@vscode/test-electron": "^2.2.0"
|
||||
"typescript": "^4.8.4"
|
||||
},
|
||||
"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.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.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.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
|
||||
}
|
||||
|
||||
export function vlogFast(path: AbsPath): Promise<Fast>;
|
||||
export function vlogAll(path: AbsPath): Promise<All>;
|
||||
export function vlogFast(path: AbsPath): Promise<Fast | undefined>;
|
||||
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 fs = require('fs');
|
||||
|
||||
const _hdlParser = {
|
||||
module: null,
|
||||
@ -17,22 +18,60 @@ const _hdlParser = {
|
||||
};
|
||||
|
||||
async function vlogFast(path) {
|
||||
if (!fs.existsSync(path)) {
|
||||
return undefined;
|
||||
}
|
||||
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' });
|
||||
const res = wasmModule.ccall('vlog_fast', 'string', ['string'], [_hdlParser.tempPath]);
|
||||
return JSON.parse(res);
|
||||
}
|
||||
|
||||
async function vlogAll(path) {
|
||||
if (!fs.existsSync(path)) {
|
||||
return undefined;
|
||||
}
|
||||
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' });
|
||||
const res = wasmModule.ccall('vlog_all', 'string', ['string'], [_hdlParser.tempPath]);
|
||||
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 = {
|
||||
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 { opeParam } from './global';
|
||||
import { opeParam, MainOutput, ReportType } from './global';
|
||||
import { hdlParam } from './hdlParser';
|
||||
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);
|
||||
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) {
|
||||
console.log('Digital-IDE 0.3.0 is launched');
|
||||
launch(context);
|
||||
|
||||
}
|
||||
|
||||
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 { PrjInfo, PrjInfoDefaults } from './prjInfo';
|
||||
import { MainOutput, YosysOutput, ReportType } from './outputChannel';
|
||||
|
||||
import * as Enum from './enum';
|
||||
import * as Lang from './lang';
|
||||
@ -15,5 +16,8 @@ export {
|
||||
Enum,
|
||||
Lang,
|
||||
AbsPath,
|
||||
RelPath
|
||||
RelPath,
|
||||
MainOutput,
|
||||
YosysOutput,
|
||||
ReportType
|
||||
};
|
@ -24,7 +24,7 @@ class Output {
|
||||
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) {
|
||||
this._output.show(true);
|
||||
this._output.appendLine('[' + type + '] ' + message);
|
||||
|
@ -75,7 +75,8 @@ function isHDLFile(path: AbsPath): boolean {
|
||||
|
||||
|
||||
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) ||
|
||||
(path instanceof Set)) {
|
||||
const hdlFiles: AbsPath[] = [];
|
||||
path.forEach(p => hdlFiles.push(...pickFileRecursive(p)));
|
||||
path.forEach(p => hdlFiles.push(...pickFileRecursive(p, ignores, condition)));
|
||||
return hdlFiles;
|
||||
}
|
||||
|
||||
@ -124,11 +125,11 @@ function getLanguageId(path: AbsPath | RelPath): HdlLangID {
|
||||
return HdlLangID.Unknown;
|
||||
}
|
||||
const ext = hdlPath.extname(path, false);
|
||||
if (verilogExts.includes(path)) {
|
||||
if (verilogExts.includes(ext)) {
|
||||
return HdlLangID.Verilog;
|
||||
} else if (vhdlExts.includes(path)) {
|
||||
} else if (vhdlExts.includes(ext)) {
|
||||
return HdlLangID.Vhdl;
|
||||
} else if (systemVerilogExts.includes(path)) {
|
||||
} else if (systemVerilogExts.includes(ext)) {
|
||||
return HdlLangID.SystemVerilog;
|
||||
} else {
|
||||
return HdlLangID.Unknown;
|
||||
|
@ -1,16 +1,17 @@
|
||||
import * as vscode from 'vscode';
|
||||
import { opeParam, AbsPath, Enum } from '../global';
|
||||
import * as hdlPath from './path';
|
||||
|
||||
interface IconConfig {
|
||||
light: AbsPath
|
||||
dark: AbsPath
|
||||
readonly light: vscode.Uri
|
||||
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 svgDir = hdlPath.join(opeParam.extensionPath, 'images', 'svg');
|
||||
const iconPath = hdlPath.join(svgDir, themeType, iconFile);
|
||||
return iconPath;
|
||||
return vscode.Uri.file(iconPath);
|
||||
}
|
||||
|
||||
function getIconConfig(iconName: string): IconConfig {
|
||||
@ -20,7 +21,7 @@ function getIconConfig(iconName: string): IconConfig {
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
export {
|
||||
getIconPath,
|
||||
getIconConfig
|
||||
};
|
@ -72,6 +72,7 @@ interface HdlModulePort {
|
||||
type: HdlModulePortType
|
||||
width: string
|
||||
range: Range
|
||||
desc?: string
|
||||
};
|
||||
|
||||
interface HdlModuleParam {
|
||||
@ -80,6 +81,7 @@ interface HdlModuleParam {
|
||||
type: string
|
||||
init: string
|
||||
range: Range
|
||||
desc?: string
|
||||
};
|
||||
|
||||
type InstRange = Range | null;
|
||||
|
@ -1,8 +1,10 @@
|
||||
import { AbsPath } from '../global';
|
||||
import { HdlLangID } from '../global/enum';
|
||||
import { MainOutput, ReportType } from '../global/outputChannel';
|
||||
|
||||
import * as common from './common';
|
||||
import { hdlFile, hdlPath } from '../hdlFs';
|
||||
import { HdlSymbol } from './util';
|
||||
|
||||
class HdlParam {
|
||||
private readonly topModules : Set<HdlModule> = new Set<HdlModule>();
|
||||
@ -57,6 +59,12 @@ class HdlParam {
|
||||
return hdlFile.getHdlModule(name);
|
||||
}
|
||||
|
||||
public getAllHdlModules(): HdlModule[] {
|
||||
const hdlModules: HdlModule[] = [];
|
||||
this.modules.forEach(m => hdlModules.push(m));
|
||||
return hdlModules;
|
||||
}
|
||||
|
||||
public addHdlModule(hdlModule: HdlModule) {
|
||||
this.modules.add(hdlModule);
|
||||
}
|
||||
@ -73,6 +81,30 @@ class HdlParam {
|
||||
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> {
|
||||
switch (hdlModule.file.type) {
|
||||
case common.HdlFileType.Src: return this.srcTopModules;
|
||||
@ -148,6 +180,29 @@ class HdlParam {
|
||||
public deleteUnhandleInstance(inst: HdlInstance) {
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
@ -226,7 +281,7 @@ class HdlModule {
|
||||
range: common.Range;
|
||||
params: common.HdlModuleParam[];
|
||||
ports: common.HdlModulePort[];
|
||||
private rawInstances: common.RawHdlInstance[];
|
||||
private rawInstances: common.RawHdlInstance[] | undefined;
|
||||
private nameToInstances: Map<string, HdlInstance>;
|
||||
private unhandleInstances: Set<HdlInstance>;
|
||||
private globalRefers: Set<HdlInstance>;
|
||||
@ -272,6 +327,10 @@ class HdlModule {
|
||||
return this.file.path;
|
||||
}
|
||||
|
||||
public get languageId(): HdlLangID {
|
||||
return this.file.languageId;
|
||||
}
|
||||
|
||||
public getInstance(name: string): HdlInstance | undefined {
|
||||
return this.nameToInstances.get(name);
|
||||
}
|
||||
@ -309,6 +368,19 @@ class HdlModule {
|
||||
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) {
|
||||
const inst = this.getInstance(name);
|
||||
this.deleteInstance(inst);
|
||||
@ -518,9 +590,17 @@ class HdlFile {
|
||||
}
|
||||
}
|
||||
|
||||
public makeInstance() {
|
||||
for (const module of this.getAllHdlModules()) {
|
||||
module.makeNameToInstances();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
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) {
|
||||
vlogAll(path);
|
||||
}
|
||||
namespace HdlSymbol {
|
||||
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
|
||||
* @descriptionCn xilinx工具链下PS端的操作类
|
||||
* @description xilinx工具链下PS端的操作类
|
||||
*/
|
||||
class XilinxOperation {
|
||||
public get config(): XilinxOperationConfig {
|
||||
|
@ -86,6 +86,7 @@ class PrjManage {
|
||||
searchPathSet.checkAdd(hardwareInfo.sim);
|
||||
|
||||
const searchPaths = searchPathSet.files;
|
||||
|
||||
return hdlFile.getHDLFiles(searchPaths, []);
|
||||
}
|
||||
|
||||
|
74
test.js
74
test.js
@ -1,20 +1,36 @@
|
||||
/* eslint-disable @typescript-eslint/naming-convention */
|
||||
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_FILE2 = './src/test/vlog/dependence_test/parent.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) {
|
||||
if (!fs.existsSync(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const state = fs.statSync(path);
|
||||
if (state.isDirectory()) {
|
||||
return true;
|
||||
@ -22,38 +38,38 @@ function isDir(path) {
|
||||
return false;
|
||||
}
|
||||
|
||||
function getHDLFiles(path) {
|
||||
if (isDir(path)) {
|
||||
const hdlFiles = [];
|
||||
function* walk(path, condition) {
|
||||
if (isFile(path)) {
|
||||
if (!condition || condition(path)) {
|
||||
yield path;
|
||||
}
|
||||
}
|
||||
else {
|
||||
for (const file of fs.readdirSync(path)) {
|
||||
const filePath = path + '/' + file;
|
||||
const filePath = fspath.join(path, file);
|
||||
if (isDir(filePath)) {
|
||||
const subHdlFiles = getHDLFiles(filePath);
|
||||
if (subHdlFiles.length > 0) {
|
||||
hdlFiles.push(...subHdlFiles);
|
||||
for (const targetPath of walk(filePath, condition)) {
|
||||
yield targetPath;
|
||||
}
|
||||
}
|
||||
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() => {
|
||||
const Module = await sysvlog_build();
|
||||
console.log(Object.keys(Module).filter(name => name.startsWith('_') && !name.startsWith('__')));
|
||||
const source = fs.readFileSync(TEST_FILE2, 'utf-8') + '\n';
|
||||
Module.FS.writeFile('/sysvlog_build', source, { encoding: 'utf8' });
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
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.log('cost time', costTime);
|
||||
console.time('test');
|
||||
for (const file of walk('./lib', f => f.endsWith('.v'))) {
|
||||
console.log(file);
|
||||
try {
|
||||
await vlogFast(file);
|
||||
} catch (err) {
|
||||
console.log(err);
|
||||
}
|
||||
}
|
||||
console.timeEnd('test');
|
||||
})();
|
@ -3,6 +3,7 @@
|
||||
"module": "commonjs",
|
||||
"target": "ES2020",
|
||||
"outDir": "out",
|
||||
"skipLibCheck": true,
|
||||
"lib": [
|
||||
"ES2020"
|
||||
],
|
||||
|
Loading…
x
Reference in New Issue
Block a user