@@ -307,33 +307,52 @@ function collectMatchingDeclarations(
307307 break ;
308308 }
309309 case "ImportStatement" : {
310+ // The grammar emits one ImportStatement for both `import x [as y]` and
311+ // `from m import x [as y], ...`. Direct children include the keywords
312+ // (`from`/`import`/`as`), commas, dots, and every VariableName from the
313+ // module path AND the import list. We only want the names that actually
314+ // bind in the current scope: the post-`as` alias if present, otherwise
315+ // the imported name itself. Names before `import` (the from-path) and
316+ // the original name when an alias follows it are NOT bindings.
310317 const subCursor = node . cursor ( ) ;
311318 subCursor . firstChild ( ) ;
312- do {
313- if (
314- subCursor . name === "VariableName" &&
315- state . doc . sliceString ( subCursor . from , subCursor . to ) === variableName
316- ) {
317- addDeclaration ( declarations , currentScope , subCursor . from ) ;
319+ let pastImport = false ;
320+ // Buffer the most recent post-`import` VariableName so we can defer
321+ // committing it until we know whether `as` follows.
322+ let pending : { from : number ; matches : boolean } | null = null ;
323+ const commit = ( ) => {
324+ if ( pending ?. matches ) {
325+ addDeclaration ( declarations , currentScope , pending . from ) ;
318326 }
319- } while ( subCursor . nextSibling ( ) ) ;
320- break ;
321- }
322- case "ImportFromStatement" : {
323- const subCursor = node . cursor ( ) ;
324- subCursor . firstChild ( ) ;
325- let foundImport = false ;
327+ pending = null ;
328+ } ;
326329 do {
327330 if ( subCursor . name === "import" ) {
328- foundImport = true ;
329- } else if (
330- foundImport &&
331- subCursor . name === "VariableName" &&
332- state . doc . sliceString ( subCursor . from , subCursor . to ) === variableName
333- ) {
334- addDeclaration ( declarations , currentScope , subCursor . from ) ;
331+ pastImport = true ;
332+ continue ;
333+ }
334+ if ( ! pastImport ) {
335+ continue ;
336+ }
337+ if ( subCursor . name === "as" ) {
338+ // Next VariableName is the alias and replaces `pending`.
339+ pending = null ;
340+ continue ;
341+ }
342+ if ( subCursor . name === "VariableName" ) {
343+ // Flush any previous pending name (no `as` followed it).
344+ commit ( ) ;
345+ pending = {
346+ from : subCursor . from ,
347+ matches :
348+ state . doc . sliceString ( subCursor . from , subCursor . to ) ===
349+ variableName ,
350+ } ;
351+ } else if ( subCursor . name === "," ) {
352+ commit ( ) ;
335353 }
336354 } while ( subCursor . nextSibling ( ) ) ;
355+ commit ( ) ;
337356 break ;
338357 }
339358 case "TryStatement" :
@@ -410,23 +429,21 @@ function findScopedDefinitionPosition(
410429 * @param view The editor view which contains the variable name.
411430 * @param variableName The name of the variable to select, if found in the editor.
412431 * @param usagePosition The position of the variable usage, if available.
413- * @param fallbackToFirstMatch Whether to fall back to the first matching
414- * variable name when no scoped definition is found. Defaults to true.
415432 */
416433export function goToVariableDefinition (
417434 view : EditorView ,
418435 variableName : string ,
419436 usagePosition ?: number ,
420- fallbackToFirstMatch = true ,
421437) : boolean {
422438 const { state } = view ;
423- let from : number | null = null ;
424- if ( usagePosition !== undefined ) {
425- from = findScopedDefinitionPosition ( state , variableName , usagePosition ) ;
426- }
427- if ( from === null && fallbackToFirstMatch ) {
428- from = findFirstMatchingVariable ( state , variableName ) ;
429- }
439+ // When the caller knows the usage position, trust the scoped lookup. Falling
440+ // back to first-match would defeat the local-vs-cross-cell decision in
441+ // goToDefinition: if the symbol only appears as a module path in an import,
442+ // scoped resolution returns null and we want the caller to try other cells.
443+ const from =
444+ usagePosition !== undefined
445+ ? findScopedDefinitionPosition ( state , variableName , usagePosition )
446+ : findFirstMatchingVariable ( state , variableName ) ;
430447
431448 if ( from === null ) {
432449 return false ;
0 commit comments