diff --git a/package.json b/package.json index 06aff47..c87f191 100644 --- a/package.json +++ b/package.json @@ -16,10 +16,10 @@ { "command": "modelsim.toggleWaveMode", "title": "Toggle Wave Debug Mode" } ], "keybindings": [ - { "command": "modelsim.addWaveUnderCursor", "key": "ctrl+w", "args": { "mode": "auto" } }, - { "command": "modelsim.addWaveUnderCursor", "key": "ctrl+e", "args": { "mode": "set" } }, - { "command": "modelsim.toggleWaveMode", "key": "ctrl+alt+m" }, - { "command": "modelsim.zoomInWave", "key": "ctrl+alt+u" } + { "command": "modelsim.addWaveUnderCursor", "key": "ctrl+w", "when": "modelsim.mode", "args": { "mode": "auto" } }, + { "command": "modelsim.addWaveUnderCursor", "key": "ctrl+e", "when": "modelsim.mode", "args": { "mode": "set" } }, + { "command": "modelsim.toggleWaveMode", "key": "ctrl+alt+m" }, + { "command": "modelsim.zoomInWave", "key": "ctrl+alt+u", "when": "modelsim.mode" } ], "viewsContainers": { "panel": [ diff --git a/src/extension.ts b/src/extension.ts index 5e17630..57d2582 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -10,6 +10,10 @@ import { requestModuleTree, addWave } from './wave_editor'; export const lastHoverByDoc = new Map(); 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]", ...] const svSelectors: vscode.DocumentSelector = [ @@ -17,20 +21,22 @@ const svSelectors: vscode.DocumentSelector = [ { language: 'verilog', scheme: 'file' } ]; -export let waveMode = false; -let statusItem: vscode.StatusBarItem; -function toggleWaveMode() { + +async function toggleWaveMode() { waveMode = !waveMode; statusItem.text = waveMode ? '🌊 Wave Debug Mode' : '✏️ Edit Mode'; + await vscode.commands.executeCommand('setContext', CTX, waveMode); statusItem.tooltip = waveMode ? 'Wave Debug Mode — click to switch to Edit 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.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 () => { toggleWaveMode(); diff --git a/src/wave_editor.ts b/src/wave_editor.ts index b4338ed..d4b9977 100644 --- a/src/wave_editor.ts +++ b/src/wave_editor.ts @@ -43,116 +43,115 @@ export async function requestModuleTree( export async function addWave( mode: String ) { - if (waveMode) { - - const editor = vscode.window.activeTextEditor; - if (!editor) return; - - const cfg = vscode.workspace.getConfiguration('modelsimWave'); - const sharedDir = cfg.get('sharedDir') || '.'; - const topScope = cfg.get('topScope') || 'sim:/test/'; // keep in sync with package.json - const timeoutMs = cfg.get('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 { + if (!waveMode) { 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('sharedDir') || '.'; + const topScope = cfg.get('topScope') || 'sim:/test/'; // keep in sync with package.json + const timeoutMs = cfg.get('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).'); } }