import * as vscode from 'vscode' ; import { XslLexer , LanguageConfiguration , GlobalInstructionData , GlobalInstructionType , DocumentTypes } from './xslLexer' ; import { GlobalsProvider } from './globalsProvider' ; import * as path from 'path' ; import { XsltTokenDefinitions } from './xsltTokenDefintions' ; import { XsltTokenCompletions } from './xsltTokenCompletions' ; import { XSLTSchema , SchemaData } from './xsltSchema' ; import { SchemaQuery } from './schemaQuery' ; import { XsltPackage , XsltSymbolProvider } from './xsltSymbolProvider' ; import { BaseToken , ExitCondition , LexPosition , XPathLexer } from './xpLexer' ; import { XPathSemanticTokensProvider } from './extension' ; import { DocumentChangeHandler } from './documentChangeHandler' ; interface ImportedGlobals { href : string ; data : GlobalInstructionData [ ] ; error : boolean ; } interface GlobalsSummary { globals : ImportedGlobals [ ] ; hrefs : string [ ] ; } export class XsltDefinitionProvider implements vscode . DefinitionProvider , vscode . CompletionItemProvider { private readonly xslLexer : XslLexer ; private xpLexer : XPathLexer | null = null ; private gp = new GlobalsProvider ( ) ; private docType : DocumentTypes ; private schemaData : SchemaData | undefined ; private languageConfig : LanguageConfiguration ; public constructor ( xsltConfiguration ) { this . languageConfig = xsltConfiguration ; this . xslLexer = new XslLexer ( xsltConfiguration ) ; this . xslLexer . provideCharLevelState = true ; this . docType = xsltConfiguration . docType ; this . schemaData = xsltConfiguration . schemaData ; } private getXPLexer ( ) { if ( this . xpLexer === null ) { this . xpLexer = new XPathLexer ( ) ; } return this . xpLexer ; } public async provideDefinition ( document , position , token ) { const lexPosition = { line : 0 , startCharacter : 0 , documentOffset : 0 } ; let { allTokens , globalInstructionData , allImportedGlobals } = await this . getImportedGlobals ( document , lexPosition ) ; return new Promise ( ( resolve , reject ) => { let location = undefined ; let isXSLT = this . docType === DocumentTypes . XSLT ; location = XsltTokenDefinitions . findDefinition ( isXSLT , document , allTokens , globalInstructionData , allImportedGlobals , position ) ; resolve ( location ) ; } ) ; } private async getImportedGlobals ( document , lexPosition ) { let allTokens = [ ] ; let globalInstructionData = [ ] ; if ( this . docType === DocumentTypes . XPath ) { allTokens = this . getXPLexer ( ) . analyse ( document . getText ( ) , ExitCondition . None , lexPosition ) ; globalInstructionData = XPathSemanticTokensProvider . getGlobalInstructionData ( ) ; } else { allTokens = this . xslLexer . analyse ( document . getText ( ) ) ; globalInstructionData = this . xslLexer . globalInstructionData ; } const xsltPackages = < XsltPackage [ ] > vscode . workspace . getConfiguration ( 'XSLT.resources' ) . get ( 'xsltPackages' ) ; const localImportedHrefs = XsltSymbolProvider . importSymbolHrefs ; let { importedGlobals1 , accumulatedHrefs } = await XsltSymbolProvider . processTopLevelImports ( false , this . xslLexer , localImportedHrefs , document , globalInstructionData , xsltPackages ) ; let globalsSummary0 = { globals : importedGlobals1 , hrefs : accumulatedHrefs } ; const maxImportLevel = 20 ; let processNestedGlobals = async ( ) => { let level = 0 ; while ( globalsSummary0 . hrefs . length > 0 && level < maxImportLevel ) { globalsSummary0 = await XsltSymbolProvider . processImportedGlobals ( xsltPackages , globalsSummary0 . globals , accumulatedHrefs , level === 0 ) ; level ++ ; } } ; await processNestedGlobals ( ) ; let allImportedGlobals = [ ] ; globalsSummary0 . globals . forEach ( ( globals ) => { if ( globals . error ) { } else { globals . data . forEach ( ( global ) => { global [ 'href' ] = globals . href ; allImportedGlobals . push ( global ) ; } ) ; } } ) ; return { allTokens , globalInstructionData , allImportedGlobals } ; } public async provideCompletionItems ( document , position , token , context ) { const keepNameTests = true ; const lexPosition = { line : 0 , startCharacter : 0 , documentOffset : 0 } ; let symbolsForXPath = [ ] ; let allTokens = [ ] ; let globalInstructionData = [ ] ; let uri ; if ( this . docType === DocumentTypes . XPath ) { allTokens = this . getXPLexer ( ) . analyse ( document . getText ( ) , ExitCondition . None , lexPosition ) ; globalInstructionData = XPathSemanticTokensProvider . getGlobalInstructionData ( ) ; uri = DocumentChangeHandler . lastActiveXMLEditor ?. document . uri ; } else { if ( this . docType === DocumentTypes . XSLT ) { uri = DocumentChangeHandler . lastActiveXMLNonXSLEditor ?. document . uri ; } else { uri = DocumentChangeHandler . lastActiveXMLEditor ?. document . uri ; } allTokens = this . xslLexer . analyse ( document . getText ( ) , keepNameTests ) ; globalInstructionData = this . xslLexer . globalInstructionData ; } if ( uri ) { const lastSymbols = XsltSymbolProvider . documentSymbols . get ( uri ) ; if ( lastSymbols ) { symbolsForXPath = lastSymbols ; } } const xsltPackages = < XsltPackage [ ] > vscode . workspace . getConfiguration ( 'XSLT.resources' ) . get ( 'xsltPackages' ) ; const localImportedHrefs = XsltSymbolProvider . importSymbolHrefs ; let { importedGlobals1 , accumulatedHrefs } = await XsltSymbolProvider . processTopLevelImports ( false , this . xslLexer , localImportedHrefs , document , globalInstructionData , xsltPackages ) ; let globalsSummary0 = { globals : importedGlobals1 , hrefs : accumulatedHrefs } ; const maxImportLevel = 20 ; let processNestedGlobals = async ( ) => { let level = 0 ; while ( globalsSummary0 . hrefs . length > 0 && level < maxImportLevel ) { globalsSummary0 = await XsltSymbolProvider . processImportedGlobals ( xsltPackages , globalsSummary0 . globals , accumulatedHrefs , level === 0 ) ; level ++ ; } } ; await processNestedGlobals ( ) ; return new Promise ( ( resolve , reject ) => { let allImportedGlobals = [ ] ; globalsSummary0 . globals . forEach ( ( globals ) => { if ( globals . error ) { } else { globals . data . forEach ( ( global ) => { global [ 'href' ] = globals . href ; allImportedGlobals . push ( global ) ; } ) ; } } ) ; let attNames = this . xslLexer . attributeNameTests ? this . xslLexer . attributeNameTests : [ ] ; let nodeNames = this . xslLexer . elementNameTests ? this . xslLexer . elementNameTests : [ ] ; let xslVariable = [ 'xsl:variable' , 'xsl:param' ] ; let completions ; completions = XsltTokenCompletions . getCompletions ( this . languageConfig , symbolsForXPath , xslVariable , attNames , nodeNames , document , allTokens , globalInstructionData , allImportedGlobals , position ) ; resolve ( completions ) ; } ) ; } }