Compare commits
	
		
			2 Commits
		
	
	
		
			a7b9e73096
			...
			main
		
	
	| Author | SHA1 | Date | |
|---|---|---|---|
|  | d805569ed6 | ||
|  | b3b104844b | 
| @@ -36,6 +36,13 @@ export async function requestModuleTree( | ||||
|     ((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); | ||||
|  | ||||
|   return moduleTree; | ||||
| @@ -64,13 +71,14 @@ export async function addWave( | ||||
|   const position = | ||||
|     hover && now - hover.at <= HOVER_FRESH_MS ? hover.pos : editor.selection.active; | ||||
|  | ||||
|   const wordRange = editor.document.getWordRangeAtPosition(position); | ||||
|   if (!wordRange) { | ||||
|   const expr = getExpressionAtPosition(editor.document, position); | ||||
|   if (!expr) { | ||||
|     vscode.window.showInformationMessage('Hover a signal, then press your shortcut.'); | ||||
|     return; | ||||
|   } | ||||
|    | ||||
|   let tokenText = editor.document.getText(wordRange); | ||||
|   let tokenText = expr.text; | ||||
|  | ||||
|   const isVariable = await looksLikeVariable(editor, position); | ||||
|   if (!isVariable) { | ||||
|     const choice = await vscode.window.showWarningMessage( | ||||
| @@ -205,3 +213,174 @@ function flattenSymbols(items: vscode.DocumentSymbol[]): vscode.DocumentSymbol[] | ||||
|   walk(items); | ||||
|   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