feat:接入波形查看器的工具

- 生成VCD文件后,就自动打开波形查看的工具显示波形
This commit is contained in:
Roe-xin
2025-12-15 11:51:35 +08:00
parent 22b9a0ed13
commit ab6d257df2
10 changed files with 642 additions and 11 deletions

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
media/vcdrom/vcd.wasm Normal file

Binary file not shown.

13
media/vcdrom/vcdrom.js Normal file

File diff suppressed because one or more lines are too long

View File

@ -37,6 +37,11 @@
"command": "ic-coder.openChat", "command": "ic-coder.openChat",
"title": "IC Coder: 打开聊天", "title": "IC Coder: 打开聊天",
"category": "IC Coder" "category": "IC Coder"
},
{
"command": "ic-coder.openVCDViewer",
"title": "打开 VCD 波形查看器",
"category": "IC Coder"
} }
], ],
"viewsContainers": { "viewsContainers": {
@ -89,6 +94,12 @@
"tools" "tools"
], ],
"dependencies": { "dependencies": {
"iconv-lite": "^0.7.1" "@wavedrom/doppler": "^1.14.0",
"iconv-lite": "^0.7.1",
"onml": "^2.1.0",
"style-mod": "^4.1.3",
"vcd-stream": "^1.5.0",
"vcdrom": "^1.6.0",
"waveql": "^1.9.0"
} }
} }

228
pnpm-lock.yaml generated
View File

@ -8,9 +8,27 @@ importers:
.: .:
dependencies: dependencies:
'@wavedrom/doppler':
specifier: ^1.14.0
version: 1.14.0
iconv-lite: iconv-lite:
specifier: ^0.7.1 specifier: ^0.7.1
version: 0.7.1 version: 0.7.1
onml:
specifier: ^2.1.0
version: 2.1.0
style-mod:
specifier: ^4.1.3
version: 4.1.3
vcd-stream:
specifier: ^1.5.0
version: 1.5.0
vcdrom:
specifier: ^1.6.0
version: 1.6.0
waveql:
specifier: ^1.9.0
version: 1.9.0
devDependencies: devDependencies:
'@types/mocha': '@types/mocha':
specifier: ^10.0.10 specifier: ^10.0.10
@ -52,6 +70,21 @@ packages:
resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==}
engines: {node: '>=18'} engines: {node: '>=18'}
'@codemirror/autocomplete@6.18.6':
resolution: {integrity: sha512-PHHBXFomUs5DF+9tCOM/UoW6XQ4R44lLNNhRaW9PKPTU0D7lIjRg3ElxaJnTwsl/oHiR93WSXDBrekhoUGCPtg==}
'@codemirror/commands@6.8.1':
resolution: {integrity: sha512-KlGVYufHMQzxbdQONiLyGQDUW0itrLZwq3CcY7xpv9ZLRHqzkBSoteocBHtMCoY7/Ci4xhzSrToIeLg7FxHuaw==}
'@codemirror/language@6.11.2':
resolution: {integrity: sha512-p44TsNArL4IVXDTbapUmEkAlvWs2CFQbcfc0ymDsis1kH2wh0gcY96AS29c/vp2d0y2Tquk1EDSaawpzilUiAw==}
'@codemirror/state@6.4.1':
resolution: {integrity: sha512-QkEyUiLhsJoZkbumGZlswmAhA7CBU02Wrz7zvH4SrcifbsqwlXShVXg65f3v/ts57W3dqyamEriMhij1Z3Zz4A==}
'@codemirror/view@6.35.2':
resolution: {integrity: sha512-u04R04XFCYCNaHoNRr37WUUAfnxKPwPdqV+370NiO6i85qB1J/qCD/WbbMJsyJfRWhXIJXAe2BG/oTzAggqv4A==}
'@discoveryjs/json-ext@0.6.3': '@discoveryjs/json-ext@0.6.3':
resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==} resolution: {integrity: sha512-4B4OijXeVNOPZlYA2oEwWOTkzyltLao+xbotHQeqN++Rv27Y6s818+n2Qkp8q+Fxhn0t/5lA5X1Mxktud8eayQ==}
engines: {node: '>=14.17.0'} engines: {node: '>=14.17.0'}
@ -134,10 +167,22 @@ packages:
'@jridgewell/trace-mapping@0.3.31': '@jridgewell/trace-mapping@0.3.31':
resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==}
'@lezer/common@1.4.0':
resolution: {integrity: sha512-DVeMRoGrgn/k45oQNu189BoW4SZwgZFzJ1+1TV5j2NJ/KFC83oa/enRqZSGshyeMk5cPWMhsKs9nx+8o0unwGg==}
'@lezer/highlight@1.2.1':
resolution: {integrity: sha512-Z5duk4RN/3zuVO7Jq0pGLJ3qynpxUVsh7IbUbGj88+uV2ApSAn6kWg2au3iJb+0Zi7kKtqffIESgNcRXWZWmSA==}
'@lezer/lr@1.4.5':
resolution: {integrity: sha512-/YTRKP5yPPSo1xImYQk7AZZMAgap0kegzqCSYHjAL9x1AZ0ZQW+IpcEzMKagCsbTsLnVeWkxYrCNeXG8xEPrjg==}
'@pkgjs/parseargs@0.11.0': '@pkgjs/parseargs@0.11.0':
resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==}
engines: {node: '>=14'} engines: {node: '>=14'}
'@types/debug@4.1.5':
resolution: {integrity: sha512-Q1y515GcOdTHgagaVFhHnIFQ38ygs/kmxdNpvpou+raI9UO3YZcHDngBSYKQklcKlvA7iuQlmIKbzvmxcOE9CQ==}
'@types/eslint-scope@3.7.7': '@types/eslint-scope@3.7.7':
resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==} resolution: {integrity: sha512-MzMFlSLBqNF2gcHWO0G1vP/YQyfvrxZ0bF+u7mzUdZ1/xK4A4sru+nraZz5i3iEIk1l1uyicaDVTB4QbbEkAYg==}
@ -230,6 +275,9 @@ packages:
resolution: {integrity: sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==} resolution: {integrity: sha512-8ukpxv4wYe0iWMRQU18jhzJOHkeGKbnw7xWRX3Zw1WJA4cEKbHcmmLPdPrPtL6rhDcrlCZN+xKRpv09n4gRHYg==}
engines: {node: '>=16'} engines: {node: '>=16'}
'@wavedrom/doppler@1.14.0':
resolution: {integrity: sha512-LYzI70g30txDVHQcMvvJ1pnazdhWIOB6lnZUoya11+54lVgYdHn/lZJW8td7u0phHDwr7+WzV1Eqo/9Y2EHX9Q==}
'@webassemblyjs/ast@1.14.1': '@webassemblyjs/ast@1.14.1':
resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==} resolution: {integrity: sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==}
@ -379,6 +427,12 @@ packages:
resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==}
engines: {node: '>=8'} engines: {node: '>=8'}
binary-search@1.3.6:
resolution: {integrity: sha512-nbE1WxOTTrUWIfsfZ4aHGYu5DOuNkbxGokjV6Z2kxfJK3uaAb8zNK1muzOeipoLHZjInT4Br88BHpzevc681xA==}
bindings@1.5.0:
resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==}
brace-expansion@1.1.12: brace-expansion@1.1.12:
resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==}
@ -487,6 +541,14 @@ packages:
resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==}
engines: {node: '>= 8'} engines: {node: '>= 8'}
debug@3.2.7:
resolution: {integrity: sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==}
peerDependencies:
supports-color: '*'
peerDependenciesMeta:
supports-color:
optional: true
debug@4.4.3: debug@4.4.3:
resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==}
engines: {node: '>=6.0'} engines: {node: '>=6.0'}
@ -507,6 +569,10 @@ packages:
resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==} resolution: {integrity: sha512-PJWHUb1RFevKCwaFA9RlG5tCd+FO5iRh9A8HEtkmBH2Li03iJriB6m6JIN4rGz3K3JLawI7/veA1xzRKP6ISBw==}
engines: {node: '>=0.3.1'} engines: {node: '>=0.3.1'}
dot-prop@6.0.1:
resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==}
engines: {node: '>=10'}
eastasianwidth@0.2.0: eastasianwidth@0.2.0:
resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==}
@ -625,6 +691,9 @@ packages:
resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==}
engines: {node: '>=16.0.0'} engines: {node: '>=16.0.0'}
file-uri-to-path@1.0.0:
resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==}
fill-range@7.1.1: fill-range@7.1.1:
resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -776,6 +845,10 @@ packages:
resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==}
engines: {node: '>=0.12.0'} engines: {node: '>=0.12.0'}
is-obj@2.0.0:
resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==}
engines: {node: '>=8'}
is-path-inside@3.0.3: is-path-inside@3.0.3:
resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==}
engines: {node: '>=8'} engines: {node: '>=8'}
@ -865,6 +938,15 @@ packages:
lie@3.3.0: lie@3.3.0:
resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==} resolution: {integrity: sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==}
llparse-builder@1.5.2:
resolution: {integrity: sha512-i862UNC3YUEdlfK/NUCJxlKjtWjgAI9AJXDRgjcfRHfwFt4Sf8eFPTRsc91/2R9MBZ0kyFdfhi8SVhMsZf1gNQ==}
llparse-frontend@3.0.0:
resolution: {integrity: sha512-G/o0Po2C+G5OtP8MJeQDjDf5qwDxcO7K6x4r6jqGsJwxk7yblbJnRqpmye7G/lZ8dD0Hv5neY4/KB5BhDmEc9Q==}
llparse@7.3.0:
resolution: {integrity: sha512-9/CMwjsfGsvA6WuXFSxswpDxuZy5BgAeMnFxQYpDChC5rRrCxeRLyKl8djwMz7ZUN41QKfF/zYtZvL1PrDpVHw==}
loader-runner@4.3.1: loader-runner@4.3.1:
resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==} resolution: {integrity: sha512-IWqP2SCPhyVFTBtRcgMHdzlf9ul25NwaFx4wCEH/KjAXuuHY4yNjvPXsBokp8jCB936PyWRaPKUNh8NvylLp2Q==}
engines: {node: '>=6.11.5'} engines: {node: '>=6.11.5'}
@ -877,6 +959,10 @@ packages:
resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==}
engines: {node: '>=10'} engines: {node: '>=10'}
lodash.get@4.4.2:
resolution: {integrity: sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==}
deprecated: This package is deprecated. Use the optional chaining (?.) operator instead.
lodash.merge@4.6.2: lodash.merge@4.6.2:
resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==}
@ -950,6 +1036,9 @@ packages:
resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==}
engines: {node: '>=18'} engines: {node: '>=18'}
onml@2.1.0:
resolution: {integrity: sha512-fvaSZRzprpwLFge/mcwE0CItfniNisVNamDdMK1FQUjh4ArQZ8ZWSkDaJbZc3XaANKZHq0xIa8NJpZ2HSe3oXA==}
optionator@0.9.4: optionator@0.9.4:
resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==}
engines: {node: '>= 0.8.0'} engines: {node: '>= 0.8.0'}
@ -1085,6 +1174,9 @@ packages:
safer-buffer@2.1.2: safer-buffer@2.1.2:
resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==}
sax@1.4.3:
resolution: {integrity: sha512-yqYn1JhPczigF94DMS+shiDMjDowYO6y9+wB/4WgO0Y19jWYk0lQ4tuG5KI7kj4FTp1wxPj5IFfcrz/s1c3jjQ==}
schema-utils@4.3.3: schema-utils@4.3.3:
resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==} resolution: {integrity: sha512-eflK8wEtyOE6+hsaRVPxvUKYCpRgzLqDTb8krvAsRIwOGlHoSgYLgBXoubGgLd2fT41/OUYdb48v4k4WWHQurA==}
engines: {node: '>= 10.13.0'} engines: {node: '>= 10.13.0'}
@ -1158,6 +1250,9 @@ packages:
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
engines: {node: '>=8'} engines: {node: '>=8'}
style-mod@4.1.3:
resolution: {integrity: sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ==}
supports-color@10.2.2: supports-color@10.2.2:
resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==}
engines: {node: '>=18'} engines: {node: '>=18'}
@ -1259,10 +1354,23 @@ packages:
resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==}
engines: {node: '>=10.12.0'} engines: {node: '>=10.12.0'}
vcd-stream@1.5.0:
resolution: {integrity: sha512-w7IR4CuUv1KbpDjMu6YW6yRufK5qMTGAbc7ATbjfComVEq4lwSu+nJsFH2lGAsa9g+c3zzYoSDfazuy629eFnA==}
vcdrom@1.6.0:
resolution: {integrity: sha512-xvhbBOHrJb2zDhHTrdFjpOb2PWgcqqHh80YaRoVFFzYVtjrSGmj0mVsqxS5Tm1Gd9hoomdarQCaYJ+nMGWAM2A==}
w3c-keyname@2.2.8:
resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==}
watchpack@2.4.4: watchpack@2.4.4:
resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==} resolution: {integrity: sha512-c5EGNOiyxxV5qmTtAB7rbiXxi1ooX1pQKMLX/MIabJjRA0SJBQOjKF+KSVfHkr9U1cADPon0mRiVe/riyaiDUA==}
engines: {node: '>=10.13.0'} engines: {node: '>=10.13.0'}
waveql@1.9.0:
resolution: {integrity: sha512-rvli279IWUpDz+iesmrWk5tUwIAcSoy3Svvjw4rcXLPAWwRkCI7YUl7JJn10Az9QhahXk2tmo4lGD/7pPhWg8Q==}
engines: {node: '>=12'}
webpack-cli@6.0.1: webpack-cli@6.0.1:
resolution: {integrity: sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==} resolution: {integrity: sha512-MfwFQ6SfwinsUVi0rNJm7rHZ31GyTcpVE5pgVA3hwFRb7COD4TzjUUwhGWKfO50+xdc2MQPuEBBJoqIMGt3JDw==}
engines: {node: '>=18.12.0'} engines: {node: '>=18.12.0'}
@ -1342,6 +1450,37 @@ snapshots:
'@bcoe/v8-coverage@1.0.2': {} '@bcoe/v8-coverage@1.0.2': {}
'@codemirror/autocomplete@6.18.6':
dependencies:
'@codemirror/language': 6.11.2
'@codemirror/state': 6.4.1
'@codemirror/view': 6.35.2
'@lezer/common': 1.4.0
'@codemirror/commands@6.8.1':
dependencies:
'@codemirror/language': 6.11.2
'@codemirror/state': 6.4.1
'@codemirror/view': 6.35.2
'@lezer/common': 1.4.0
'@codemirror/language@6.11.2':
dependencies:
'@codemirror/state': 6.4.1
'@codemirror/view': 6.35.2
'@lezer/common': 1.4.0
'@lezer/highlight': 1.2.1
'@lezer/lr': 1.4.5
style-mod: 4.1.3
'@codemirror/state@6.4.1': {}
'@codemirror/view@6.35.2':
dependencies:
'@codemirror/state': 6.4.1
style-mod: 4.1.3
w3c-keyname: 2.2.8
'@discoveryjs/json-ext@0.6.3': {} '@discoveryjs/json-ext@0.6.3': {}
'@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)': '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1)':
@ -1431,9 +1570,21 @@ snapshots:
'@jridgewell/resolve-uri': 3.1.2 '@jridgewell/resolve-uri': 3.1.2
'@jridgewell/sourcemap-codec': 1.5.5 '@jridgewell/sourcemap-codec': 1.5.5
'@lezer/common@1.4.0': {}
'@lezer/highlight@1.2.1':
dependencies:
'@lezer/common': 1.4.0
'@lezer/lr@1.4.5':
dependencies:
'@lezer/common': 1.4.0
'@pkgjs/parseargs@0.11.0': '@pkgjs/parseargs@0.11.0':
optional: true optional: true
'@types/debug@4.1.5': {}
'@types/eslint-scope@3.7.7': '@types/eslint-scope@3.7.7':
dependencies: dependencies:
'@types/eslint': 9.6.1 '@types/eslint': 9.6.1
@ -1573,6 +1724,12 @@ snapshots:
transitivePeerDependencies: transitivePeerDependencies:
- supports-color - supports-color
'@wavedrom/doppler@1.14.0':
dependencies:
lodash.get: 4.4.2
onml: 2.1.0
w3c-keyname: 2.2.8
'@webassemblyjs/ast@1.14.1': '@webassemblyjs/ast@1.14.1':
dependencies: dependencies:
'@webassemblyjs/helper-numbers': 1.13.2 '@webassemblyjs/helper-numbers': 1.13.2
@ -1726,6 +1883,12 @@ snapshots:
binary-extensions@2.3.0: {} binary-extensions@2.3.0: {}
binary-search@1.3.6: {}
bindings@1.5.0:
dependencies:
file-uri-to-path: 1.0.0
brace-expansion@1.1.12: brace-expansion@1.1.12:
dependencies: dependencies:
balanced-match: 1.0.2 balanced-match: 1.0.2
@ -1838,6 +2001,10 @@ snapshots:
shebang-command: 2.0.0 shebang-command: 2.0.0
which: 2.0.2 which: 2.0.2
debug@3.2.7:
dependencies:
ms: 2.1.3
debug@4.4.3(supports-color@8.1.1): debug@4.4.3(supports-color@8.1.1):
dependencies: dependencies:
ms: 2.1.3 ms: 2.1.3
@ -1850,6 +2017,10 @@ snapshots:
diff@7.0.0: {} diff@7.0.0: {}
dot-prop@6.0.1:
dependencies:
is-obj: 2.0.0
eastasianwidth@0.2.0: {} eastasianwidth@0.2.0: {}
electron-to-chromium@1.5.267: {} electron-to-chromium@1.5.267: {}
@ -1966,6 +2137,8 @@ snapshots:
dependencies: dependencies:
flat-cache: 4.0.1 flat-cache: 4.0.1
file-uri-to-path@1.0.0: {}
fill-range@7.1.1: fill-range@7.1.1:
dependencies: dependencies:
to-regex-range: 5.0.1 to-regex-range: 5.0.1
@ -2096,6 +2269,8 @@ snapshots:
is-number@7.0.0: {} is-number@7.0.0: {}
is-obj@2.0.0: {}
is-path-inside@3.0.3: {} is-path-inside@3.0.3: {}
is-plain-obj@2.1.0: {} is-plain-obj@2.1.0: {}
@ -2177,6 +2352,28 @@ snapshots:
dependencies: dependencies:
immediate: 3.0.6 immediate: 3.0.6
llparse-builder@1.5.2:
dependencies:
'@types/debug': 4.1.5
binary-search: 1.3.6
debug: 4.4.3(supports-color@8.1.1)
transitivePeerDependencies:
- supports-color
llparse-frontend@3.0.0:
dependencies:
debug: 3.2.7
llparse-builder: 1.5.2
transitivePeerDependencies:
- supports-color
llparse@7.3.0:
dependencies:
debug: 4.4.3(supports-color@8.1.1)
llparse-frontend: 3.0.0
transitivePeerDependencies:
- supports-color
loader-runner@4.3.1: {} loader-runner@4.3.1: {}
locate-path@5.0.0: locate-path@5.0.0:
@ -2187,6 +2384,8 @@ snapshots:
dependencies: dependencies:
p-locate: 5.0.0 p-locate: 5.0.0
lodash.get@4.4.2: {}
lodash.merge@4.6.2: {} lodash.merge@4.6.2: {}
log-symbols@4.1.0: log-symbols@4.1.0:
@ -2268,6 +2467,10 @@ snapshots:
dependencies: dependencies:
mimic-function: 5.0.1 mimic-function: 5.0.1
onml@2.1.0:
dependencies:
sax: 1.4.3
optionator@0.9.4: optionator@0.9.4:
dependencies: dependencies:
deep-is: 0.1.4 deep-is: 0.1.4
@ -2395,6 +2598,8 @@ snapshots:
safer-buffer@2.1.2: {} safer-buffer@2.1.2: {}
sax@1.4.3: {}
schema-utils@4.3.3: schema-utils@4.3.3:
dependencies: dependencies:
'@types/json-schema': 7.0.15 '@types/json-schema': 7.0.15
@ -2465,6 +2670,8 @@ snapshots:
strip-json-comments@3.1.1: {} strip-json-comments@3.1.1: {}
style-mod@4.1.3: {}
supports-color@10.2.2: {} supports-color@10.2.2: {}
supports-color@7.2.0: supports-color@7.2.0:
@ -2561,11 +2768,32 @@ snapshots:
'@types/istanbul-lib-coverage': 2.0.6 '@types/istanbul-lib-coverage': 2.0.6
convert-source-map: 2.0.0 convert-source-map: 2.0.0
vcd-stream@1.5.0:
dependencies:
bindings: 1.5.0
dot-prop: 6.0.1
llparse: 7.3.0
transitivePeerDependencies:
- supports-color
vcdrom@1.6.0: {}
w3c-keyname@2.2.8: {}
watchpack@2.4.4: watchpack@2.4.4:
dependencies: dependencies:
glob-to-regexp: 0.4.1 glob-to-regexp: 0.4.1
graceful-fs: 4.2.11 graceful-fs: 4.2.11
waveql@1.9.0:
dependencies:
'@codemirror/autocomplete': 6.18.6
'@codemirror/commands': 6.8.1
'@codemirror/language': 6.11.2
'@codemirror/state': 6.4.1
'@codemirror/view': 6.35.2
'@lezer/highlight': 1.2.1
webpack-cli@6.0.1(webpack@5.103.0): webpack-cli@6.0.1(webpack@5.103.0):
dependencies: dependencies:
'@discoveryjs/json-ext': 0.6.3 '@discoveryjs/json-ext': 0.6.3

View File

@ -1,6 +1,7 @@
import * as vscode from "vscode"; import * as vscode from "vscode";
import { ICViewProvider } from "./views/ICViewProvider"; import { ICViewProvider } from "./views/ICViewProvider";
import { showICHelperPanel } from "./panels/ICHelperPanel"; import { showICHelperPanel } from "./panels/ICHelperPanel";
import { VCDViewerPanel } from "./panels/VCDViewerPanel";
export function activate(context: vscode.ExtensionContext) { export function activate(context: vscode.ExtensionContext) {
console.log("🎉 IC Coder 插件已激活!"); console.log("🎉 IC Coder 插件已激活!");
@ -21,6 +22,34 @@ export function activate(context: vscode.ExtensionContext) {
} }
); );
// 注册命令:打开 VCD 波形查看器
const openVCDViewerCommand = vscode.commands.registerCommand(
"ic-coder.openVCDViewer",
async (vcdFilePath?: string) => {
if (!vcdFilePath) {
// 如果没有提供文件路径,让用户选择 VCD 文件
const fileUri = await vscode.window.showOpenDialog({
canSelectFiles: true,
canSelectFolders: false,
canSelectMany: false,
filters: {
"VCD 文件": ["vcd"],
"所有文件": ["*"],
},
title: "选择 VCD 文件",
});
if (fileUri && fileUri[0]) {
vcdFilePath = fileUri[0].fsPath;
} else {
return;
}
}
VCDViewerPanel.createOrShow(context.extensionUri, vcdFilePath);
}
);
// 注册侧边栏视图 // 注册侧边栏视图
const viewProvider = new ICViewProvider(context.extensionUri); const viewProvider = new ICViewProvider(context.extensionUri);
const viewRegistration = vscode.window.registerWebviewViewProvider( const viewRegistration = vscode.window.registerWebviewViewProvider(
@ -32,6 +61,7 @@ export function activate(context: vscode.ExtensionContext) {
context.subscriptions.push( context.subscriptions.push(
openPanelCommand, openPanelCommand,
openChatCommand, openChatCommand,
openVCDViewerCommand,
viewRegistration viewRegistration
); );
} }

View File

@ -0,0 +1,352 @@
import * as vscode from "vscode";
import * as path from "path";
import * as fs from "fs";
/**
* VCD 波形查看器面板
*/
export class VCDViewerPanel {
public static currentPanel: VCDViewerPanel | undefined;
private readonly _panel: vscode.WebviewPanel;
private readonly _extensionUri: vscode.Uri;
private _disposables: vscode.Disposable[] = [];
private constructor(panel: vscode.WebviewPanel, extensionUri: vscode.Uri) {
this._panel = panel;
this._extensionUri = extensionUri;
// 设置初始 HTML 内容
this._panel.webview.html = this._getLoadingHtml();
// 监听面板关闭事件
this._panel.onDidDispose(() => this.dispose(), null, this._disposables);
// 监听来自 webview 的消息
this._panel.webview.onDidReceiveMessage(
(message) => {
switch (message.command) {
case "loadVCD":
if (message.filePath) {
this.loadVCDFile(message.filePath);
}
break;
}
},
null,
this._disposables
);
}
/**
* 创建或显示 VCD 查看器面板
*/
public static createOrShow(extensionUri: vscode.Uri, vcdFilePath?: string) {
const column = vscode.ViewColumn.One;
// 如果已经有面板打开,则显示它
if (VCDViewerPanel.currentPanel) {
VCDViewerPanel.currentPanel._panel.reveal(column);
if (vcdFilePath) {
VCDViewerPanel.currentPanel.loadVCDFile(vcdFilePath);
}
return;
}
// 创建新面板
const panel = vscode.window.createWebviewPanel(
"vcdViewer",
"VCD 波形查看器",
column,
{
enableScripts: true,
retainContextWhenHidden: true,
localResourceRoots: [extensionUri],
}
);
VCDViewerPanel.currentPanel = new VCDViewerPanel(panel, extensionUri);
// 如果提供了 VCD 文件路径,加载它
if (vcdFilePath) {
VCDViewerPanel.currentPanel.loadVCDFile(vcdFilePath);
}
}
/**
* 加载 VCD 文件
*/
public loadVCDFile(vcdFilePath: string) {
try {
// 检查文件是否存在
if (!fs.existsSync(vcdFilePath)) {
vscode.window.showErrorMessage(`VCD 文件不存在: ${vcdFilePath}`);
return;
}
// 更新面板标题
const fileName = path.basename(vcdFilePath);
this._panel.title = `VCD 波形查看器 - ${fileName}`;
// 设置 HTML 内容
this._panel.webview.html = this._getWebviewContent(vcdFilePath);
} catch (error) {
vscode.window.showErrorMessage(
`加载 VCD 文件失败: ${error instanceof Error ? error.message : "未知错误"}`
);
}
}
/**
* 清理资源
*/
public dispose() {
VCDViewerPanel.currentPanel = undefined;
this._panel.dispose();
while (this._disposables.length) {
const disposable = this._disposables.pop();
if (disposable) {
disposable.dispose();
}
}
}
/**
* 获取加载中的 HTML
*/
private _getLoadingHtml(): string {
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>VCD 波形查看器</title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
font-family: var(--vscode-font-family);
color: var(--vscode-foreground);
background-color: var(--vscode-editor-background);
}
.loading {
text-align: center;
}
.spinner {
border: 4px solid var(--vscode-progressBar-background);
border-top: 4px solid var(--vscode-progressBar-foreground);
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin: 0 auto 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<div class="loading">
<div class="spinner"></div>
<p>正在加载 VCD 波形查看器...</p>
</div>
</body>
</html>`;
}
/**
* 获取 Webview 的 HTML 内容
*/
private _getWebviewContent(vcdFilePath: string): string {
// 获取资源 URI
const vcdromJsUri = this._panel.webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, "media", "vcdrom", "vcdrom.js")
);
const vcdWasmUri = this._panel.webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, "media", "vcdrom", "vcd.wasm")
);
const fontRegularUri = this._panel.webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, "media", "vcdrom", "IosevkaDrom-Regular.woff2")
);
const fontObliqueUri = this._panel.webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, "media", "vcdrom", "IosevkaDrom-Oblique.woff2")
);
const fontItalicUri = this._panel.webview.asWebviewUri(
vscode.Uri.joinPath(this._extensionUri, "media", "vcdrom", "IosevkaDrom-Italic.woff2")
);
// 读取 VCD 文件内容并转换为 base64
const vcdContent = fs.readFileSync(vcdFilePath, "utf-8");
const vcdBase64 = Buffer.from(vcdContent).toString("base64");
return `<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; font-src ${this._panel.webview.cspSource}; style-src 'unsafe-inline' ${this._panel.webview.cspSource}; script-src 'unsafe-inline' 'unsafe-eval' ${this._panel.webview.cspSource}; img-src ${this._panel.webview.cspSource} data:; connect-src ${this._panel.webview.cspSource};">
<title>VCD 波形查看器</title>
<style>
@font-face {
font-family: 'Iosevka Drom Web';
font-display: swap;
font-weight: 400;
font-stretch: normal;
font-style: normal;
src: url('${fontRegularUri}') format('woff2');
}
@font-face {
font-family: 'Iosevka Drom Web';
font-display: swap;
font-weight: 400;
font-stretch: normal;
font-style: oblique;
src: url('${fontObliqueUri}') format('woff2');
}
@font-face {
font-family: 'Iosevka Drom Web';
font-display: swap;
font-weight: 400;
font-stretch: normal;
font-style: italic;
src: url('${fontItalicUri}') format('woff2');
}
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
font-family: 'Iosevka Drom Web', monospace;
color: var(--vscode-foreground);
background-color: var(--vscode-editor-background);
overflow: hidden;
}
#waveform-container {
width: 100vw;
height: 100vh;
overflow: auto;
}
#waveform1 {
width: 100%;
height: 100%;
}
.loading {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
flex-direction: column;
}
.spinner {
border: 4px solid var(--vscode-progressBar-background);
border-top: 4px solid var(--vscode-progressBar-foreground);
border-radius: 50%;
width: 40px;
height: 40px;
animation: spin 1s linear infinite;
margin-bottom: 20px;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
.error-message {
padding: 20px;
color: var(--vscode-errorForeground);
background-color: var(--vscode-inputValidation-errorBackground);
border: 1px solid var(--vscode-inputValidation-errorBorder);
border-radius: 4px;
margin: 20px;
}
</style>
<script src="${vcdromJsUri}"></script>
</head>
<body>
<div id="waveform-container">
<div class="loading">
<div class="spinner"></div>
<p>正在加载 VCD 波形...</p>
</div>
<div id="waveform1"></div>
</div>
<script>
(async function() {
try {
// 设置 WASM 文件路径
window.wasmBinaryFile = '${vcdWasmUri}';
// 解码 base64 VCD 内容
const vcdBase64 = '${vcdBase64}';
const vcdContent = atob(vcdBase64);
// 隐藏加载提示
document.querySelector('.loading').style.display = 'none';
// 创建一个函数来提供 VCD 数据流
const vcdProvider = async (handler) => {
// 将 VCD 内容转换为 Uint8Array
const encoder = new TextEncoder();
const vcdData = encoder.encode(vcdContent);
// 创建一个 ReadableStream reader
const stream = new ReadableStream({
start(controller) {
controller.enqueue(vcdData);
controller.close();
}
});
const reader = stream.getReader();
// 调用 handler 并传递 reader
await handler([{
key: 'local',
value: 'waveform.vcd',
format: 'raw',
baseName: 'waveform.vcd',
ext: 'vcd',
reader: reader
}]);
};
// 初始化 VCDrom使用函数回调方式
if (typeof VCDrom === 'function') {
await VCDrom('waveform1', vcdProvider);
} else {
throw new Error('VCDrom 未正确加载');
}
} catch (error) {
console.error('加载 VCD 波形失败:', error);
document.getElementById('waveform-container').innerHTML =
'<div class="error-message">' +
'<h3>❌ 加载 VCD 波形失败</h3>' +
'<p>' + error.message + '</p>' +
'<p style="margin-top: 10px;">请确保 VCD 文件格式正确。</p>' +
'<pre style="margin-top: 10px; padding: 10px; background: rgba(0,0,0,0.1); overflow: auto;">' + error.stack + '</pre>' +
'</div>';
}
})();
</script>
</body>
</html>`;
}
}

View File

@ -595,16 +595,13 @@ async function handleVCDGeneration(
text: successMsg, text: successMsg,
}); });
vscode.window.showInformationMessage( // 自动打开 VCD 波形查看器
`VCD 文件生成成功: ${result.vcdFilePath}`, if (result.vcdFilePath) {
"打开文件" vscode.commands.executeCommand("ic-coder.openVCDViewer", result.vcdFilePath);
).then((selection) => { vscode.window.showInformationMessage(
if (selection === "打开文件" && result.vcdFilePath) { `VCD 文件生成成功,已自动打开波形查看器`
vscode.workspace.openTextDocument(result.vcdFilePath).then((doc) => { );
vscode.window.showTextDocument(doc); }
});
}
});
} else { } else {
let errorMsg = `${result.message}`; let errorMsg = `${result.message}`;