This commit is contained in:
锦恢 2024-02-27 16:17:39 +08:00
parent 0c21631357
commit b120bc39b7
18 changed files with 1549 additions and 275 deletions

941
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -9,9 +9,11 @@
}, },
"dependencies": { "dependencies": {
"core-js": "^3.8.3", "core-js": "^3.8.3",
"element-plus": "^2.5.6",
"mitt": "^3.0.1", "mitt": "^3.0.1",
"stream": "^0.0.2", "stream": "^0.0.2",
"vue": "^3.2.13" "vue": "^3.2.13",
"vue-i18n": "^9.9.1"
}, },
"devDependencies": { "devDependencies": {
"@babel/core": "^7.12.16", "@babel/core": "^7.12.16",
@ -20,7 +22,9 @@
"@vue/cli-plugin-eslint": "~5.0.0", "@vue/cli-plugin-eslint": "~5.0.0",
"@vue/cli-service": "~5.0.0", "@vue/cli-service": "~5.0.0",
"eslint": "^7.32.0", "eslint": "^7.32.0",
"eslint-plugin-vue": "^8.0.3" "eslint-plugin-vue": "^8.0.3",
"unplugin-auto-import": "^0.17.5",
"unplugin-vue-components": "^0.26.0"
}, },
"eslintConfig": { "eslintConfig": {
"root": true, "root": true,

View File

@ -52,4 +52,27 @@ html, body {
::-webkit-scrollbar-corner { ::-webkit-scrollbar-corner {
background: none; background: none;
display: none; display: none;
}
.el-select__wrapper {
background-color: transparent !important;
width: 50% !important;
min-width: 200px !important;
padding: 13px !important;
font-size: 16px !important;
color: var(--sidebar-item-text) !important;
}
.el-select__placeholder {
color: var(--sidebar-item-text) !important;
}
.el-select-dropdown {
min-width: 300px !important;
background-color: var(--sidebar);
border: 1px solid var(--main-color);
}
.el-checkbox-button__inner {
font-size: 16px !important;
} }

View File

@ -24,7 +24,7 @@
<script> <script>
import { onMounted, reactive } from 'vue'; import { onMounted, reactive } from 'vue';
import { getVcdStream, readVcdFile } from '@/hook/utils'; import { getVcdStream, readVcdFile } from '@/hook/utils';
import { emitter } from '@/hook/global'; import { emitter, globalLookup } from '@/hook/global';
import RightNav from '@/components/right-nav.vue'; import RightNav from '@/components/right-nav.vue';
@ -40,6 +40,18 @@ export default {
}); });
onMounted(async () => { onMounted(async () => {
//
document.body.style.setProperty('--el-color-primary', 'var(--main-color)');
document.body.style.setProperty('--el-color-primary-light-9', 'var(--main-color)');
document.body.style.setProperty('--el-color-primary-light-3', 'var(--main-color)');
document.body.style.setProperty('--el-text-color-secondary', 'var(--foreground)');
document.body.style.setProperty('--el-text-color-regular', 'var(--foreground)');
document.body.style.setProperty('--el-border-color', 'var(--vscode-focusBorder)');
document.body.style.setProperty('--el-fill-color-blank', 'var(--sidebar)');
document.body.style.setProperty('--el-fill-color-light', 'var(--vscode-button-hoverBackground)');
document.body.style.setProperty('--el-switch-on-color', 'var(--main-color)');
const uint8array = await readVcdFile(); const uint8array = await readVcdFile();
const vcdstream = await getVcdStream(); const vcdstream = await getVcdStream();
const maxChunkLength = 1 << 17; const maxChunkLength = 1 << 17;
@ -51,16 +63,17 @@ export default {
VcdInfo.topModules.push(topModule); VcdInfo.topModules.push(topModule);
} }
// timestamp when vcd is loaded //
// send wires of first module //
if (VcdInfo.topModules.length > 0) { if (VcdInfo.topModules.length > 0) {
const defaultMod = VcdInfo.topModules[0]; const defaultMod = VcdInfo.topModules[0];
const wires = defaultMod.body.filter(mod => mod.link); const wires = defaultMod.body.filter(mod => mod.link);
emitter.emit('tree-view', wires); emitter.emit('tree-view', wires);
// 便
for (const mod of VcdInfo.topModules) {
globalLookup.topModules.push(mod);
}
} }
}); });
return { return {

View File

@ -4,19 +4,18 @@
<img src="../../assets/icon.png" height="200px" alt=""> <img src="../../assets/icon.png" height="200px" alt="">
</div> </div>
<div class="version-caption"> <div class="version-caption">
<span>当前版本 &ensp; <span class="version-wrapper">0.3.3</span></span> <span>{{ t('current-version') }} &ensp; <span class="version-wrapper">0.3.3</span></span>
</div> </div>
<hr> <hr>
<div style="display: flex;justify-content: space-around;"> <div style="display: flex;justify-content: space-around;">
<div class="copyright-caption">本软件版权归 <div class="copyright-caption" v-html="t('copyright')"></div>
<a href="https://github.com/Digital-EDA" target="_blank">Digital-IDE</a> 项目组所有欢迎 <a href="https://github.com/Digital-EDA/Digital-IDE">Star</a></div>
<div class="copyright-caption">The copyright of this software belongs to
<a href="https://github.com/Digital-EDA" target="_blank">Digital-IDE</a> project team. Welcome to <a href="https://github.com/Digital-EDA/Digital-IDE">Star</a>.</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { useI18n } from 'vue-i18n';
export default { export default {
name: 'dide-about', name: 'dide-about',
setup() { setup() {
@ -24,8 +23,11 @@ export default {
window.open(url, '_blank'); window.open(url, '_blank');
} }
const { t } = useI18n();
return { return {
goto goto,
t
} }
} }
} }

View File

@ -1,20 +1,75 @@
<template> <template>
<div class="setting-wrapper"> <div class="setting-wrapper">
<div class="section"> <div class="setting-section">
<h2>{{ t('search-setting') }}</h2>
<div class="setting-option">
<span class="option-title">{{ t('case-sensitivity') }}</span>
<el-switch v-model="globalSetting.caseSensitivity" />
</div>
<br>
<div class="setting-option">
<span class="option-title">{{ t('search-scope') }}</span>
<el-checkbox-group v-model="globalSetting.searchScope" size="default">
<el-checkbox-button label="wire" border>wire </el-checkbox-button>
<el-checkbox-button label="reg" border>reg </el-checkbox-button>
<el-checkbox-button label="module" border>module</el-checkbox-button>
</el-checkbox-group>
</div>
</div> </div>
<hr> <hr>
<div class="section">
<div class="setting-section">
<h2>{{ t('general-setting') }}</h2>
<div class="setting-option" style="width: 300px;">
<span class="option-title">{{ t('language-setting') }}</span>
<el-select name="language-setting" class="language-setting" v-model="locale">
<el-option
v-for="option in languageSetting.options"
:value="option.value"
:label="option.text"
:key="option.value">
</el-option>
</el-select>
</div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
import { reactive } from 'vue';
import { useI18n } from 'vue-i18n';
import { globalSetting } from '@/hook/global';
export default { export default {
name: 'dide-setting', name: 'dide-setting',
setup() { setup() {
const { t, locale } = useI18n();
const languageSetting = reactive({
options: [
{
value: 'en',
text: 'English'
},
{
value: 'zh',
text: '中文'
}
]
});
return {
t,
languageSetting,
globalSetting,
locale
}
} }
} }
</script> </script>
@ -22,12 +77,30 @@ export default {
<style> <style>
.setting-wrapper { .setting-wrapper {
width: 600px; width: 600px;
padding: 10px;
} }
.setting-wrapper section { .setting-section {
padding: 10px; padding: 10px;
margin: 10px; margin: 10px;
border-radius: .3em; border-radius: .3em;
min-height: 50px; min-height: 50px;
} }
.setting-option {
margin: 5px;
padding: 10px 12px;
height: 40px;
width: fit-content;
border-radius: .5em;
background-color: var(--background);
display: flex;
align-items: center;
}
.option-title {
min-width: 80px;
margin-right: 12px;
}
</style> </style>

View File

@ -3,17 +3,17 @@
<div class="vcd-treeview"> <div class="vcd-treeview">
<TreeViewSearch></TreeViewSearch> <TreeViewSearch></TreeViewSearch>
<br> <br>
<div style="display: flex;"> <div class="vcd-module-wrapper">
<div class="vcd-signal-info"> <div class="vcd-module-info">
<div>Modules</div> <div>{{ t('module') }}</div>
<hr> <hr>
<Signals v-for="mod of props.topModules" <Modules v-for="mod of props.topModules"
:key="mod.name" :key="mod.name"
:signal="mod" :module="mod"
></Signals> ></Modules>
</div> </div>
<div class="vcd-signal-wires"> <div class="vcd-module-wires">
<Wires></Wires> <Signals></Signals>
</div> </div>
</div> </div>
</div> </div>
@ -21,46 +21,44 @@
<script> <script>
import { onMounted } from 'vue'; import { onMounted } from 'vue';
import { useI18n } from 'vue-i18n';
import TreeViewSearch from '@/components/treeview/search.vue'; import TreeViewSearch from '@/components/treeview/search.vue';
import Modules from '@/components/treeview/modules.vue';
import Signals from '@/components/treeview/signals.vue'; import Signals from '@/components/treeview/signals.vue';
import Wires from '@/components/treeview/wires.vue';
import { emitter } from '@/hook/global';
export default { export default {
name: 'tree-view', name: 'tree-view',
components: { components: {
Modules,
Signals, Signals,
Wires,
TreeViewSearch TreeViewSearch
}, },
props: { props: {
topModules: Array topModules: Array
}, },
setup(props) { setup(props) {
onMounted(() => { const { t } = useI18n();
});
return { return {
props props,
t
} }
} }
} }
</script> </script>
<style> <style>
.vcd-signal-info { .vcd-module-info {
height: 80vh; height: 80vh;
width: 300px; width: 300px;
padding-right: 5px; padding-right: 5px;
overflow-x: scroll; overflow-x: scroll;
} }
.vcd-signal-wires { .vcd-module-wires {
height: 80vh; height: 80vh;
width: 300px; width: 300px;
overflow-x: scroll; overflow-x: scroll;
@ -68,9 +66,17 @@ export default {
.vcd-treeview { .vcd-treeview {
background-color: var(--sidebar); background-color: var(--sidebar);
padding: 10px; padding: 10px 10px 10px 10px;
height: fit-content; height: 98vh;
border-radius: 1.0em; border-radius: 1.0em;
display: flex;
flex-direction: column;
}
.vcd-module-wrapper {
flex: 1;
display: flex;
overflow: scroll;
} }
</style> </style>

View File

@ -0,0 +1,139 @@
<template>
<div class="module">
<div @click="clickItem()" class="vcd-treeview-item"
:class="module === globalLookup.currentModule ? 'vcd-treeview-selected' : ''">
<span class="module-tag-status" @click.stop="expandManage.click">
<div :class="expandManage.expandTagClass"></div>
</span>
<span class="iconfont icon-memory-chip"></span>
&ensp;{{ module.name }}
</div>
<div v-if="mods.length > 0" v-show="expandManage.expanded" class="vcd-subtree-wrapper">
<div style="width: 20px;"></div>
<div style="width: 100%;">
<modules
v-for="(child, index) in mods"
:module="child"
:key="index"
></modules>
</div>
</div>
</div>
</template>
<script>
/* eslint-disable */
import { reactive, onMounted } from 'vue';
import { emitter, globalLookup } from '@/hook/global';
export default {
name: "modules",
props: {
module: Object
},
setup(props) {
const module = props.module;
globalLookup.initcurrentModule(module);
const signals = [];
const mods = [];
for (const wire of module.body) {
if (wire.body) {
mods.push(wire);
} else {
signals.push(wire);
}
}
function clickItem() {
emitter.emit('tree-view', signals);
// color change into selected
globalLookup.currentModule = module;
}
const expandManage = reactive({
expanded: true,
expandTagClass: mods.length === 0 ? '' : 'expand-tag',
click() {
this.expanded = !this.expanded;
if (this.expandTagClass) {
this.expandTagClass = this.expanded ? 'expand-tag' : 'collapse-tag';
}
}
});
return {
module,
mods,
signals,
clickItem,
expandManage,
globalLookup
}
}
};
</script>
<style>
.icon-memory-chip {
color: #FF7043;
}
.module {
text-align: left;
}
.vcd-subtree-wrapper {
display: flex;
width: 100%;
}
.vcd-treeview-item {
color: var(--sidebar-item-text);
cursor: pointer;
height: 27px;
display: flex;
align-items: center;
}
.vcd-treeview-item::selection {
background: none;
}
.vcd-treeview-item:hover {
background-color: var(--vscode-button-hoverBackground);
border-radius: .3em;
}
.vcd-treeview-selected {
background-color: var(--vscode-button-hoverBackground);
border-radius: .3em;
}
.module-tag-status {
width: 25px;
height: 25px;
align-items: center;
justify-content: space-around;
display: flex;
}
.expand-tag {
height: 7px;
width: 7px;
border-top: solid 1.7px var(--sidebar-item-text);
border-left: solid 1.7px var(--sidebar-item-text);
transform: rotate(225deg);
}
.collapse-tag {
height: 7px;
width: 7px;
border-top: solid 1.7px var(--sidebar-item-text);
border-left: solid 1.7px var(--sidebar-item-text);
transform: rotate(135deg);
}
</style>

View File

@ -1,17 +1,91 @@
<template> <template>
<div class="tree-view-search-wrapper"> <div class="tree-view-search-wrapper">
<input type="text" class="tree-view-search" placeholder="Search Signal"> <div>
<el-input
:placeholder="t('search-signal')"
size="large"
v-model="searchManage.content"
input-style="font-size: 16px;"
@input="safeSearch"
/>
</div>
<div class="search-result" v-if="searchManage.content.trim().length > 0">
<div v-if="searchManage.searchResult.length > 0">
<div class="search-result-item"
v-for="(searchResult, index) in searchManage.searchResult"
:key="index"
:class="globalLookup.currentWires.has(searchResult.module) ? 'vcd-treeview-selected' : ''"
v-html="searchResult.htmlString"
@click="clickItem(searchResult.module)">
</div>
</div>
<div v-else>
{{ t('search-nothing') }}
</div>
</div>
</div> </div>
</template> </template>
<script> <script>
import { reactive } from 'vue';
import { useI18n } from 'vue-i18n';
import { globalSetting, globalLookup } from '@/hook/global';
import { debounceWrapper, makeSearchResultItem } from '@/hook/utils';
export default { export default {
name: 'tree-view-search', name: 'tree-view-search',
setup() { setup() {
const { t } = useI18n();
const searchManage = reactive({
content: '',
searchResult: []
});
function search() {
const searchString = searchManage.content.trim();
if (searchString.length === 0) {
return;
}
searchManage.searchResult = [];
const stacks = [ { name: '', body: globalLookup.topModules } ];
const searchRule = new Set(globalSetting.searchScope);
const caseSensitivity = globalSetting.caseSensitivity;
while (stacks.length > 0) {
const p = stacks.pop();
if (p.body && p.body.length) {
p.body.forEach(mod => stacks.push(mod));
}
const searchResultItem = makeSearchResultItem(searchString, p, searchRule, caseSensitivity);
if (searchResultItem) {
searchManage.searchResult.push(searchResultItem);
}
}
}
function clickItem(signal) {
if (!signal.link) {
return;
}
if (globalLookup.currentWires.has(signal)) {
globalLookup.currentWires.delete(signal);
} else {
globalLookup.currentWires.add(signal);
}
}
const safeSearch = debounceWrapper(search, 500);
return { return {
searchManage,
safeSearch,
globalLookup,
debounceWrapper,
t,
clickItem
} }
} }
} }
@ -19,33 +93,39 @@ export default {
<style> <style>
.tree-view-search-wrapper { .tree-view-search-wrapper {
height: 30px; min-height: 30px;
padding: 10px; padding: 10px;
margin-bottom: 10px;
} }
.tree-view-search[type="text"] { .search-result {
color: var(--input-foreground); overflow-x: hidden;
background-color: var(--input-background); overflow-y: scroll;
border-radius: var(--input-radius); padding: 10px;
border: .5px solid var(--input-border); margin: 10px;
font-size: 18px; max-height: 40vh;
padding: 6px;
width: 98%;
} }
.tree-view-search[type="text"]:focus { .search-result-item {
color: var(--input-active-foreground); display: flex;
background-color: var(--input-active-background); align-items: center;
border: .5px solid var(--input-active-border); height: 25px;
outline: none; margin: 3px;
padding-left: 3px;
cursor: pointer;
} }
.tree-view-search[type="text"]:hover { .search-result-item:hover {
background-color: var(--input-hover); background-color: var(--vscode-button-hoverBackground);
border-radius: .3em;
} }
.tree-view-search[type="text"]::placeholder { .dep-arrow {
color: var(--input-placeholder); height: 7px;
width: 7px;
border-top: solid 1.7px var(--sidebar-item-text);
border-left: solid 1.7px var(--sidebar-item-text);
transform: rotate(135deg);
margin-right: 8px;
margin-left: 3px;
} }
</style> </style>

View File

@ -1,139 +1,105 @@
<template> <template>
<div class="signal"> <div>
<div @click="clickItem()" class="vcd-treeview-item" <div>{{ t('signal') }}({{signals.content.length}})</div>
:class="signal === globalLookup.currentSignal ? 'vcd-treeview-selected' : ''"> <hr>
<span class="signal-tag-status" @click.stop="expandManage.click"> <div class="vcd-signal-signals-display">
<div :class="expandManage.expandTagClass"></div> <div v-for="(signal, index) in signals.content" :key="index"
</span> @click="clickItem(signal)"
<span class="iconfont icon-memory-chip"></span> class="vcd-signal-signal-item"
&ensp;{{ signal.name }} :class="globalLookup.currentWires.has(signal) ? 'vcd-treeview-selected' : ''">
</div> <div><span class="iconfont icon-wave-square"></span>&ensp;{{ signal.name }}</div>
<div>
<div v-if="signal.body" v-show="expandManage.expanded" class="vcd-subtree-wrapper"> <div :class="signal.caption ? 'vcd-signal-signal-caption' : ''">
<div style="width: 20px;"></div> {{ signal.caption }}
<div style="width: 100%;"> </div>
<signals </div>
v-for="(child, index) in signal.body"
:signal="child"
:key="index"
></signals>
</div> </div>
</div> </div>
</div> </div>
</template> </template>
<script> <script>
/* eslint-disable */ import { reactive } from 'vue';
import { reactive, onMounted } from 'vue'; import { useI18n } from 'vue-i18n';
import { emitter, globalLookup } from '@/hook/global'; import { emitter, globalLookup } from '@/hook/global';
/* eslint-disable */
export default { export default {
name: "signals", name: 'signals',
props: { props: {},
signal: Object setup() {
}, const { t } = useI18n();
setup(props) {
const signal = props.signal;
const signalChildern = signal.body;
globalLookup.initCurrentSignal(signal); // signal : link, name, size, type
const signals = reactive({
content: []
});
const wires = []; emitter.on('tree-view', sendWires => {
signal.body = []; signals.content.length = 0;
for (const wire of signalChildern) { for (const signal of sendWires) {
if (wire.body) { const caption = signal.size === 1 ? '' : `${signal.size - 1}:0`;
signal.body.push(wire); signals.content.push({
} else { name: signal.name,
wires.push(wire); caption
} });
}
function clickItem() {
emitter.emit('tree-view', wires);
// color change into selected
globalLookup.currentSignal = signal;
}
const expandManage = reactive({
expanded: true,
expandTagClass: signal.body.length === 0 ? '' : 'expand-tag',
click() {
this.expanded = !this.expanded;
if (this.expandTagClass) {
this.expandTagClass = this.expanded ? 'expand-tag' : 'collapse-tag';
}
} }
}); });
function clickItem(signal) {
if (globalLookup.currentWires.has(signal)) {
globalLookup.currentWires.delete(signal);
} else {
globalLookup.currentWires.add(signal);
}
}
return { return {
signal, signals,
clickItem, clickItem,
expandManage, globalLookup,
globalLookup t
} }
} }
}; }
</script> </script>
<style> <style>
.icon-memory-chip { .icon-wave-square {
color: #FF7043; color: #00F600;
} }
.signal { .vcd-signal-signals-display {
text-align: left;
}
.vcd-subtree-wrapper {
display: flex;
width: 100%;
}
.vcd-treeview-item {
color: var(--sidebar-item-text); color: var(--sidebar-item-text);
cursor: pointer; padding: 0px 8px;
height: 27px; }
.vcd-signal-signal-item {
margin: 3px;
display: flex; display: flex;
justify-content: space-between;
height: 25px;
padding-left: 3px;
cursor: pointer;
align-items: center; align-items: center;
} }
.vcd-treeview-item::selection {
.vcd-signal-signal-item::selection {
background: none; background: none;
} }
.vcd-treeview-item:hover { .vcd-signal-signal-item:hover {
background-color: var(--vscode-button-hoverBackground); background-color: var(--vscode-button-hoverBackground);
border-radius: .3em; border-radius: .3em;
} }
.vcd-treeview-selected { .vcd-signal-signal-caption {
background-color: var(--vscode-button-hoverBackground); color: var(--sidebar-item-text);
border-radius: .3em; border-radius: .5em;
background-color: var(--color-deepPurple);
padding: 3px;
font-size: 15px;
} }
</style>
.signal-tag-status {
width: 25px;
height: 25px;
align-items: center;
justify-content: space-around;
display: flex;
}
.expand-tag {
height: 7px;
width: 7px;
border-top: solid 1.7px var(--sidebar-item-text);
border-left: solid 1.7px var(--sidebar-item-text);
transform: rotate(225deg);
}
.collapse-tag {
height: 7px;
width: 7px;
border-top: solid 1.7px var(--sidebar-item-text);
border-left: solid 1.7px var(--sidebar-item-text);
transform: rotate(135deg);
}
</style>

View File

@ -1,94 +0,0 @@
<template>
<div>
<div>Signals({{wires.content.length}})</div>
<hr>
<div class="vcd-signal-wires-display">
<div v-for="(wire, index) in wires.content" :key="index"
@click="clickItem(wire)"
class="vcd-signal-wire-item"
:class="globalLookup.currentWires.has(wire) ? 'vcd-treeview-selected' : ''">
<div><span class="iconfont icon-wave-square"></span>&ensp;{{ wire.name }}</div>
<div>
<div :class="wire.caption ? 'vcd-signal-wire-caption' : ''">
{{ wire.caption }}
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import { reactive } from 'vue';
import { emitter, globalLookup } from '@/hook/global';
/* eslint-disable */
export default {
name: 'wires',
props: {},
setup() {
// wire : link, name, size, type
const wires = reactive({
content: []
});
emitter.on('tree-view', sendWires => {
wires.content.length = 0;
for (const wire of sendWires) {
const caption = wire.size === 1 ? '' : `${wire.size - 1}:0`;
wires.content.push({
name: wire.name,
caption
});
}
});
function clickItem(wire) {
if (globalLookup.currentWires.has(wire)) {
globalLookup.currentWires.delete(wire);
} else {
globalLookup.currentWires.add(wire);
}
}
return {
wires,
clickItem,
globalLookup
}
}
}
</script>
<style>
.icon-wave-square {
color: #00F600;
}
.vcd-signal-wires-display {
color: var(--sidebar-item-text);
padding: 0px 8px;
}
.vcd-signal-wire-item {
margin: 3px;
display: flex;
justify-content: space-between;
height: 25px;
cursor: pointer;
align-items: center;
}
.vcd-signal-wire-item:hover {
background-color: var(--vscode-button-hoverBackground);
border-radius: .3em;
}
.vcd-signal-wire-caption {
color: var(--sidebar-item-text);
border-radius: .5em;
background-color: var(--color-deepPurple);
padding: 3px;
font-size: 15px;
}
</style>

View File

@ -5,21 +5,31 @@ const emitter = mitt();
// 用于记载全局的一些对象,以便在不同组件中比较 ID // 用于记载全局的一些对象,以便在不同组件中比较 ID
const globalLookup = reactive({ const globalLookup = reactive({
// 所有的顶层文件
topModules: [],
// 当前选中的 信号,也就是 tree-view 左列的,默认是第一个。不可复选。 // 当前选中的 信号,也就是 tree-view 左列的,默认是第一个。不可复选。
currentSignal: undefined, currentModule: undefined,
// 当前选中的某个 信号 的 数据。可复选。 // 当前选中的某个 信号 的 数据。可复选。
currentWires: new Set(), currentWires: new Set(),
initCurrentSignal(signal) { initcurrentModule(module) {
if (this.currentSignal === undefined && signal) { if (this.currentModule === undefined && module) {
this.currentSignal = signal; this.currentModule = module;
}
// 创造 parent
if (module.body && module.body instanceof Array) {
for (const childModule of module.body) {
childModule.parent = module;
}
} }
} }
}); });
const globalSetting = { const globalSetting = reactive({
caseSensitivity: false caseSensitivity: false,
}; searchMode: 'so', // so, mo, sm
searchScope: ['wire', 'reg']
})
export { export {
emitter, emitter,

View File

@ -28,7 +28,72 @@ async function readVcdFile() {
}); });
} }
function debounceWrapper(fn, delay) {
let timer
return function () {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn()
}, delay)
}
}
/**
* @param { string } searchString
* @param {{
* kind: 'var' | 'scope',
* type: 'wire' | 'reg' | 'module',
* name: string,
* size?: number,
* link?: string
* }} module
* @param { Set<string> } searchScope
* @param { boolean } caseSensitivity
* @returns { { htmlString: string, module } | null }
*/
function makeSearchResultItem(searchString, module, searchScope, caseSensitivity) {
if (searchScope.has(module.type)) {
let pattern = module.name;
if (!caseSensitivity) {
pattern = pattern.toLowerCase();
searchString = searchString.toLowerCase();
}
if (pattern.includes(searchString)) {
let p = module;
const deps = [];
while (p) {
if (p.name && p.type) {
deps.push(p);
}
p = p.parent;
}
let htmlString = '';
for (let i = deps.length - 1; i >= 0; -- i) {
const mod = deps[i];
if (mod.type === 'module') {
htmlString += '<span class="iconfont icon-memory-chip"></span>&ensp;' + mod.name;
} else {
htmlString += '<span class="iconfont icon-wave-square"></span>&ensp;' + mod.name;
}
if (i > 0) {
htmlString += '<div class="dep-arrow"></div>';
}
}
return {
htmlString,
module
};
}
}
return null;
}
export { export {
getVcdStream, getVcdStream,
readVcdFile readVcdFile,
debounceWrapper,
makeSearchResultItem
}; };

17
src/i18n/en.json Normal file
View File

@ -0,0 +1,17 @@
{
"module": "Modules",
"signal": "Signals",
"search-signal": "Search Signal",
"language-setting": "Language",
"search-setting": "Search",
"case-sensitivity": "case sensitivity",
"search-mode": "search mode",
"search-scope": "search scope",
"signal-only": "Signal Only",
"module-only": "Module Only",
"signal-module": "Signal + Module",
"general-setting": "General",
"current-version": "current version",
"search-nothing": "find nothing",
"copyright": "The copyright of this software belongs to <a href=\"https://github.com/Digital-EDA\" target=\"_blank\">Digital-IDE</a> project team. Welcome to <a href=\"https://github.com/Digital-EDA/Digital-IDE\">Star</a>."
}

12
src/i18n/index.js Normal file
View File

@ -0,0 +1,12 @@
import { createI18n } from 'vue-i18n';
import en from './en.json';
import zh from './zh.json';
const i18n = createI18n({
legacy: false,
locale: 'en',
messages: { en, zh }
});
export default i18n;

17
src/i18n/zh.json Normal file
View File

@ -0,0 +1,17 @@
{
"module": "模块",
"signal": "信号",
"search-signal": "搜索信号",
"language-setting": "语言",
"search-setting": "搜索",
"case-sensitivity": "区分大小写",
"search-mode": "搜索模式",
"search-scope": "搜索范围",
"signal-only": "信号",
"module-only": "模块",
"signal-module": "信号 + 模块",
"general-setting": "通用",
"current-version": "当前版本",
"search-nothing": "没有找到任何符号",
"copyright": "本软件版权归 <a href=\"https://github.com/Digital-EDA\" target=\"_blank\">Digital-IDE</a> 项目组所有,欢迎 <a href=\"https://github.com/Digital-EDA/Digital-IDE\">Star</a>。"
}

View File

@ -1,4 +1,10 @@
import { createApp } from 'vue' import { createApp } from 'vue';
import App from './App.vue' import App from './App.vue';
import i18n from './i18n';
import ElementPlus from 'element-plus'
import 'element-plus/dist/index.css'
createApp(App).mount('#app') createApp(App)
.use(i18n)
.use(ElementPlus)
.mount('#app')

14
webpack.config.js Normal file
View File

@ -0,0 +1,14 @@
const AutoImport = require('unplugin-auto-import/webpack')
const Components = require('unplugin-vue-components/webpack')
const { ElementPlusResolver } = require('unplugin-vue-components/resolvers')
module.exports = {
plugins: [
AutoImport({
resolvers: [ElementPlusResolver()],
}),
Components({
resolvers: [ElementPlusResolver()],
}),
],
}