@@ -44,7 +44,7 @@ import Constants from 'vs/workbench/contrib/markers/browser/constants';
4444import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService' ;
4545import { IEditorService } from 'vs/workbench/services/editor/common/editorService' ;
4646import { IConfigurationResolverService } from 'vs/workbench/services/configurationResolver/common/configurationResolver' ;
47- import { IWorkspaceContextService , WorkbenchState , IWorkspaceFolder } from 'vs/platform/workspace/common/workspace' ;
47+ import { IWorkspaceContextService , WorkbenchState , IWorkspaceFolder , IWorkspace } from 'vs/platform/workspace/common/workspace' ;
4848
4949import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles' ;
5050import { IOutputService , IOutputChannel } from 'vs/workbench/contrib/output/common/output' ;
@@ -178,6 +178,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
178178 private _schemaVersion : JsonSchemaVersion | undefined ;
179179 private _executionEngine : ExecutionEngine | undefined ;
180180 private _workspaceFolders : IWorkspaceFolder [ ] | undefined ;
181+ private _workspace : IWorkspace | undefined ;
181182 private _ignoredWorkspaceFolders : IWorkspaceFolder [ ] | undefined ;
182183 private _showIgnoreMessage ?: boolean ;
183184 private _providers : Map < number , ITaskProvider > ;
@@ -425,7 +426,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
425426 return this . _showIgnoreMessage ;
426427 }
427428
428- private updateSetup ( setup ?: [ IWorkspaceFolder [ ] , IWorkspaceFolder [ ] , ExecutionEngine , JsonSchemaVersion ] ) : void {
429+ private updateSetup ( setup ?: [ IWorkspaceFolder [ ] , IWorkspaceFolder [ ] , ExecutionEngine , JsonSchemaVersion , IWorkspace | undefined ] ) : void {
429430 if ( ! setup ) {
430431 setup = this . computeWorkspaceFolderSetup ( ) ;
431432 }
@@ -447,6 +448,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
447448 this . _ignoredWorkspaceFolders = setup [ 1 ] ;
448449 this . _executionEngine = setup [ 2 ] ;
449450 this . _schemaVersion = setup [ 3 ] ;
451+ this . _workspace = setup [ 4 ] ;
450452 }
451453
452454 protected showOutput ( runSource : TaskRunSource = TaskRunSource . User ) : void {
@@ -1402,13 +1404,21 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
14021404 for ( let folder of this . workspaceFolders ) {
14031405 promises . push ( this . computeWorkspaceFolderTasks ( folder , runSource ) . then ( ( value ) => value , ( ) => undefined ) ) ;
14041406 }
1405- return Promise . all ( promises ) . then ( ( values ) => {
1407+ return Promise . all ( promises ) . then ( async ( values ) => {
14061408 let result = new Map < string , WorkspaceFolderTaskResult > ( ) ;
14071409 for ( let value of values ) {
14081410 if ( value ) {
14091411 result . set ( value . workspaceFolder . uri . toString ( ) , value ) ;
14101412 }
14111413 }
1414+ const userTasks = await this . computeUserTasks ( this . workspaceFolders [ 0 ] , runSource ) . then ( ( value ) => value , ( ) => undefined ) ;
1415+ if ( userTasks ) {
1416+ result . set ( 'settings' , userTasks ) ;
1417+ }
1418+ const workspaceFileTasks = await this . computeWorkspaceFileTasks ( this . workspaceFolders [ 0 ] , runSource ) . then ( ( value ) => value , ( ) => undefined ) ;
1419+ if ( workspaceFileTasks && this . _workspace && this . _workspace . configuration ) {
1420+ result . set ( this . _workspace . configuration . toString ( ) , workspaceFileTasks ) ;
1421+ }
14121422 return result ;
14131423 } ) ;
14141424 }
@@ -1429,7 +1439,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
14291439 return ProblemMatcherRegistry . onReady ( ) . then ( async ( ) : Promise < WorkspaceFolderTaskResult > => {
14301440 let taskSystemInfo : TaskSystemInfo | undefined = this . _taskSystemInfos . get ( workspaceFolder . uri . scheme ) ;
14311441 let problemReporter = new ProblemReporter ( this . _outputChannel ) ;
1432- let parseResult = TaskConfig . parse ( workspaceFolder , taskSystemInfo ? taskSystemInfo . platform : Platform . platform , workspaceFolderConfiguration . config ! , problemReporter ) ;
1442+ let parseResult = TaskConfig . parse ( workspaceFolder , this . _workspace , taskSystemInfo ? taskSystemInfo . platform : Platform . platform , workspaceFolderConfiguration . config ! , problemReporter , TaskConfig . TaskConfigSource . TasksJson ) ;
14331443 let hasErrors = false ;
14341444 if ( ! parseResult . validationStatus . isOK ( ) ) {
14351445 hasErrors = true ;
@@ -1456,25 +1466,121 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
14561466 } ) ;
14571467 }
14581468
1469+ private testParseExternalConfig ( config : TaskConfig . ExternalTaskRunnerConfiguration | undefined , location : string ) : { config : TaskConfig . ExternalTaskRunnerConfiguration | undefined , hasParseErrors : boolean } {
1470+ if ( ! config ) {
1471+ return { config : undefined , hasParseErrors : false } ;
1472+ }
1473+ let parseErrors : string [ ] = ( config as any ) . $parseErrors ;
1474+ if ( parseErrors ) {
1475+ let isAffected = false ;
1476+ for ( const parseError of parseErrors ) {
1477+ if ( / t a s k s \. j s o n $ / . test ( parseError ) ) {
1478+ isAffected = true ;
1479+ break ;
1480+ }
1481+ }
1482+ if ( isAffected ) {
1483+ this . _outputChannel . append ( nls . localize ( 'TaskSystem.invalidTaskJsonOther' , 'Error: The content of the tasks json in {0} has syntax errors. Please correct them before executing a task.\n' , location ) ) ;
1484+ this . showOutput ( ) ;
1485+ return { config, hasParseErrors : true } ;
1486+ }
1487+ }
1488+ return { config, hasParseErrors : false } ;
1489+ }
1490+
1491+ private async computeWorkspaceFileTasks ( workspaceFolder : IWorkspaceFolder , runSource : TaskRunSource = TaskRunSource . User ) : Promise < WorkspaceFolderTaskResult > {
1492+ if ( this . executionEngine === ExecutionEngine . Process ) {
1493+ return this . emptyWorkspaceTaskResults ( workspaceFolder ) ;
1494+ }
1495+ const configuration = this . testParseExternalConfig ( this . configurationService . inspect < TaskConfig . ExternalTaskRunnerConfiguration > ( 'tasks' ) . workspace , nls . localize ( 'TasksSystem.locationWorkspaceConfig' , 'workspace file' ) ) ;
1496+ let customizedTasks : { byIdentifier : IStringDictionary < ConfiguringTask > ; } = {
1497+ byIdentifier : Object . create ( null )
1498+ } ;
1499+
1500+ const custom : CustomTask [ ] = [ ] ;
1501+ await this . computeTasksForSingleConfig ( workspaceFolder , configuration . config , runSource , custom , customizedTasks . byIdentifier , TaskConfig . TaskConfigSource . WorkspaceFile ) ;
1502+ const engine = configuration . config ? TaskConfig . ExecutionEngine . from ( configuration . config ) : ExecutionEngine . Terminal ;
1503+ if ( engine === ExecutionEngine . Process ) {
1504+ this . notificationService . warn ( nls . localize ( 'TaskSystem.versionWorkspaceFile' , 'Only tasks version 2.0.0 permitted in .codeworkspace.' ) ) ;
1505+ return this . emptyWorkspaceTaskResults ( workspaceFolder ) ;
1506+ }
1507+ return { workspaceFolder, set : { tasks : custom } , configurations : customizedTasks , hasErrors : configuration . hasParseErrors } ;
1508+ }
1509+
1510+ private async computeUserTasks ( workspaceFolder : IWorkspaceFolder , runSource : TaskRunSource = TaskRunSource . User ) : Promise < WorkspaceFolderTaskResult > {
1511+ if ( this . executionEngine === ExecutionEngine . Process ) {
1512+ return this . emptyWorkspaceTaskResults ( workspaceFolder ) ;
1513+ }
1514+ const configuration = this . testParseExternalConfig ( this . configurationService . inspect < TaskConfig . ExternalTaskRunnerConfiguration > ( 'tasks' ) . user , nls . localize ( 'TasksSystem.locationUserConfig' , 'user settings' ) ) ;
1515+ let customizedTasks : { byIdentifier : IStringDictionary < ConfiguringTask > ; } = {
1516+ byIdentifier : Object . create ( null )
1517+ } ;
1518+
1519+ const custom : CustomTask [ ] = [ ] ;
1520+ await this . computeTasksForSingleConfig ( workspaceFolder , configuration . config , runSource , custom , customizedTasks . byIdentifier , TaskConfig . TaskConfigSource . User ) ;
1521+ const engine = configuration . config ? TaskConfig . ExecutionEngine . from ( configuration . config ) : ExecutionEngine . Terminal ;
1522+ if ( engine === ExecutionEngine . Process ) {
1523+ this . notificationService . warn ( nls . localize ( 'TaskSystem.versionSettings' , 'Only tasks version 2.0.0 permitted in user settings.' ) ) ;
1524+ return this . emptyWorkspaceTaskResults ( workspaceFolder ) ;
1525+ }
1526+ return { workspaceFolder, set : { tasks : custom } , configurations : customizedTasks , hasErrors : configuration . hasParseErrors } ;
1527+ }
1528+
1529+ private emptyWorkspaceTaskResults ( workspaceFolder : IWorkspaceFolder ) : WorkspaceFolderTaskResult {
1530+ return { workspaceFolder, set : undefined , configurations : undefined , hasErrors : false } ;
1531+ }
1532+
1533+ private async computeTasksForSingleConfig ( workspaceFolder : IWorkspaceFolder , config : TaskConfig . ExternalTaskRunnerConfiguration | undefined , runSource : TaskRunSource , custom : CustomTask [ ] , customized : IStringDictionary < ConfiguringTask > , source : TaskConfig . TaskConfigSource ) : Promise < boolean > {
1534+ if ( ! config ) {
1535+ return false ;
1536+ }
1537+ let taskSystemInfo : TaskSystemInfo | undefined = workspaceFolder ? this . _taskSystemInfos . get ( workspaceFolder . uri . scheme ) : undefined ;
1538+ let problemReporter = new ProblemReporter ( this . _outputChannel ) ;
1539+ let parseResult = TaskConfig . parse ( workspaceFolder , this . _workspace , taskSystemInfo ? taskSystemInfo . platform : Platform . platform , config , problemReporter , source ) ;
1540+ let hasErrors = false ;
1541+ if ( ! parseResult . validationStatus . isOK ( ) ) {
1542+ this . showOutput ( runSource ) ;
1543+ hasErrors = true ;
1544+ }
1545+ if ( problemReporter . status . isFatal ( ) ) {
1546+ problemReporter . fatal ( nls . localize ( 'TaskSystem.configurationErrors' , 'Error: the provided task configuration has validation errors and can\'t not be used. Please correct the errors first.' ) ) ;
1547+ return hasErrors ;
1548+ }
1549+ if ( parseResult . configured && parseResult . configured . length > 0 ) {
1550+ for ( let task of parseResult . configured ) {
1551+ customized [ task . configures . _key ] = task ;
1552+ }
1553+ }
1554+ if ( ! ( await this . _areJsonTasksSupportedPromise ) && ( parseResult . custom . length > 0 ) ) {
1555+ console . warn ( 'Custom workspace tasks are not supported.' ) ;
1556+ } else {
1557+ for ( let task of parseResult . custom ) {
1558+ custom . push ( task ) ;
1559+ }
1560+ }
1561+ return hasErrors ;
1562+ }
1563+
14591564 private computeConfiguration ( workspaceFolder : IWorkspaceFolder ) : Promise < WorkspaceFolderConfigurationResult > {
14601565 let { config, hasParseErrors } = this . getConfiguration ( workspaceFolder ) ;
14611566 return Promise . resolve < WorkspaceFolderConfigurationResult > ( { workspaceFolder, config, hasErrors : hasParseErrors } ) ;
14621567 }
14631568
14641569 protected abstract computeLegacyConfiguration ( workspaceFolder : IWorkspaceFolder ) : Promise < WorkspaceFolderConfigurationResult > ;
14651570
1466- private computeWorkspaceFolderSetup ( ) : [ IWorkspaceFolder [ ] , IWorkspaceFolder [ ] , ExecutionEngine , JsonSchemaVersion ] {
1571+ private computeWorkspaceFolderSetup ( ) : [ IWorkspaceFolder [ ] , IWorkspaceFolder [ ] , ExecutionEngine , JsonSchemaVersion , IWorkspace | undefined ] {
14671572 let workspaceFolders : IWorkspaceFolder [ ] = [ ] ;
14681573 let ignoredWorkspaceFolders : IWorkspaceFolder [ ] = [ ] ;
14691574 let executionEngine = ExecutionEngine . Terminal ;
14701575 let schemaVersion = JsonSchemaVersion . V2_0_0 ;
1471-
1576+ let workspace : IWorkspace | undefined ;
14721577 if ( this . contextService . getWorkbenchState ( ) === WorkbenchState . FOLDER ) {
14731578 let workspaceFolder : IWorkspaceFolder = this . contextService . getWorkspace ( ) . folders [ 0 ] ;
14741579 workspaceFolders . push ( workspaceFolder ) ;
14751580 executionEngine = this . computeExecutionEngine ( workspaceFolder ) ;
14761581 schemaVersion = this . computeJsonSchemaVersion ( workspaceFolder ) ;
14771582 } else if ( this . contextService . getWorkbenchState ( ) === WorkbenchState . WORKSPACE ) {
1583+ workspace = this . contextService . getWorkspace ( ) ;
14781584 for ( let workspaceFolder of this . contextService . getWorkspace ( ) . folders ) {
14791585 if ( schemaVersion === this . computeJsonSchemaVersion ( workspaceFolder ) ) {
14801586 workspaceFolders . push ( workspaceFolder ) ;
@@ -1487,7 +1593,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
14871593 }
14881594 }
14891595 }
1490- return [ workspaceFolders , ignoredWorkspaceFolders , executionEngine , schemaVersion ] ;
1596+ return [ workspaceFolders , ignoredWorkspaceFolders , executionEngine , schemaVersion , workspace ] ;
14911597 }
14921598
14931599 private computeExecutionEngine ( workspaceFolder : IWorkspaceFolder ) : ExecutionEngine {
@@ -1508,7 +1614,7 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
15081614
15091615 protected getConfiguration ( workspaceFolder : IWorkspaceFolder ) : { config : TaskConfig . ExternalTaskRunnerConfiguration | undefined ; hasParseErrors : boolean } {
15101616 let result = this . contextService . getWorkbenchState ( ) !== WorkbenchState . EMPTY
1511- ? Objects . deepClone ( this . configurationService . getValue < TaskConfig . ExternalTaskRunnerConfiguration > ( 'tasks' , { resource : workspaceFolder . uri } ) )
1617+ ? Objects . deepClone ( this . configurationService . inspect < TaskConfig . ExternalTaskRunnerConfiguration > ( 'tasks' , { resource : workspaceFolder . uri } ) . workspaceFolder )
15121618 : undefined ;
15131619 if ( ! result ) {
15141620 return { config : undefined , hasParseErrors : false } ;
@@ -1660,7 +1766,11 @@ export abstract class AbstractTaskService extends Disposable implements ITaskSer
16601766 }
16611767 const TaskQuickPickEntry = ( task : Task ) : TaskQuickPickEntry => {
16621768 let description : string | undefined ;
1663- if ( this . needsFolderQualification ( ) ) {
1769+ if ( task . _source . kind === TaskSourceKind . User ) {
1770+ description = nls . localize ( 'taskQuickPick.userSettings' , 'User Settings' ) ;
1771+ } else if ( task . _source . kind === TaskSourceKind . WorkspaceFile ) {
1772+ description = task . getWorkspaceFileName ( ) ;
1773+ } else if ( this . needsFolderQualification ( ) ) {
16641774 let workspaceFolder = task . getWorkspaceFolder ( ) ;
16651775 if ( workspaceFolder ) {
16661776 description = workspaceFolder . name ;
0 commit comments