完成 vec 模式下的 0 绘制

This commit is contained in:
锦恢 2024-03-26 03:47:14 +08:00
parent b2e4fb8a8a
commit 0a36a28a57
21 changed files with 304 additions and 572 deletions

View File

@ -56,6 +56,8 @@ export default {
document.body.style.setProperty('--el-color-info', 'var(--foreground)');
document.body.style.setProperty('--el-color-info-light-8', 'var(--vscode-focusBorder)');
document.body.style.setProperty('--el-bg-color-overlay', 'transplant');
// document.body.style.setProperty('--el-color-white', 'var(--background)');
// signal height
document.body.style.setProperty('--display-signal-info-height', globalSetting.displaySignalHeight + 'px');

View File

@ -1,7 +1,7 @@
<template>
<!-- <VerticalCursor></VerticalCursor> -->
<!-- <TimeScale></TimeScale> -->
<div class="vcd-render-wrapper" >
<div class="vcd-render-wrapper" @click="updateWireCurrentValue()">
</div>
</template>
@ -10,6 +10,7 @@
<script>
import { reactive, ref } from 'vue';
import { emitter, globalLookup, globalSetting } from '@/hook/global';
import { updateWireCurrentValue } from '@/hook/utils';
import VerticalCursor from '@/components/render/cursor.vue';
import TimeScale from '@/components/render/time-scale.vue';
@ -22,8 +23,11 @@ export default {
},
setup() {
return {
globalLookup
globalLookup,
updateWireCurrentValue
}
}
}
@ -127,11 +131,15 @@ rect.wd-cursor-time {
transform: translate(-50%, -50%);
}
text.xred {
text.common {
fill: var(--sidebar-item-text);
}
text.high-impedance {
fill: hsl(0, 100%, 50%);
}
text.zxviolet {
text.unknown {
fill: hsl(287, 100%, 67%);
}

View File

@ -48,6 +48,11 @@
</el-option>
</el-select>
</div>
<br>
<div class="setting-option" style="width: 380px;">
<span class="option-title" style="width: 300px;">{{ t('wheel-zoom-ratio') }}</span>
<el-slider v-model="languageSetting.wheelZoomRatio" show-stops :min="1" :max="5"/>
</div>
</div>
<hr>
@ -145,4 +150,8 @@ export default {
min-width: 80px;
margin-right: 12px;
}
.el-slider__button {
background-color: var(--background) !important;
}
</style>

View File

@ -8,9 +8,35 @@
<span :class="makeSignalIconClass(signal)"></span>
</div>
<div class="signal-info">
{{ signal.name }}
</div>
<div>
<div class="signal-info">
<el-tooltip
effect="dark"
:content="makeFullSignalNameDeps(signal)"
placement="top"
raw-content
>
<div class="signal-info-name">
{{ signal.name }}
</div></el-tooltip>
<div class="signal-info-width">
<div :class="signal.size > 1 ? 'signal-info-caption' : ''">
{{ makeSignalCaption(signal) }}
</div>
</div>
</div>
<div class="signal-info-current-value-wrapper">
<span></span>
<el-tooltip
effect="dark"
:content="globalLookup.currentSignalValues[signal.link] + ''"
placement="top"
raw-content
><div class="signal-info-current-value">
{{ globalLookup.currentSignalValues[signal.link] }}
</div></el-tooltip>
</div>
</div>
</div>
@ -41,10 +67,41 @@ export default {
return 'iconfont ' + makeIconClass(signal);
}
function makeSignalCaption(signal) {
return signal.size === 1 ? '' : `${signal.size - 1}:0`;
}
function makeFullSignalNameDeps(signal) {
const deps = [];
while (signal) {
if (signal.name && signal.type) {
deps.push(signal);
}
signal = signal.parent;
}
let htmlString = '';
for (let i = deps.length - 1; i >= 0; -- i) {
const mod = deps[i];
// const displayName = mod.name.length > 6 ? mod.name.substring(0, 6) + '...' : mod.name;
const iconClass = makeIconClass(mod);
const iconText = `<span class="iconfont ${iconClass}"></span>&ensp;${mod.name}`;
htmlString += iconText;
if (i > 0) {
htmlString += '<div class="dep-arrow"></div>';
}
}
htmlString = '<div class="signal-info-tooltip-wrapper">' + htmlString + '</div>';
return htmlString;
}
return {
t,
globalLookup,
makeSignalIconClass,
makeSignalCaption,
makeFullSignalNameDeps,
addSignal
}
}
@ -112,11 +169,54 @@ export default {
}
.signal-info {
width: 90%;
display: flex;
justify-content: space-around;
justify-content: space-between;
align-items: center;
}
.signal-info-name {
cursor: pointer;
max-width: 100px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.signal-info-tooltip-wrapper {
display: flex;
align-items: center;
justify-content: space-around;
}
.signal-info-width {
margin-left: 10px;
}
.signal-info-caption {
width: fit-content;
color: var(--sidebar-item-text);
border-radius: .5em;
background-color: #7CA532;
padding: 5px;
font-size: 16px;
}
.signal-info-current-value-wrapper {
margin-left: 10px;
width: 60px;
display: flex;
justify-content: space-around;
}
.signal-info-current-value {
cursor: pointer;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
.signal-info::selection {
background: none;
cursor: none;

View File

@ -1,48 +0,0 @@
class LineDrawer {
/**
*
* @param {CanvasRenderingContext2D} ctx
*/
constructor(ctx) {
this.ctx = ctx;
this.lastColor = null;
}
beginPath() {
this.ctx.beginPath();
}
/**
*
* @param {number} x
* @param {number} y
*/
moveTo(x, y) {
this.ctx.moveTo(x, y);
}
/**
*
* @param {number} x
* @param {number} y
* @param {string} color
*/
lineTo(x, y, color) {
const ctx = this.ctx;
ctx.lineTo(x, y);
if (this.lastColor === null) {
ctx.strokeStyle = color;
this.lastColor = color;
} else if (this.lastColor !== color) {
ctx.stroke();
ctx.strokeStyle = color;
this.lastColor = color;
}
}
}
export {
LineDrawer
}

View File

@ -12,6 +12,11 @@ const globalLookup = reactive({
// 当前选中的某个 信号 的 数据。可复选。
currentWires: new Set(),
currentSignalValues: {},
// 当前 ns 数(或者 ps
currentTime: 0,
// 模拟器的版本,比如如果使用 iverilog 那么就是 Icarus Verilog
version: '',
// 创建时间
@ -65,7 +70,7 @@ const globalSetting = reactive({
searchMode: 'so', // so, mo, sm
searchScope: ['wire', 'reg', 'integer'],
displaySignalInfoScope: ['width', 'parent'],
wheelZoomRatio: 1,
minGridWidth: 300
});

View File

@ -1,9 +1,7 @@
import { globalLookup, globalSetting, signalValues } from "./global";
import { LineDrawer } from './canvas';
import { domContainer, pluginRenderTimeGrid, pluginRenderValues, mountTree,
genOnWheel, genKeyHandler, keyBindo } from './wave-view';
import { createCodeMirrorState, mountCodeMirror6 } from 'waveql';
import { findCurrentSignalValue } from './utils';
let mainRenderEl = null;
const canvasMap = new Map();
@ -22,227 +20,6 @@ function getMainRenderEl() {
return mainRenderEl;
}
/**
*
* @param {{
* time: BigInt,
* cmd: number,
* value?: BigInt,
* mask?: BigInt
* }} dataItem
* @returns
*/
function isBlocked(dataItem) {
const mask = dataItem.mask;
if (mask && mask === 1n) {
return true;
}
if (mask && mask === 0n) {
return false;
}
if (mask === undefined && dataItem.cmd > 15) {
return true;
}
return false;
}
/**
* @param {{
* kind: 'var' | 'scope',
* type: 'wire' | 'reg' | 'module',
* name: string,
* size: number,
* link: string
* }} signal
*/
function makeWaveCanvas(signal) {
const mainRender = getMainRenderEl();
const canvas = document.createElement('canvas');
canvas.id = 'wave-' + signal.link;
canvas.className = 'render-canvas';
canvas.width = document.body.clientWidth;
canvas.height = globalSetting.displaySignalHeight;
mainRender.appendChild(canvas);
canvasMap.set(signal, canvas);
const ctx = canvas.getContext('2d');
const datas = signalValues[signal.link];
if (signal.size === 1) {
drawSimpleSignal(ctx, datas);
} else {
// adwa
}
}
/**
* @param {{
* kind: 'var' | 'scope',
* type: 'wire' | 'reg' | 'module',
* name: string,
* size: number,
* link: string
* }} signal
*/
function makeWaveSvg(signal) {
const mainRender = getMainRenderEl();
const height = globalSetting.displaySignalHeight;
const width = document.body.clientWidth;
const draw = SVG().addTo(mainRender).size(width, height);
const datas = signalValues[signal.link];
if (signal.size === 1) {
drawSimpleSignalSvg(draw, datas);
} else {
// adwa
}
}
/**
*
* @param {Svg} ctx
* @param {Array<{
* time: BigInt,
* cmd: number,
* value?: BigInt,
* mask?: BigInt
* }>} signals
*/
function drawSimpleSignalSvg(ctx, signals) {
let lastData = null;
let lastX = 300;
let lastColor = '';
// ctx.lineWidth = 3;
// ctx.lineJoin = 'round';
// const drawer = new LineDrawer(ctx);
// drawer.beginPath();
for (const data of signals) {
if (lastData === null) {
lastData = data;
lastX = 300;
lastColor = getDataRenderColor(data);
let lastY = Math.max((15 - data.cmd) * 30, 0) + 10;
// drawer.moveTo(last_x, last_y);
ctx.move(lastX, lastY);
} else {
// 高阻态
const start = lastData.time;
const end = data.time;
console.log(lastData, isBlocked(lastData));
let lastY = Math.max((15 - lastData.cmd) * 30, 0) + 10;
const duration = parseInt(end - start);
const currentX = lastX + 100;
const currentColor = getDataRenderColor(data);
console.log(currentX, lastY, duration);
const line = ctx.line(lastX, lastY, currentX, lastY);
if (currentColor !== lastColor) {
ctx.stroke({ color: lastColor, linecap: 'round', width: 3 });
}
// drawer.lineTo(current_x, last_y, color);
if (lastData.cmd !== data.cmd) {
let currentY = Math.max((15 - data.cmd) * 30, 0) + 10;
const color = getDataRenderColor(data);
ctx.line(currentX, lastY, currentX, currentY);
// drawer.lineTo(current_x, current_y, color);
}
lastData = data;
lastX = currentX;
lastColor = currentColor;
}
}
// 如果 last_data 的时间不足最长时间,就用最后一个时刻的去补足
ctx.stroke({ color: lastColor, linecap: 'round', width: 3 });
}
function getDataRenderColor(data) {
return isBlocked(data) ? 'rgb(224,108,117)' : 'rgb(10, 200, 10)';
}
/**
* @param {{
* kind: 'var' | 'scope',
* type: 'wire' | 'reg' | 'module',
* name: string,
* size: number,
* link: string
* }} signal
*/
function removeWaveCanvas(signal) {
const canvas = canvasMap.get(signal);
if (canvas instanceof HTMLCanvasElement) {
canvas.parentNode.removeChild(canvas);
}
}
/**
*
* @param {CanvasRenderingContext2D} ctx
* @param {Array<{
* time: BigInt,
* cmd: number,
* value?: BigInt,
* mask?: BigInt
* }>} signals
*/
function drawSimpleSignal(ctx, signals) {
let last_data = null;
let last_x = 300;
ctx.lineWidth = 3;
ctx.lineJoin = 'round';
const drawer = new LineDrawer(ctx);
drawer.beginPath();
for (const data of signals) {
if (last_data === null) {
last_data = data;
last_x = 300;
let last_y = Math.max((15 - last_data.cmd) * 30, 0) + 10;
drawer.moveTo(last_x, last_y);
} else {
// 高阻态
const start = last_data.time;
const end = data.time;
console.log(last_data, isBlocked(last_data));
let last_y = Math.max((15 - last_data.cmd) * 30, 0) + 10;
const duration = parseInt(end - start);
const current_x = last_x + 100;
console.log(current_x, last_y, duration);
const color = getDataRenderColor(last_data);
drawer.lineTo(current_x, last_y, color);
if (last_data.cmd !== data.cmd) {
let current_y = Math.max((15 - data.cmd) * 30, 0) + 10;
const color = getDataRenderColor(data);
drawer.lineTo(current_x, current_y, color);
}
last_data = data;
last_x = current_x;
}
}
// 如果 last_data 的时间不足最长时间,就用最后一个时刻的去补足
ctx.stroke();
}
function pluginLocalStore(desc, pstate /* , els */) {
const pstateJsonString = JSON.stringify({
@ -278,22 +55,7 @@ function makeWaveView(parentElement) {
console.log('updater');
};
const cmState = createCodeMirrorState(globalLookup, container.pstate);
const cm = mountCodeMirror6(
cmState,
container.elo.waveqlPanel,
globalLookup,
container.pstate
);
cm.view.dispatch({changes: {from: 0, insert: ' '}});
cm.view.dispatch({changes: {from: 0, to: 1, insert: ''}});
container.elo.container.addEventListener('keydown', genKeyHandler.genKeyHandler(parentElement, container.pstate, globalLookup, cm, keyBindo));
container.elo.container.addEventListener('wheel', genOnWheel(parentElement, container.pstate, globalLookup, cm, keyBindo));
// console.log(cm);
// cm.view.focus();
container.elo.container.addEventListener('wheel', genOnWheel(parentElement, container.pstate, globalLookup, keyBindo));
}
@ -309,18 +71,20 @@ function makeWaveView(parentElement) {
function toggleRender(signal) {
if (globalLookup.currentWires.has(signal)) {
globalLookup.currentWires.delete(signal);
delete globalLookup.currentSignalValues[signal.link];
globalLookup.render();
} else {
globalLookup.currentWires.add(signal);
const signalItem = globalLookup.chango[signal.link];
const { wave } = signalItem;
const time = globalLookup.currentTime;
globalLookup.currentSignalValues[signal.link] = findCurrentSignalValue(wave, time);
globalLookup.render();
}
}
export {
getMainRenderEl,
makeWaveCanvas,
makeWaveSvg,
removeWaveCanvas,
makeWaveView,
toggleRender
}

View File

@ -1,6 +1,7 @@
/* eslint-disable no-undef */
import { Stream } from "stream";
import { globalLookup } from "./global";
/**
*
@ -110,34 +111,100 @@ function makeSearchResultItem(searchString, module, searchScope, caseSensitivity
}
let htmlString = '';
let depString = '';
let currentCounts = 0;
for (let i = deps.length - 1; i >= 0; -- i) {
const mod = deps[i];
// const displayName = mod.name.length > 6 ? mod.name.substring(0, 6) + '...' : mod.name;
const iconClass = makeIconClass(mod);
const iconText = `<span class="iconfont ${iconClass}"></span>&ensp;${mod.name}`;
depString += iconText;
htmlString += iconText;
if (i > 0) {
depString += '<br>';
htmlString += '<div class="dep-arrow"></div>';
}
}
return {
htmlString,
module,
depString
module
};
}
}
return null;
}
/**
*
* @param {BigInt} value
* @param {BigInt} mask
* @returns {number | string}
*/
function getWireValueCaption(value, mask) {
if (!mask) {
return value;
}
// mask 不为空,代表存在问题
if (value) {
return '?';
} else {
return 'x';
}
}
async function updateWireCurrentValue() {
const chango = globalLookup.chango;
const time = globalLookup.currentTime;
const currentSignalValues = globalLookup.currentSignalValues;
for (const signal of globalLookup.currentWires) {
const signalItem = chango[signal.link];
const { wave } = signalItem;
if (wave === undefined || wave.length === 0) {
currentSignalValues[signal.link] = 'x';
} else if (wave.length === 1) {
currentSignalValues[signal.link] = getWireValueCaption(wave[0][1], wave[0][2]);
} else {
currentSignalValues[signal.link] = findCurrentSignalValue(wave, time);
}
// console.log(signal.name, currentSignalValues[signal.link]);
}
}
/**
*
* @param {Array<Array<string | number>>} wave
* @param {number} time
*/
function findCurrentSignalValue(wave, time) {
const times = wave.map(p => p[0]);
// 二分查找,并将结果存入 i
let i = 0, j = wave.length - 1;
while (i < j) {
if (times[i] === time) {
break;
}
if (times[j] === time) {
i = j;
break;
}
if (j - i === 1) {
break;
}
const mid = (i + j) >> 1;
if (times[mid] > time) {
j = mid;
} else {
i = mid;
}
}
const value = getWireValueCaption(wave[i][1], wave[i][2]);
console.log(wave[i][1], wave[i][2]);
return value;
}
/**
*
* @param {string} timescale
@ -263,5 +330,7 @@ export {
parseTimescale,
numberOrString,
gcd,
normaliseUsingGCD
findCurrentSignalValue,
normaliseUsingGCD,
updateWireCurrentValue
};

View File

@ -14,7 +14,9 @@ const setTime = (pstate, str) => {
};
const mouseMoveHandler = (cursor, content, pstate /* , render */) => {
// 这是上面展示当前 time 的圆角矩形框框的宽度
const xmargin = 160;
// 这是上面展示当前 time 的圆角矩形内的字体大小
const fontHeight = 20;
const fontWidth = fontHeight / 2;
const handler = event => {
@ -22,6 +24,7 @@ const mouseMoveHandler = (cursor, content, pstate /* , render */) => {
cursor.style.left = (x - xmargin) + 'px';
cursor.innerHTML = renderCursor({ xmargin, fontWidth, fontHeight }, pstate);
};
// 添加初始鼠标位置
handler({ clientX: pstate.width / 2 });
content.addEventListener('mousemove', handler);
};

View File

@ -1,6 +1,6 @@
'use strict';
const genOnWheel = (element, pstate, deso, cm, keyBindo, plugins) =>
const genOnWheel = (element, pstate, deso, keyBindo, plugins) =>
event => {
const {deltaY} = event;
if (event.ctrlKey) {

View File

@ -6,7 +6,7 @@ const cColors = new Float32Array([
0.2, 0.847, 0.1, 1, // 2: strong 0
0.2, 0.847, 0.1, 1, // 3: strong 1
1, 0, 0, 1, // 4: (x X) strong unknown
0.9, 0.2, 0.2, 1, // 4: (x X) strong unknown
.5, 1, 1, 1, // 5: vec
1, 1, 0, 1, // 6: yellow
@ -289,27 +289,25 @@ class WebGL2WaveRender {
const vertices = [];
const ilen = wave.length;
for (let i = 0; i < ilen; i++) {
const [tim, val, msk] = wave[i];
const tt = (i === (ilen - 1)) ? time : wave[i + 1][0];
const [t1, val, msk] = wave[i];
const t2 = (i === (ilen - 1)) ? time : wave[i + 1][0];
if (val) {
if (msk) {
vertices.push(...brick[2](2, 2, tim, tt, 4, 4)); // x,z?
} else {
vertices.push(
tim, 0, 0,
tt, 0, 0, tt, 0, 5, tt, 4, 5,
tim, 6, 5, tim, 0, 5, tim, 3, 5,
tt, 1, 5, tt, 0, 5
);
}
if (msk) {
vertices.push(...brick[2](2, 2, t1, t2, 4, 4)); // x,z?
} else {
if (msk) {
vertices.push(...brick[2](2, 2, tim, tt, 4, 4)); // x
} else {
vertices.push(tim, 6, 2, tt, 4, 2);
}
vertices.push(
t1, 0, 0,
t2, 0, 0,
t2, 0, 5,
t2, 4, 5,
t1, 6, 5,
t1, 0, 5,
t1, 3, 5,
t2, 1, 5,
t2, 0, 5
);
}
}
return new Uint32Array(vertices);

View File

@ -8,6 +8,8 @@ const genResizeHandler = pstate =>
pstate.width = width;
pstate.height = height;
console.log('time', time);
// Y
const yOffsetMax = (numLanes + 2) * 2 * yStep;
if (yOffsetMax < 0) {
@ -16,11 +18,13 @@ const genResizeHandler = pstate =>
yOffset = yOffsetMax;
}
pstate.yOffset = yOffset;
console.log('resize handler', pstate);
// console.log('resize handler', pstate);
// X
const xScaleMin = pstate.xScaleMin = (width - sidebarWidth) / time;
// const xScaleMin = pstate.xScaleMin = (width - sidebarWidth) / time;
const xScaleMin = pstate.xScaleMin = 0.001;
console.log(width, sidebarWidth);
console.log('xScaleMin', xScaleMin);
pstate.xScale = (xScale < xScaleMin) ? xScaleMin : xScale;
pstate.xScaleMin = 0.001;
xOffsetUpdate(pstate, xOffset);
};

View File

@ -3,31 +3,33 @@
const format = require('./format.js');
const getLabel = (lane) => {
if (typeof lane !== 'object') {
lane = {};
}
const fmt = lane.format || '%h';
const width = Number(lane.width || 1);
const formatter = format(fmt, width);
return (vPre, mPre, x, w) => {
if (mPre) {
if (vPre) {
return ['text', {x, class: 'zxviolet'}, '?'];
} else {
return ['text', {x, class: 'xred'}, 'x'];
}
if (typeof lane !== 'object') {
lane = {};
}
const fmt = lane.format || '%h';
const width = Number(lane.width || 1);
const formatter = format(fmt, width);
const pos = (w / 8) |0;
return (value, mask, x, w) => {
console.log(value, mask, x, w);
vPre = BigInt(vPre);
if (mask) {
if (value) {
return ['text', { x, class: 'unknown' }, '?'];
} else {
return ['text', { x, class: 'high-impedance' }, 'x'];
}
}
const txtShort = formatter(vPre, pos, width);
return ['text', {x}, txtShort];
};
const pos = (w / 8) | 0;
value = BigInt(value);
const txtShort = formatter(value, pos, width);
return ['text', { x, class: 'common' }, txtShort];
};
};
module.exports = getLabel;

View File

@ -11,12 +11,12 @@ const yScroll = delta => (pstate, cm) => {
const pluso = {
desc: 'Zoom in time',
fn: pstate => xScaleUpdate(pstate, 3 / 2 * pstate.xScale)
fn: pstate => xScaleUpdate(pstate, 10 / 9 * pstate.xScale)
};
const minuso = {
desc: 'Zoom out time',
fn: pstate => xScaleUpdate(pstate, 2 / 3 * pstate.xScale)
fn: pstate => xScaleUpdate(pstate, 9 / 10 * pstate.xScale)
};
const fullo = {
@ -27,11 +27,11 @@ const fullo = {
const scroll = {
left: {
desc: 'Scroll into the past',
fn: pstate => xOffsetUpdate(pstate, pstate.xOffset + .2 * pstate.width)
fn: pstate => xOffsetUpdate(pstate, pstate.xOffset + pstate.time)
},
right: {
desc: 'Scroll into the future',
fn: pstate => xOffsetUpdate(pstate, pstate.xOffset - .2 * pstate.width)
fn: pstate => xOffsetUpdate(pstate, pstate.xOffset - pstate.time)
},
up: {
desc: 'scroll up',

View File

@ -4,11 +4,14 @@ const genSVG = require('onml/gen-svg.js');
const stringify = require('onml/stringify.js');
const formatTime = require('./format-time.js');
const { globalLookup } = require('../global');
const renderCursor = (cfg, pstate) => {
const { xmargin, fontWidth, fontHeight } = cfg;
const { height, xScale, xOffset, tgcd, timescale, xCursor } = pstate;
const xx = Math.round((xCursor - xOffset) / xScale) * tgcd;
globalLookup.currentTime = xx;
const label = formatTime(xx, timescale);
const lWidth = (label.length + 1) * fontWidth;

View File

@ -88,16 +88,21 @@ function* renderValues(desc, pstate) {
const labeler = getLabel(lane);
for (let j = 1; j <= jlen; j++) {
const mark = wave[j];
const [tCur, vCur, mCur] = (mark || [desc.time, 0, 0]);
const xCur = getX(pstate, tCur);
if (vPre || mPre) {
console.log(mark, vPre, mPre, vCur, mCur);
if (vPre !== undefined || mPre !== undefined) {
if (xPre > width && xCur > width) { // both time stamps to the right
break perLane;
}
if (!((xPre < sidebarWidth) && (xCur < sidebarWidth))) { // both time stamps to the left
const xPreNorm = ((xPre > sidebarWidth) ? xPre : sidebarWidth) | 0;
const xCurNorm = ((xCur < width) ? xCur : width) | 0;
const w = xCurNorm - xPreNorm;
// 宽度太小不画了
if (w > 8) {
const x = Math.round((xPreNorm + xCurNorm) / 2);
mLane.push(labeler(vPre, mPre, x, w));
@ -106,7 +111,9 @@ function* renderValues(desc, pstate) {
}
xPre = xCur;
vPre = vCur;
console.log(mPre, mCur);
mPre = mCur;
console.log(mPre, mCur);
}
}
ml.push(mLane);

View File

@ -1,202 +0,0 @@
'use strict';
const get = require('lodash.get');
const diz = (cols, wires, path, rowIdx) => {
if (cols[0] !== 'DIZ') {
return;
}
const levelo = get(wires, path, false);
const arg1 = cols[1]; // pipeline stages
// find all potential candidates
const othero0 = Object.keys(levelo).reduce((res, name) => {
const m = name.match(arg1);
if (m) {
const {id, pc, go} = m.groups;
const stage = res[id] = (res[id] || {});
const desc = {name, ref: levelo[name]};
if (pc) {
stage[pc] = desc;
} else
if (go) {
stage[go] = desc;
} else {
console.log(desc);
}
}
return res;
}, {});
// filter out singles
const othero = Object.keys(othero0).reduce((res, name) => {
const val = othero0[name];
if (val.pc && val.go) {
res[name] = val;
}
return res;
}, {});
return {kind: 'DIZ', idx: rowIdx, othero, clock: {name: 'clock', ref: levelo.clock}};
};
exports.parser = wires => str => {
const arr = str.split('\n');
const path = [];
const labelo = {};
let nRow;
let mat;
const res = arr.map((row, rowIdx) => {
row = row.trim();
// Section with Parentheses
if (row[0] === '(') {
const cols = row.slice(1).split(/\s+/);
const res = diz(cols, wires, path, rowIdx); // || other commands
if (res) {
nRow = res;
return res;
}
}
if (row[0] === ')') {
if (nRow !== undefined) {
nRow.len = rowIdx - nRow.idx + 1;
nRow = undefined;
}
return {};
}
const rowo = {};
const cols = row.split(/\s+/);
cols.map(col => {
if (col === '...') { path.pop(); path.pop(); return; }
if (col === '..') { path.pop(); return; }
if (col === '.') { return; }
if (col === '/') { path.length = 0; return; }
mat = col.match(/^:(\S+)$/); if (mat) {
labelo[mat[1]] = rowo;
return;
}
mat = col.match(/^(\{)([^}]+)(\})$/); if (mat) {
const a = mat[2];
const b = a.split(',');
rowo.kind = 'brace';
rowo.body = b.reduce((res, e) => {
const ee = e.split(':');
if (ee.length === 2) {
const key = ee[0];
const val = labelo[ee[1]] || Number(ee[1]);
res[key] = val;
} else
if (ee.length === 1) {
res[ee[0]] = labelo[ee[0]] || {};
} else {
console.error(ee);
}
return res;
}, {});
return;
}
mat = col.match(/^%([<>^])?([+-])?([su])?([bodhHac])$/); if (mat) {
rowo.format = {
align: mat[1],
plus: mat[2],
sign: mat[3],
radix: mat[4]
};
return;
}
const newPath = path.concat(col);
const ref = get(wires, newPath, false);
if (typeof ref === 'string') {
rowo.name = col;
rowo.ref = ref;
} else
if (typeof ref === 'object') {
path.push(col);
}
});
return rowo;
});
return res;
};
exports.cmMode = function(CodeMirror, desc) {
const { wires } = desc;
CodeMirror.defineMode('waveql', function() {
return {
startState: function() {
return {path: []};
},
token: function (stream, stt) {
// const line = stream.lineOracle.line;
let mat;
if (stream.eatSpace()) { return null; }
mat = stream.match(/^\.\.\.(\s+|$)/); if (mat) { stt.path.pop(); stt.path.pop(); return 'punct'; }
mat = stream.match(/^\.\.(\s+|$)/); if (mat) { stt.path.pop(); return 'punct'; }
mat = stream.match(/^\.(\s+|$)/); if (mat) { return 'punct'; }
mat = stream.match(/^\/(\s+|$)/); if (mat) { stt.path.length = 0; return 'punct'; }
mat = stream.match(/^:(\S+)(\s+|$)/); if (mat) {
return 'label';
}
mat = stream.match(/^\{[^}]+\}(\s+|$)/); if (mat) {
return 'mark';
}
mat = stream.match(/^%([<>^])?([+-])?([su])?([bodhHac])(\s+|$)/); if (mat) {
return 'format';
}
mat = stream.match(/^(\S+)(\s+|$)/); if (mat) {
const sigName = mat[1];
const newPath = stt.path.concat(sigName);
const ref = get(wires, newPath, false);
if (typeof ref === 'string') {
return 'signal';
}
if (typeof ref === 'object') {
stt.path = newPath;
return 'path';
}
return 'comment';
}
}
};
});
CodeMirror.defineMIME('text/x-waveql', 'waveql');
};
exports.cmHint = (CodeMirror, desc) => {
const { wires } = desc;
return async (cm /*, options */) => {
const cursor = cm.getCursor();
const token = cm.getTokenAt(cursor);
const line = cm.getLine(cursor.line);
let start = cursor.ch;
let end = cursor.ch;
while (start && /\w/.test(line.charAt(start - 1))) --start;
while (end < line.length && /\w/.test(line.charAt(end))) ++end;
const cur = token.string.trim();
const list = get(wires, token.state.path, {});
const alls = ['/', '..'].concat(Object.keys(list));
const hints = alls.filter(e => e.match(cur));
return {
list: hints,
from: CodeMirror.Pos(cursor.line, start),
to: CodeMirror.Pos(cursor.line, end)
};
};
};

View File

@ -1,20 +1,26 @@
'use strict';
const xOffsetUpdate = (pstate, xOffsetNext) => {
let {width, xOffset, xScale, time, sidebarWidth} = pstate;
const xOffsetUpdate = (pstate, nextOffsetX) => {
const { width, xOffset, xScale, time, sidebarWidth } = pstate;
const xOffsetMax = sidebarWidth; // maximum offset
xOffsetNext = (xOffsetNext > xOffsetMax) ? xOffsetMax : xOffsetNext;
// console.log('input offset', nextOffsetX);
// console.log('xScale', xScale);
const maxOffsetX = width - xScale * time + 2000; // maximum offset
nextOffsetX = Math.min(nextOffsetX, maxOffsetX);
const xOffsetMin = width - xScale * time; // minimum offset
xOffsetNext = (xOffsetNext < xOffsetMin) ? xOffsetMin : xOffsetNext;
const minOffsetX = 0; // minimum offset
nextOffsetX = Math.max(nextOffsetX, minOffsetX);
if (xOffsetNext === xOffset) {
return false; // exit without scroll
}
// console.log('max offset', maxOffsetX);
// console.log('min offset', minOffsetX);
// console.log('next offset', nextOffsetX);
pstate.xOffset = xOffsetNext;
return true;
if (nextOffsetX === xOffset) {
return false; // exit without scroll
}
pstate.xOffset = nextOffsetX;
return true;
};
module.exports = xOffsetUpdate;

View File

@ -9,8 +9,7 @@ const xScaleUpdate = (pstate, xScaleNext) => {
xScaleNext = (xScaleNext < xScaleMin) ? xScaleMin : xScaleNext;
console.log('pstate', pstate);
console.log('scale next', xScaleNext);
// console.log('scale next', xScaleNext);
if (xScaleNext === xScale) {
return false; // exit without scale change

View File

@ -3,6 +3,7 @@
"signal": "Signals",
"search-signal": "Search Signal",
"language-setting": "Language",
"wheel-zoom-ratio": "Wheel Zoom Level",
"search-setting": "Search",
"search-case-sensitivity": "Case Sensitivity",
@ -11,6 +12,7 @@
"search-display-parent-only": "Display Parent Module Only",
"search-nothing": "Find Nothing",
"signal-only": "Signal Only",
"module-only": "Module Only",
"signal-module": "Signal + Module",

View File

@ -3,6 +3,7 @@
"signal": "信号",
"search-signal": "搜索信号",
"language-setting": "语言",
"wheel-zoom-ratio": "滚轮缩放倍率",
"search-setting": "搜索",
"search-case-sensitivity": "区分大小写",