import * as vscode from 'vscode' ; import { JsonMap } from './utilities' ; import { GLTF2 } from './GLTF2' ; const GLTF_VALIDATOR = 'glTF Validator' ; const UNDECLARED_EXTENSION = 'UNDECLARED_EXTENSION' ; const ADD_EXTENSION = 'Add Extension to \'extensionsUsed\'' ; export class GltfActionProvider implements vscode . CodeActionProvider { public static readonly providedCodeActionKinds = [ vscode . CodeActionKind . QuickFix ] ; provideCodeActions ( document , range , context , token ) { return context . diagnostics . filter ( diagnostic => diagnostic . source === GLTF_VALIDATOR && diagnostic . code === UNDECLARED_EXTENSION ) . map ( diagnostic => this . createCommandDeclareExtension ( diagnostic ) ) ; } private createCommandDeclareExtension ( diagnostic ) { const action = new vscode . CodeAction ( ADD_EXTENSION , vscode . CodeActionKind . QuickFix ) ; action . command = { command : 'gltf.declareExtension' , arguments : [ diagnostic ] , title : ADD_EXTENSION , tooltip : 'Add this extension to the extensionsUsed array.' } ; action . diagnostics = [ diagnostic ] ; action . isPreferred = true ; return action ; } public static declareExtension ( diagnostic , map , textEditor , edit ) { const document = textEditor . document ; let searchRange ; if ( diagnostic ) { searchRange = diagnostic . range ; } else { const selection = textEditor . selection ; searchRange = new vscode . Range ( selection . active , selection . active ) ; } const pointers = map . pointers ; let bestKey = '' ; for ( let key of Object . keys ( pointers ) ) { let pointer = pointers [ key ] ; if ( pointer . key ) { const range = new vscode . Range ( document . positionAt ( pointer . key . pos ) , document . positionAt ( pointer . valueEnd . pos ) ) ; if ( range . contains ( searchRange ) ) { bestKey = key ; } } } let pos = bestKey . lastIndexOf ( '/extensions/' ) ; if ( pos < 0 ) { return ; } let extensionName = bestKey . substring ( pos + 12 ) ; let pos2 = extensionName . indexOf ( '/' ) ; if ( pos2 >= 0 ) { extensionName = extensionName . substring ( 0 , pos2 ) ; } if ( extensionName === '' ) { return ; } const eol = ( document . eol === vscode . EndOfLine . CRLF ) ? '\r\n' : '\n' ; const tabSize = textEditor . options . tabSize as number ; const space = textEditor . options . insertSpaces ? ( new Array ( tabSize + 1 ) . join ( ' ' ) ) : '\t' ; let insert = - 1 ; let newJson ; if ( pointers [ '/extensionsUsed' ] !== undefined ) { for ( let key of Object . keys ( pointers ) ) { if ( key . startsWith ( '/extensionsUsed/' ) ) { insert = Math . max ( insert , pointers [ key ] . valueEnd . pos ) ; } } newJson = ',' + eol + space + space + '"' + extensionName + '"' ; if ( insert < 0 ) { insert = pointers [ '/extensionsUsed' ] . value . pos + 1 ; newJson = newJson . substring ( 1 ) ; } } else { for ( let key of Object . keys ( pointers ) ) { if ( key . length > 2 ) { insert = Math . max ( insert , pointers [ key ] . valueEnd . pos ) ; } } newJson = ',' + eol + space + '"extensionsUsed": [' + eol + space + space + '"' + extensionName + '"' + eol + space + ']' ; } edit . insert ( document . positionAt ( insert ) , newJson ) ; } }