Use VS Code mode
This commit is contained in:
		| @@ -10,6 +10,10 @@ import { requestModuleTree, addWave } from './wave_editor'; | ||||
| export const lastHoverByDoc = new Map<string, { pos: vscode.Position; at: number }>(); | ||||
| 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(); | ||||
|   | ||||
| @@ -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<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 { | ||||
|   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<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