/******************************************************************************
 * Copyright 2021 TypeFox GmbH
 * This program and the accompanying materials are made available under the
 * terms of the MIT License, which is available in the project root.
 ******************************************************************************/ import { CancellationToken , DefinitionParams , LocationLink } from 'vscode-languageserver' ; import { NameProvider } from '../references/naming' ; import { References } from '../references/references' ; import { LangiumServices } from '../services' ; import { CstNode } from '../syntax-tree' ; import { findLeafNodeAtOffset , getDocument } from '../utils/ast-util' ; import { MaybePromise } from '../utils/promise-util' ; import { LangiumDocument } from '../workspace/documents' ; export interface GoToResolver { throws throws goToDefinition ( document , params , cancelToken ? ) : MaybePromise < LocationLink [ ] | undefined > ; } export class DefaultGoToResolverProvider implements GoToResolver { protected readonly nameProvider : NameProvider ; protected readonly references : References ; constructor ( services ) { this . nameProvider = services . references . NameProvider ; this . references = services . references . References ; } goToDefinition ( document , params ) { const rootNode = document . parseResult . value ; const targetCstNodes = [ ] ; if ( rootNode . $cstNode ) { const cst = rootNode . $cstNode ; const sourceCstNode = findLeafNodeAtOffset ( cst , document . textDocument . offsetAt ( params . position ) ) ; if ( sourceCstNode ) { const targetNode = this . references . findDeclaration ( sourceCstNode ) ; if ( targetNode ?. element ) { const targetDoc = getDocument ( targetNode ?. element ) ; if ( targetNode && targetDoc ) { targetCstNodes . push ( { source : sourceCstNode , target : targetNode , targetDocument : targetDoc } ) ; } } } } return targetCstNodes . map ( link => LocationLink . create ( link . targetDocument . textDocument . uri , ( this . findActualNodeFor ( link . target ) ?? link . target ) . range , link . target . range , link . source . range ) ) ; } protected findActualNodeFor ( cstNode ) { let actualNode = cstNode ; while ( ! actualNode ?. element ?. $cstNode ) { if ( ! actualNode ) return undefined ; actualNode = actualNode . parent ; } return actualNode . element . $cstNode ; } }