@@ -94,63 +94,67 @@ export class ConfigurationResolverService implements IConfigurationResolverServi
9494 return this . resolver . resolveAny ( root ? root . uri : undefined , value ) ;
9595 }
9696
97- public resolveAny ( root : IWorkspaceFolder , value : any ) : any {
98- return this . resolver . resolveAny ( root ? root . uri : undefined , value ) ;
97+ public resolveAny ( root : IWorkspaceFolder , value : any , commandValueMapping ?: IStringDictionary < string > ) : any {
98+ return this . resolver . resolveAny ( root ? root . uri : undefined , value , commandValueMapping ) ;
9999 }
100100
101101 /**
102- * Resolve all interactive variables in configuration #6569
102+ * Finds and executes all command variables (see #6569)
103103 */
104- public resolveInteractiveVariables ( configuration : any , interactiveVariablesMap : { [ key : string ] : string } ) : TPromise < any > {
104+ public executeCommandVariables ( configuration : any , variableToCommandMap : IStringDictionary < string > ) : TPromise < IStringDictionary < string > > {
105+
105106 if ( ! configuration ) {
106107 return TPromise . as ( null ) ;
107108 }
108109
109- // We need a map from interactive variables to keys because we only want to trigger an command once per key -
110- // even though it might occur multiple times in configuration #7026.
111- const interactiveVariablesToSubstitutes : { [ interactiveVariable : string ] : { object : any , key : string } [ ] } = Object . create ( null ) ;
112- const findInteractiveVariables = ( object : any ) => {
110+ // use an array to preserve order of first appearance
111+ const commands : string [ ] = [ ] ;
112+
113+ const cmd_var = / \$ { command:( .* ?) } / g;
114+
115+ const findCommandVariables = ( object : any ) => {
113116 Object . keys ( object ) . forEach ( key => {
114- if ( object [ key ] && typeof object [ key ] === 'object' ) {
115- findInteractiveVariables ( object [ key ] ) ;
116- } else if ( typeof object [ key ] === 'string' ) {
117- const matches = / \$ { command:( .* ?) } / . exec ( object [ key ] ) ;
118- if ( matches && matches . length === 2 ) {
119- const interactiveVariable = matches [ 1 ] ;
120- if ( ! interactiveVariablesToSubstitutes [ interactiveVariable ] ) {
121- interactiveVariablesToSubstitutes [ interactiveVariable ] = [ ] ;
117+ const value = object [ key ] ;
118+ if ( value && typeof value === 'object' ) {
119+ findCommandVariables ( value ) ;
120+ } else if ( typeof value === 'string' ) {
121+ let matches ;
122+ while ( ( matches = cmd_var . exec ( value ) ) !== null ) {
123+ if ( matches . length === 2 ) {
124+ const command = matches [ 1 ] ;
125+ if ( commands . indexOf ( command ) < 0 ) {
126+ commands . push ( command ) ;
127+ }
122128 }
123- interactiveVariablesToSubstitutes [ interactiveVariable ] . push ( { object, key } ) ;
124129 }
125130 }
126131 } ) ;
127132 } ;
128- findInteractiveVariables ( configuration ) ;
129- let substitionCanceled = false ;
130133
131- const factory : { ( ) : TPromise < any > } [ ] = Object . keys ( interactiveVariablesToSubstitutes ) . map ( interactiveVariable => {
134+ findCommandVariables ( configuration ) ;
135+
136+ let cancelled = false ;
137+ const commandValueMapping : IStringDictionary < string > = Object . create ( null ) ;
138+
139+ const factory : { ( ) : TPromise < any > } [ ] = commands . map ( interactiveVariable => {
132140 return ( ) => {
133- let commandId : string = null ;
134- commandId = interactiveVariablesMap ? interactiveVariablesMap [ interactiveVariable ] : null ;
141+
142+ let commandId = variableToCommandMap ? variableToCommandMap [ interactiveVariable ] : null ;
135143 if ( ! commandId ) {
136144 // Just launch any command if the interactive variable is not contributed by the adapter #12735
137145 commandId = interactiveVariable ;
138146 }
139147
140148 return this . commandService . executeCommand < string > ( commandId , configuration ) . then ( result => {
141149 if ( result ) {
142- interactiveVariablesToSubstitutes [ interactiveVariable ] . forEach ( substitute => {
143- if ( substitute . object [ substitute . key ] . indexOf ( `\${command:${ interactiveVariable } }` ) >= 0 ) {
144- substitute . object [ substitute . key ] = substitute . object [ substitute . key ] . replace ( `\${command:${ interactiveVariable } }` , result ) ;
145- }
146- } ) ;
150+ commandValueMapping [ interactiveVariable ] = result ;
147151 } else {
148- substitionCanceled = true ;
152+ cancelled = true ;
149153 }
150154 } ) ;
151155 } ;
152156 } ) ;
153157
154- return sequence ( factory ) . then ( ( ) => substitionCanceled ? null : configuration ) ;
158+ return sequence ( factory ) . then ( ( ) => cancelled ? null : commandValueMapping ) ;
155159 }
156160}
0 commit comments