Use VS Code mode
This commit is contained in:
@@ -16,10 +16,10 @@
|
|||||||
{ "command": "modelsim.toggleWaveMode", "title": "Toggle Wave Debug Mode" }
|
{ "command": "modelsim.toggleWaveMode", "title": "Toggle Wave Debug Mode" }
|
||||||
],
|
],
|
||||||
"keybindings": [
|
"keybindings": [
|
||||||
{ "command": "modelsim.addWaveUnderCursor", "key": "ctrl+w", "args": { "mode": "auto" } },
|
{ "command": "modelsim.addWaveUnderCursor", "key": "ctrl+w", "when": "modelsim.mode", "args": { "mode": "auto" } },
|
||||||
{ "command": "modelsim.addWaveUnderCursor", "key": "ctrl+e", "args": { "mode": "set" } },
|
{ "command": "modelsim.addWaveUnderCursor", "key": "ctrl+e", "when": "modelsim.mode", "args": { "mode": "set" } },
|
||||||
{ "command": "modelsim.toggleWaveMode", "key": "ctrl+alt+m" },
|
{ "command": "modelsim.toggleWaveMode", "key": "ctrl+alt+m" },
|
||||||
{ "command": "modelsim.zoomInWave", "key": "ctrl+alt+u" }
|
{ "command": "modelsim.zoomInWave", "key": "ctrl+alt+u", "when": "modelsim.mode" }
|
||||||
],
|
],
|
||||||
"viewsContainers": {
|
"viewsContainers": {
|
||||||
"panel": [
|
"panel": [
|
||||||
|
|||||||
@@ -10,6 +10,10 @@ import { requestModuleTree, addWave } from './wave_editor';
|
|||||||
export const lastHoverByDoc = new Map<string, { pos: vscode.Position; at: number }>();
|
export const lastHoverByDoc = new Map<string, { pos: vscode.Position; at: number }>();
|
||||||
export const HOVER_FRESH_MS = 2000;
|
export const HOVER_FRESH_MS = 2000;
|
||||||
|
|
||||||
|
let statusItem: vscode.StatusBarItem;
|
||||||
|
const CTX = 'modelsim.mode';
|
||||||
|
export let waveMode = false;
|
||||||
|
|
||||||
// Hold MANY instance paths per module name, e.g. queue_slot -> ["/test/...[0]", "/test/...[1]", ...]
|
// Hold MANY instance paths per module name, e.g. queue_slot -> ["/test/...[0]", "/test/...[1]", ...]
|
||||||
|
|
||||||
const svSelectors: vscode.DocumentSelector = [
|
const svSelectors: vscode.DocumentSelector = [
|
||||||
@@ -17,20 +21,22 @@ const svSelectors: vscode.DocumentSelector = [
|
|||||||
{ language: 'verilog', scheme: 'file' }
|
{ language: 'verilog', scheme: 'file' }
|
||||||
];
|
];
|
||||||
|
|
||||||
export let waveMode = false;
|
|
||||||
let statusItem: vscode.StatusBarItem;
|
|
||||||
|
|
||||||
function toggleWaveMode() {
|
|
||||||
|
async function toggleWaveMode() {
|
||||||
waveMode = !waveMode;
|
waveMode = !waveMode;
|
||||||
statusItem.text = waveMode ? '🌊 Wave Debug Mode' : '✏️ Edit Mode';
|
statusItem.text = waveMode ? '🌊 Wave Debug Mode' : '✏️ Edit Mode';
|
||||||
|
await vscode.commands.executeCommand('setContext', CTX, waveMode);
|
||||||
statusItem.tooltip = waveMode
|
statusItem.tooltip = waveMode
|
||||||
? 'Wave Debug Mode — click to switch to Edit Mode'
|
? 'Wave Debug Mode — click to switch to Edit Mode'
|
||||||
: 'Edit Mode — click to switch to Wave Debug Mode';
|
: 'Edit Mode — click to switch to Wave Debug Mode';
|
||||||
}
|
}
|
||||||
|
|
||||||
export function activate(context: vscode.ExtensionContext) {
|
export async function activate(context: vscode.ExtensionContext) {
|
||||||
statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 1000);
|
statusItem = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Right, 1000);
|
||||||
statusItem.command = 'modelsim.toggleWaveMode'; // click to toggle
|
// statusItem.command = 'modelsim.toggleWaveMode'; // click to toggle
|
||||||
|
|
||||||
|
await vscode.commands.executeCommand('setContext', CTX, false);
|
||||||
|
|
||||||
const cmd_2 = vscode.commands.registerCommand('modelsim.toggleWaveMode', async () => {
|
const cmd_2 = vscode.commands.registerCommand('modelsim.toggleWaveMode', async () => {
|
||||||
toggleWaveMode();
|
toggleWaveMode();
|
||||||
|
|||||||
@@ -43,116 +43,115 @@ export async function requestModuleTree(
|
|||||||
export async function addWave(
|
export async function addWave(
|
||||||
mode: String
|
mode: String
|
||||||
) {
|
) {
|
||||||
if (waveMode) {
|
if (!waveMode) {
|
||||||
|
|
||||||
const editor = vscode.window.activeTextEditor;
|
|
||||||
if (!editor) return;
|
|
||||||
|
|
||||||
const cfg = vscode.workspace.getConfiguration('modelsimWave');
|
|
||||||
const sharedDir = cfg.get<string>('sharedDir') || '.';
|
|
||||||
const topScope = cfg.get<string>('topScope') || 'sim:/test/'; // keep in sync with package.json
|
|
||||||
const timeoutMs = cfg.get<number>('timeoutMs') ?? 5000;
|
|
||||||
|
|
||||||
// Prefer last hover over caret
|
|
||||||
const docKey = editor.document.uri.toString();
|
|
||||||
const hover = lastHoverByDoc.get(docKey);
|
|
||||||
const now = Date.now();
|
|
||||||
const position =
|
|
||||||
hover && now - hover.at <= HOVER_FRESH_MS ? hover.pos : editor.selection.active;
|
|
||||||
|
|
||||||
const wordRange = editor.document.getWordRangeAtPosition(position);
|
|
||||||
if (!wordRange) {
|
|
||||||
vscode.window.showInformationMessage('Hover a signal, then press your shortcut.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const tokenText = editor.document.getText(wordRange);
|
|
||||||
const isVariable = await looksLikeVariable(editor, position);
|
|
||||||
if (!isVariable) {
|
|
||||||
const choice = await vscode.window.showWarningMessage(
|
|
||||||
`"${tokenText}" doesn’t look like a variable here. Add anyway?`,
|
|
||||||
'Add',
|
|
||||||
'Cancel'
|
|
||||||
);
|
|
||||||
if (choice !== 'Add') return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load module tree once per session
|
|
||||||
if (Object.keys(moduleTree).length === 0) {
|
|
||||||
moduleTree = await requestModuleTree(sharedDir, topScope, timeoutMs);
|
|
||||||
console.log("Lenght: ", Object.keys(moduleTree).length);
|
|
||||||
if (Object.keys(moduleTree).length === 0) {
|
|
||||||
vscode.window.showErrorMessage('Failed to load module hierarchy from ModelSim.');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get module name from file name (language-independent)
|
|
||||||
const modName = path.basename(editor.document.fileName, path.extname(editor.document.fileName));
|
|
||||||
|
|
||||||
let instancePaths =
|
|
||||||
moduleTree[modName].module ?? moduleTree[modName.toLowerCase()].module;
|
|
||||||
if (!instancePaths || instancePaths.length === 0) {
|
|
||||||
console.log(
|
|
||||||
`No instance paths found for module "${modName}". ` +
|
|
||||||
`Ensure your poller uses "find instances" and the design is loaded.`
|
|
||||||
);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Add the token for every instance of this module (dedupe paths just in case)
|
|
||||||
instancePaths = Array.from(new Set(instancePaths)).map(p => p.replace(/\/+/g, '/'));
|
|
||||||
|
|
||||||
let instance_num = moduleTree[modName].last ?? moduleTree[modName.toLowerCase()].last;
|
|
||||||
if (instancePaths.length > 1 && mode === 'set') {
|
|
||||||
const input_num = await vscode.window.showInputBox({
|
|
||||||
title: 'Enter a number',
|
|
||||||
prompt: 'This number will be used by the action.',
|
|
||||||
placeHolder: moduleTree[modName].last !== undefined ? `Press Enter to reuse ${moduleTree[modName].last}` : 'e.g. 42',
|
|
||||||
value: moduleTree[modName].last !== undefined ? String(moduleTree[modName].last) : '',
|
|
||||||
ignoreFocusOut: true,
|
|
||||||
validateInput: (value) => {
|
|
||||||
if (value.trim() === '') return null; // allow Enter to reuse last
|
|
||||||
const n = Number(value);
|
|
||||||
if (!Number.isInteger(n)) return 'Please enter an integer.';
|
|
||||||
if (n < 0) return 'Please enter a non-negative integer.';
|
|
||||||
// optionally cap it
|
|
||||||
if (n > 10000) return 'That’s too large (max 10000).';
|
|
||||||
return null;
|
|
||||||
},
|
|
||||||
});
|
|
||||||
|
|
||||||
if (input_num === undefined) {
|
|
||||||
// User hit Esc — do nothing
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Empty input means reuse last (if any)
|
|
||||||
instance_num = (input_num.trim() === '' || Number(input_num) >= moduleTree[modName].module.length) && moduleTree[modName].last !== undefined ? moduleTree[modName].last : Number(input_num);
|
|
||||||
|
|
||||||
moduleTree[modName].last = instance_num;
|
|
||||||
}
|
|
||||||
|
|
||||||
let ok = true;
|
|
||||||
// for (const p of instancePaths) {
|
|
||||||
const cmd = `quietly add wave -noupdate \{${instancePaths[instance_num]}/${tokenText}\}`.replace(/\/+/g, '/');
|
|
||||||
console.log(cmd);
|
|
||||||
const res = await sendAndAwait(sharedDir, cmd, timeoutMs);
|
|
||||||
ok = ok && !!res;
|
|
||||||
ok = ok && !!(await sendAndAwait(sharedDir, 'update', timeoutMs));
|
|
||||||
|
|
||||||
if (ok) {
|
|
||||||
vscode.window.showInformationMessage(
|
|
||||||
`Added "${tokenText}" for ${instancePaths.length} instance(s) of ${modName}.`
|
|
||||||
);
|
|
||||||
} else {
|
|
||||||
vscode.window.showWarningMessage('No response from ModelSim (timeout or error).');
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
await vscode.commands.executeCommand("workbench.action.closeActiveEditor");
|
await vscode.commands.executeCommand("workbench.action.closeActiveEditor");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const editor = vscode.window.activeTextEditor;
|
||||||
|
if (!editor) return;
|
||||||
|
|
||||||
|
const cfg = vscode.workspace.getConfiguration('modelsimWave');
|
||||||
|
const sharedDir = cfg.get<string>('sharedDir') || '.';
|
||||||
|
const topScope = cfg.get<string>('topScope') || 'sim:/test/'; // keep in sync with package.json
|
||||||
|
const timeoutMs = cfg.get<number>('timeoutMs') ?? 5000;
|
||||||
|
|
||||||
|
// Prefer last hover over caret
|
||||||
|
const docKey = editor.document.uri.toString();
|
||||||
|
const hover = lastHoverByDoc.get(docKey);
|
||||||
|
const now = Date.now();
|
||||||
|
const position =
|
||||||
|
hover && now - hover.at <= HOVER_FRESH_MS ? hover.pos : editor.selection.active;
|
||||||
|
|
||||||
|
const wordRange = editor.document.getWordRangeAtPosition(position);
|
||||||
|
if (!wordRange) {
|
||||||
|
vscode.window.showInformationMessage('Hover a signal, then press your shortcut.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const tokenText = editor.document.getText(wordRange);
|
||||||
|
const isVariable = await looksLikeVariable(editor, position);
|
||||||
|
if (!isVariable) {
|
||||||
|
const choice = await vscode.window.showWarningMessage(
|
||||||
|
`"${tokenText}" doesn’t look like a variable here. Add anyway?`,
|
||||||
|
'Add',
|
||||||
|
'Cancel'
|
||||||
|
);
|
||||||
|
if (choice !== 'Add') return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Load module tree once per session
|
||||||
|
if (Object.keys(moduleTree).length === 0) {
|
||||||
|
moduleTree = await requestModuleTree(sharedDir, topScope, timeoutMs);
|
||||||
|
console.log("Lenght: ", Object.keys(moduleTree).length);
|
||||||
|
if (Object.keys(moduleTree).length === 0) {
|
||||||
|
vscode.window.showErrorMessage('Failed to load module hierarchy from ModelSim.');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get module name from file name (language-independent)
|
||||||
|
const modName = path.basename(editor.document.fileName, path.extname(editor.document.fileName));
|
||||||
|
|
||||||
|
let instancePaths =
|
||||||
|
moduleTree[modName].module ?? moduleTree[modName.toLowerCase()].module;
|
||||||
|
if (!instancePaths || instancePaths.length === 0) {
|
||||||
|
console.log(
|
||||||
|
`No instance paths found for module "${modName}". ` +
|
||||||
|
`Ensure your poller uses "find instances" and the design is loaded.`
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Add the token for every instance of this module (dedupe paths just in case)
|
||||||
|
instancePaths = Array.from(new Set(instancePaths)).map(p => p.replace(/\/+/g, '/'));
|
||||||
|
|
||||||
|
let instance_num = moduleTree[modName].last ?? moduleTree[modName.toLowerCase()].last;
|
||||||
|
if (instancePaths.length > 1 && mode === 'set') {
|
||||||
|
const input_num = await vscode.window.showInputBox({
|
||||||
|
title: 'Enter a number',
|
||||||
|
prompt: 'This number will be used by the action.',
|
||||||
|
placeHolder: moduleTree[modName].last !== undefined ? `Press Enter to reuse ${moduleTree[modName].last}` : 'e.g. 42',
|
||||||
|
value: moduleTree[modName].last !== undefined ? String(moduleTree[modName].last) : '',
|
||||||
|
ignoreFocusOut: true,
|
||||||
|
validateInput: (value) => {
|
||||||
|
if (value.trim() === '') return null; // allow Enter to reuse last
|
||||||
|
const n = Number(value);
|
||||||
|
if (!Number.isInteger(n)) return 'Please enter an integer.';
|
||||||
|
if (n < 0) return 'Please enter a non-negative integer.';
|
||||||
|
// optionally cap it
|
||||||
|
if (n > 10000) return 'That’s too large (max 10000).';
|
||||||
|
return null;
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
if (input_num === undefined) {
|
||||||
|
// User hit Esc — do nothing
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Empty input means reuse last (if any)
|
||||||
|
instance_num = (input_num.trim() === '' || Number(input_num) >= moduleTree[modName].module.length) && moduleTree[modName].last !== undefined ? moduleTree[modName].last : Number(input_num);
|
||||||
|
|
||||||
|
moduleTree[modName].last = instance_num;
|
||||||
|
}
|
||||||
|
|
||||||
|
let ok = true;
|
||||||
|
// for (const p of instancePaths) {
|
||||||
|
const cmd = `quietly add wave -noupdate \{${instancePaths[instance_num]}/${tokenText}\}`.replace(/\/+/g, '/');
|
||||||
|
console.log(cmd);
|
||||||
|
const res = await sendAndAwait(sharedDir, cmd, timeoutMs);
|
||||||
|
ok = ok && !!res;
|
||||||
|
ok = ok && !!(await sendAndAwait(sharedDir, 'update', timeoutMs));
|
||||||
|
|
||||||
|
if (ok) {
|
||||||
|
vscode.window.showInformationMessage(
|
||||||
|
`Added "${tokenText}" for ${instancePaths.length} instance(s) of ${modName}.`
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
vscode.window.showWarningMessage('No response from ModelSim (timeout or error).');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user