Compare commits
	
		
			2 Commits
		
	
	
		
			a7b9e73096
			...
			d805569ed6
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | d805569ed6 | ||
|  | b3b104844b | 
| @@ -36,6 +36,13 @@ export async function requestModuleTree( | |||||||
|     ((moduleTree[modType] ??= { module: [], last: 0 }).module).push(rawPath); |     ((moduleTree[modType] ??= { module: [], last: 0 }).module).push(rawPath); | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   for (const entry of Object.values(moduleTree)) { | ||||||
|  |     entry.module.sort((a, b) =>   a.replace(/[^a-zA-Z0-9]/gi, "").localeCompare( b.replace(/[^a-zA-Z0-9]/gi, ""), undefined, { numeric: true, sensitivity: "base" } )); | ||||||
|  |     for (const elt of entry.module) { | ||||||
|  |       console.log(elt) | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |  | ||||||
|   console.log(moduleTree); |   console.log(moduleTree); | ||||||
|  |  | ||||||
|   return moduleTree; |   return moduleTree; | ||||||
| @@ -64,13 +71,14 @@ export async function addWave( | |||||||
|   const position = |   const position = | ||||||
|     hover && now - hover.at <= HOVER_FRESH_MS ? hover.pos : editor.selection.active; |     hover && now - hover.at <= HOVER_FRESH_MS ? hover.pos : editor.selection.active; | ||||||
|  |  | ||||||
|   const wordRange = editor.document.getWordRangeAtPosition(position); |   const expr = getExpressionAtPosition(editor.document, position); | ||||||
|   if (!wordRange) { |   if (!expr) { | ||||||
|     vscode.window.showInformationMessage('Hover a signal, then press your shortcut.'); |     vscode.window.showInformationMessage('Hover a signal, then press your shortcut.'); | ||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   let tokenText = editor.document.getText(wordRange); |   let tokenText = expr.text; | ||||||
|  |  | ||||||
|   const isVariable = await looksLikeVariable(editor, position); |   const isVariable = await looksLikeVariable(editor, position); | ||||||
|   if (!isVariable) { |   if (!isVariable) { | ||||||
|     const choice = await vscode.window.showWarningMessage( |     const choice = await vscode.window.showWarningMessage( | ||||||
| @@ -205,3 +213,174 @@ function flattenSymbols(items: vscode.DocumentSymbol[]): vscode.DocumentSymbol[] | |||||||
|   walk(items); |   walk(items); | ||||||
|   return out; |   return out; | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /** | ||||||
|  |  * Expand the hovered token into its full left-only member-access expression. | ||||||
|  |  * | ||||||
|  |  * Examples on: foo.bar[1][i].baz[2] | ||||||
|  |  *   hover "foo"    => "foo" | ||||||
|  |  *   hover "bar"    => "foo.bar" | ||||||
|  |  *   hover "[1]"    => "foo.bar[1]" | ||||||
|  |  *   hover "[i]"    => "foo.bar[1][i]" | ||||||
|  |  *   hover "baz"    => "foo.bar[1][i].baz" | ||||||
|  |  *   hover "[2]"    => "foo.bar[1][i].baz[2]" | ||||||
|  |  */ | ||||||
|  | export function getExpressionAtPosition( | ||||||
|  |   document: vscode.TextDocument, | ||||||
|  |   position: vscode.Position | ||||||
|  | ): { text: string; range: vscode.Range } | undefined { | ||||||
|  |   const text = document.getText(); | ||||||
|  |   const toff = document.offsetAt(position); | ||||||
|  |  | ||||||
|  |   const isIdentChar = (c: string) => /[A-Za-z0-9_$]/.test(c); | ||||||
|  |   const isSpace = (c: string) => /\s/.test(c); | ||||||
|  |  | ||||||
|  |   // --- 1) Find the "segment" under the cursor: BRACKET GROUP [ ... ] first, then IDENT | ||||||
|  |   let segStart = -1; | ||||||
|  |   let segEnd = -1; | ||||||
|  |  | ||||||
|  |   // Try bracket group first (fixes the [1] case) | ||||||
|  |   const group = findEnclosingBracketGroup(text, toff); | ||||||
|  |   if (group) { | ||||||
|  |     segStart = group.start; | ||||||
|  |     segEnd = group.end; | ||||||
|  |   } else { | ||||||
|  |     // No bracket group → try word | ||||||
|  |     const identRegex = /[A-Za-z_$][A-Za-z0-9_$]*/; | ||||||
|  |     const word = | ||||||
|  |       document.getWordRangeAtPosition(position, identRegex) ?? | ||||||
|  |       (toff > 0 ? document.getWordRangeAtPosition(document.positionAt(toff - 1), identRegex) : undefined); | ||||||
|  |     if (!word) return undefined; | ||||||
|  |     segStart = document.offsetAt(word.start); | ||||||
|  |     segEnd = document.offsetAt(word.end); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   // --- 2) Expand LEFT to include ".ident" and bracket chains | ||||||
|  |   let left = segStart; | ||||||
|  |  | ||||||
|  |   const includePrevBracketGroup = (): boolean => { | ||||||
|  |     if (left <= 0 || text[left - 1] !== ']') return false; | ||||||
|  |     let depth = 1; | ||||||
|  |     for (let k = left - 2; k >= 0; k--) { | ||||||
|  |       const ch = text[k]; | ||||||
|  |       if (ch === ']') depth++; | ||||||
|  |       else if (ch === '[') { | ||||||
|  |         depth--; | ||||||
|  |         if (depth === 0) { | ||||||
|  |           left = k; | ||||||
|  |           return true; | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return false; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   const includePrevDotIdent = (): boolean => { | ||||||
|  |     let p = left; | ||||||
|  |  | ||||||
|  |     // allow spaces before checking for '.' | ||||||
|  |     while (p > 0 && isSpace(text[p - 1])) p--; | ||||||
|  |  | ||||||
|  |     // --- dot case | ||||||
|  |     if (p > 0 && text[p - 1] === '.') { | ||||||
|  |       p--; // on '.' | ||||||
|  |       // skip spaces before dot | ||||||
|  |       while (p > 0 && isSpace(text[p - 1])) p--; | ||||||
|  |  | ||||||
|  |       // consume any bracket groups before the dot | ||||||
|  |       let q = p; | ||||||
|  |       const consumePrevBracketGroupAt = (idx: number): number | null => { | ||||||
|  |         if (idx <= 0 || text[idx - 1] !== ']') return null; | ||||||
|  |         let d = 1; | ||||||
|  |         for (let k = idx - 2; k >= 0; k--) { | ||||||
|  |           const ch = text[k]; | ||||||
|  |           if (ch === ']') d++; | ||||||
|  |           else if (ch === '[') { | ||||||
|  |             d--; | ||||||
|  |             if (d === 0) return k; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         return null; | ||||||
|  |       }; | ||||||
|  |  | ||||||
|  |       while (true) { | ||||||
|  |         while (q > 0 && isSpace(text[q - 1])) q--; | ||||||
|  |         const nextQ = consumePrevBracketGroupAt(q); | ||||||
|  |         if (nextQ === null) break; | ||||||
|  |         q = nextQ; | ||||||
|  |       } | ||||||
|  |  | ||||||
|  |       // now require identifier before them | ||||||
|  |       while (q > 0 && isSpace(text[q - 1])) q--; | ||||||
|  |       if (q <= 0 || !isIdentChar(text[q - 1])) return false; | ||||||
|  |  | ||||||
|  |       let k = q - 1; | ||||||
|  |       while (k >= 0 && isIdentChar(text[k])) k--; | ||||||
|  |       left = k + 1; | ||||||
|  |  | ||||||
|  |       // also include bracket groups attached even further left | ||||||
|  |       while (includePrevBracketGroup()) {} | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     // --- bare ident case: only if adjacent (no whitespace) | ||||||
|  |     if (left > 0 && isIdentChar(text[left - 1])) { | ||||||
|  |       let k = left - 1; | ||||||
|  |       while (k >= 0 && isIdentChar(text[k])) k--; | ||||||
|  |       const start = k + 1; | ||||||
|  |  | ||||||
|  |       // Stop before SV declaration keywords (logic, wire, etc.) | ||||||
|  |       const token = text.slice(start, left); | ||||||
|  |       const stopKeywords = new Set([ | ||||||
|  |         'logic','wire','reg','bit','byte','shortint','int','longint','integer','time', | ||||||
|  |         'signed','unsigned','const','var','local','static','automatic' | ||||||
|  |       ]); | ||||||
|  |       if (stopKeywords.has(token)) return false; | ||||||
|  |  | ||||||
|  |       left = start; | ||||||
|  |       while (includePrevBracketGroup()) {} | ||||||
|  |       return true; | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     return false; | ||||||
|  |   }; | ||||||
|  |  | ||||||
|  |   // include bracket groups and dot chains iteratively | ||||||
|  |   while (includePrevBracketGroup()) {} | ||||||
|  |   while (includePrevDotIdent()) {} | ||||||
|  |  | ||||||
|  |   const range = new vscode.Range(document.positionAt(left), document.positionAt(segEnd)); | ||||||
|  |   const expr = text.slice(left, segEnd).trim(); | ||||||
|  |   if (!expr) return undefined; | ||||||
|  |  | ||||||
|  |   return { text: expr, range }; | ||||||
|  | } | ||||||
|  |  | ||||||
|  | /** Finds the [ ... ] group that contains `offset`, or just before it if cursor is on a ']'. */ | ||||||
|  | function findEnclosingBracketGroup(text: string, offset: number): { start: number; end: number } | undefined { | ||||||
|  |   let i = offset; | ||||||
|  |   if (i > 0 && text[i - 1] === ']') i--; // hovering just after a ']' counts | ||||||
|  |  | ||||||
|  |   for (let l = i; l >= 0; l--) { | ||||||
|  |     const ch = text[l]; | ||||||
|  |     if (ch === '[') { | ||||||
|  |       let depth = 1; | ||||||
|  |       for (let r = l + 1; r < text.length; r++) { | ||||||
|  |         const cr = text[r]; | ||||||
|  |         if (cr === '[') depth++; | ||||||
|  |         else if (cr === ']') { | ||||||
|  |           depth--; | ||||||
|  |           if (depth === 0) { | ||||||
|  |             if (i >= l && i <= r) { | ||||||
|  |               return { start: l, end: r + 1 }; | ||||||
|  |             } | ||||||
|  |             break; | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       } | ||||||
|  |     } else if (ch === '\n' || ch === '\r') { | ||||||
|  |       break; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   return undefined; | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user