diff --git a/extensions/tasks/package.json b/extensions/tasks/package.json new file mode 100644 index 00000000000..d19603aadad --- /dev/null +++ b/extensions/tasks/package.json @@ -0,0 +1,21 @@ +{ + "name": "tasks", + "description": "Extension to add support for tasks.json files", + "displayName": "Tasks.json support for VSCode", + "version": "0.10.1", + "author": "Microsoft Corporation", + "license": "MIT", + "publisher": "vscode", + "engines": { + "vscode": "*" + }, + "scripts": { + "vscode:prepublish": "node ../../node_modules/gulp/bin/gulp.js --gulpfile ../../gulpfile.plugins.js compile-plugin:tasks ./src/tsconfig.json" + }, + "activationEvents": [ + "onLanguage:json" + ], + "main": "./out/tasksMain", + "contributes": { + } +} \ No newline at end of file diff --git a/extensions/tasks/src/tasksMain.ts b/extensions/tasks/src/tasksMain.ts new file mode 100644 index 00000000000..d011264653b --- /dev/null +++ b/extensions/tasks/src/tasksMain.ts @@ -0,0 +1,101 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ +'use strict'; + +import * as path from 'path'; + +import { languages, workspace, ExtensionContext, TextDocument, Position, CancellationToken, CompletionItem, CompletionItemKind, DocumentFilter } from 'vscode'; + +export function activate(context: ExtensionContext): void { + // We can't use a pattern here since it disables the normal json code complete + // which we don't want. Do the filtering in the actual suggest + let selector: DocumentFilter = { language: 'json' }; + let taskFileName = workspace.rootPath ? path.join(workspace.rootPath, '.vscode/tasks.json') : null; + let items = taskFileName ? createCompletionItems() : []; + + languages.registerCompletionItemProvider(selector, { + provideCompletionItems: (document: TextDocument, position: Position, token: CancellationToken): CompletionItem[] => { + if (document.fileName === taskFileName) { + return items; + } else { + return []; + } + } + }); +} + +function createCompletionItems(): CompletionItem[] { + let result: CompletionItem[] = []; + let item: CompletionItem; + + item = new CompletionItem('tsc'); + item.kind = CompletionItemKind.Snippet; + item.detail = 'Use the tsc compiler on a specific file.'; + item.filterText = 'ts-tsc'; + item.insertText = [ + '"version": "0.1.0",', + '"command": "tsc",', + '"isShellCommand": true,', + '"showOutput": "silent",', + '"args": ["HelloWorld.ts"],', + '"problemMatcher": "$tsc"' + ].join('\n'); + result.push(item); + + item = new CompletionItem('tsc - tsconfig.json'); + item.kind = CompletionItemKind.Snippet; + item.detail = 'Use the tsc compiler with a tsconfig.json file.'; + item.filterText = 'ts-tsc - tsconfig.json'; + item.insertText = [ + '"version": "0.1.0",', + '"command": "tsc",', + '"isShellCommand": true,', + '"showOutput": "silent",', + '"args": ["-p", "."],', + '"problemMatcher": "$tsc"' + ].join('\n'); + result.push(item); + + item = new CompletionItem('tsc - watch'); + item.kind = CompletionItemKind.Snippet; + item.detail = 'Use the tsc compiler in watch mode.'; + item.filterText = 'ts-tsc - watch'; + item.insertText = [ + '"version": "0.1.0",', + '"command": "tsc",', + '"isShellCommand": true,', + '"showOutput": "silent",', + '"args": ["-w", "-p", "."],', + '"problemMatcher": "$tsc-watch"' + ].join('\n'); + result.push(item); + + item = new CompletionItem('msbuild'); + item.kind = CompletionItemKind.Snippet; + item.detail = 'Use msbuild to compile your project.'; + item.filterText = 'ts-msbuild'; + item.insertText = [ + '"version": "0.1.0",', + '"command": "msbuild",', + '"args": [', + '\t// Ask msbuild to generate full paths for file names.', + '\t"/property:GenerateFullPaths=true"', + '],', + '"taskSelector": "/t:",', + '"showOutput": "silent",', + '"tasks": [', + '\t{', + '\t\t"taskName": "build",', + '\t\t// Show the output window only if unrecognized errors occur.', + '\t\t"showOutput": "silent",', + '\t\t// Use the standard MS compiler pattern to detect errors, warnings and infos', + '\t\t"problemMatcher": "$msCompile"', + '\t}', + ']' + ].join('\n'); + result.push(item); + + return result; +} \ No newline at end of file diff --git a/extensions/tasks/src/tsconfig.json b/extensions/tasks/src/tsconfig.json new file mode 100644 index 00000000000..e51744d35f4 --- /dev/null +++ b/extensions/tasks/src/tsconfig.json @@ -0,0 +1,9 @@ +{ + "compilerOptions": { + "module": "commonjs", + "target": "es5", + "noLib": true, + "sourceMap": true, + "outDir": "../out" + } +} \ No newline at end of file diff --git a/extensions/tasks/src/typings/node.additions.d.ts b/extensions/tasks/src/typings/node.additions.d.ts new file mode 100644 index 00000000000..3ae7322bc8a --- /dev/null +++ b/extensions/tasks/src/typings/node.additions.d.ts @@ -0,0 +1,28 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +declare function setTimeout(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; +declare function clearTimeout(timeoutId: NodeJS.Timer): void; +declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; +declare function clearInterval(intervalId: NodeJS.Timer): void; +declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; +declare function clearImmediate(immediateId: any): void; + +interface Console { + assert(test?: boolean, message?: string, ...optionalParams: any[]): void; + dir(value?: any, ...optionalParams: any[]): void; + error(message?: any, ...optionalParams: any[]): void; + info(message?: any, ...optionalParams: any[]): void; + log(message?: any, ...optionalParams: any[]): void; + time(timerName?: string): void; + timeEnd(timerName?: string): void; + trace(message?: any, ...optionalParams: any[]): void; + warn(message?: any, ...optionalParams: any[]): void; +} + +declare var Console: { + prototype: Console; + new(): Console; +}; \ No newline at end of file diff --git a/extensions/tasks/src/typings/refs.d.ts b/extensions/tasks/src/typings/refs.d.ts new file mode 100644 index 00000000000..6b027cbfa31 --- /dev/null +++ b/extensions/tasks/src/typings/refs.d.ts @@ -0,0 +1,9 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +/// +/// +/// +/// \ No newline at end of file diff --git a/extensions/typescript/src/typescriptServiceClient.ts b/extensions/typescript/src/typescriptServiceClient.ts index 05303aee4cd..40512e7900e 100644 --- a/extensions/typescript/src/typescriptServiceClient.ts +++ b/extensions/typescript/src/typescriptServiceClient.ts @@ -184,7 +184,7 @@ export default class TypeScriptServiceClient implements ITypescriptServiceClient return unknown; } let contents = fs.readFileSync(fileName).toString(); - let desc = null; + let desc:any = null; try { desc = JSON.parse(contents); } catch(err) { diff --git a/extensions/typescript/src/typings/node.additions.d.ts b/extensions/typescript/src/typings/node.additions.d.ts index 0dccea79121..3ae7322bc8a 100644 --- a/extensions/typescript/src/typings/node.additions.d.ts +++ b/extensions/typescript/src/typings/node.additions.d.ts @@ -8,4 +8,21 @@ declare function clearTimeout(timeoutId: NodeJS.Timer): void; declare function setInterval(callback: (...args: any[]) => void, ms: number, ...args: any[]): NodeJS.Timer; declare function clearInterval(intervalId: NodeJS.Timer): void; declare function setImmediate(callback: (...args: any[]) => void, ...args: any[]): any; -declare function clearImmediate(immediateId: any): void; \ No newline at end of file +declare function clearImmediate(immediateId: any): void; + +interface Console { + assert(test?: boolean, message?: string, ...optionalParams: any[]): void; + dir(value?: any, ...optionalParams: any[]): void; + error(message?: any, ...optionalParams: any[]): void; + info(message?: any, ...optionalParams: any[]): void; + log(message?: any, ...optionalParams: any[]): void; + time(timerName?: string): void; + timeEnd(timerName?: string): void; + trace(message?: any, ...optionalParams: any[]): void; + warn(message?: any, ...optionalParams: any[]): void; +} + +declare var Console: { + prototype: Console; + new(): Console; +}; \ No newline at end of file diff --git a/src/vs/workbench/parts/tasks/common/taskSampleConfig.json b/src/vs/workbench/parts/tasks/common/taskSampleConfig.json index 1f312158d75..19c92397b15 100644 --- a/src/vs/workbench/parts/tasks/common/taskSampleConfig.json +++ b/src/vs/workbench/parts/tasks/common/taskSampleConfig.json @@ -1,190 +1,6 @@ -// Available variables which can be used inside of strings. -// ${workspaceRoot}: the root folder of the team -// ${file}: the current opened file -// ${fileBasename}: the current opened file's basename -// ${fileDirname}: the current opened file's dirname -// ${fileExtname}: the current opened file's extension -// ${cwd}: the current working directory of the spawned process - -// A task runner that calls the Typescript compiler (tsc) and -// Compiles a HelloWorld.ts program { - "version": "0.1.0", - - // The command is tsc. Assumes that tsc has been installed using npm install -g typescript - "command": "tsc", - - // The command is a shell script - "isShellCommand": true, - - // Show the output window only if unrecognized errors occur. - "showOutput": "silent", - - // args is the HelloWorld program to compile. - "args": ["HelloWorld.ts"], - - // use the standard tsc problem matcher to find compile problems - // in the output. - "problemMatcher": "$tsc" -} - -// A task runner that calls the Typescript compiler (tsc) and -// compiles based on a tsconfig.json file that is present in -// the root of the folder open in VSCode -/* -{ - "version": "0.1.0", - - // The command is tsc. Assumes that tsc has been installed using npm install -g typescript - "command": "tsc", - - // The command is a shell script - "isShellCommand": true, - - // Show the output window only if unrecognized errors occur. - "showOutput": "silent", - - // Tell the tsc compiler to use the tsconfig.json from the open folder. - "args": ["-p", "."], - - // use the standard tsc problem matcher to find compile problems - // in the output. - "problemMatcher": "$tsc" -} -*/ - -// A task runner configuration for gulp. Gulp provides a less task -// which compiles less to css. -/* -{ - "version": "0.1.0", - "command": "gulp", - "isShellCommand": true, - "tasks": [ - { - "taskName": "less", - // Make this the default build command. - "isBuildCommand": true, - // Show the output window only if unrecognized errors occur. - "showOutput": "silent", - // Use the standard less compilation problem matcher. - "problemMatcher": "$lessCompile" - } - ] -} -*/ - -// Uncomment the following section to use jake to build a workspace -// cloned from https://github.com/Microsoft/TypeScript.git -/* -{ - "version": "0.1.0", - // Task runner is jake - "command": "jake", - // Need to be executed in shell / cmd - "isShellCommand": true, - "showOutput": "silent", - "tasks": [ - { - // TS build command is local. - "taskName": "local", - // Make this the default build command. - "isBuildCommand": true, - // Show the output window only if unrecognized errors occur. - "showOutput": "silent", - // Use the redefined Typescript output problem matcher. - "problemMatcher": [ - "$tsc" - ] - } - ] -} -*/ - -// Uncomment the section below to use msbuild and generate problems -// for csc, cpp, tsc and vb. The configuration assumes that msbuild -// is available on the path and a solution file exists in the -// workspace folder root. -/* -{ - "version": "0.1.0", - "command": "msbuild", - "args": [ - // Ask msbuild to generate full paths for file names. - "/property:GenerateFullPaths=true" - ], - "taskSelector": "/t:", - "showOutput": "silent", - "tasks": [ - { - "taskName": "build", - // Show the output window only if unrecognized errors occur. - "showOutput": "silent", - // Use the standard MS compiler pattern to detect errors, warnings - // and infos in the output. - "problemMatcher": "$msCompile" - } - ] -} -*/ - -// Uncomment the following section to use msbuild which compiles Typescript -// and less files. -/* -{ - "version": "0.1.0", - "command": "msbuild", - "args": [ - // Ask msbuild to generate full paths for file names. - "/property:GenerateFullPaths=true" - ], - "taskSelector": "/t:", - "showOutput": "silent", - "tasks": [ - { - "taskName": "build", - // Show the output window only if unrecognized errors occur. - "showOutput": "silent", - // Use the standard MS compiler pattern to detect errors, warnings - // and infos in the output. - "problemMatcher": [ - "$msCompile", - "$lessCompile" - ] - } - ] -} -*/ -// A task runner example that defines a problemMatcher inline instead of using -// a predefined one. -/* -{ - "version": "0.1.0", - "command": "tsc", - "isShellCommand": true, - "args": ["HelloWorld.ts"], - "showOutput": "silent", - "problemMatcher": { - // The problem is owned by the typescript language service. Ensure that the problems - // are merged with problems produced by Visual Studio's language service. - "owner": "typescript", - // The file name for reported problems is relative to the current working directory. - "fileLocation": ["relative", "${cwd}"], - // The actual pattern to match problems in the output. - "pattern": { - // The regular expression. Matches HelloWorld.ts(2,10): error TS2339: Property 'logg' does not exist on type 'Console'. - "regexp": "^([^\\s].*)\\((\\d+|\\d+,\\d+|\\d+,\\d+,\\d+,\\d+)\\):\\s+(error|warning|info)\\s+(TS\\d+)\\s*:\\s*(.*)$", - // The match group that denotes the file containing the problem. - "file": 1, - // The match group that denotes the problem location. - "location": 2, - // The match group that denotes the problem's severity. Can be omitted. - "severity": 3, - // The match group that denotes the problem code. Can be omitted. - "code": 4, - // The match group that denotes the problem's message. - "message": 5 - } - } -} -*/ \ No newline at end of file + // See http://code.visualstudio.com/docs/editor/tasks + // for the documentation about the tasks.json format + // Use IntelliSense to insert predefined task snippets + ts +} \ No newline at end of file diff --git a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts index baab42c50f2..d81bc16384d 100644 --- a/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts +++ b/src/vs/workbench/parts/tasks/electron-browser/task.contribution.ts @@ -39,10 +39,13 @@ import { IConfigurationService, ConfigurationServiceEventTypes } from 'vs/platfo import { IFileService, FileChangesEvent, FileChangeType, EventType as FileEventType } from 'vs/platform/files/common/files'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IPluginService } from 'vs/platform/plugins/common/plugins'; +import { IKeybindingService } from 'vs/platform/keybinding/common/keybindingService'; import { IModeService } from 'vs/editor/common/services/modeService'; import { IModelService } from 'vs/editor/common/services/modelService'; +import { ICodeEditor } from 'vs/editor/browser/editorBrowser'; + import jsonContributionRegistry = require('vs/platform/jsonschemas/common/jsonContributionRegistry'); import { IJSONSchema } from 'vs/base/common/jsonSchema'; @@ -148,11 +151,12 @@ class ConfigureTaskRunnerAction extends Action { private contextService: IWorkspaceContextService; private outputService: IOutputService; private messageService: IMessageService; + private keybindingService: IKeybindingService constructor(id: string, label: string, @IConfigurationService configurationService: IConfigurationService, @IWorkbenchEditorService editorService: IWorkbenchEditorService, @IFileService fileService: IFileService, @IWorkspaceContextService contextService: IWorkspaceContextService, @IOutputService outputService: IOutputService, - @IMessageService messageService: IMessageService) { + @IMessageService messageService: IMessageService, @IKeybindingService keybindingService: IKeybindingService) { super(id, label); this.configurationService = configurationService; @@ -161,11 +165,13 @@ class ConfigureTaskRunnerAction extends Action { this.contextService = contextService; this.outputService = outputService; this.messageService = messageService; + this.keybindingService = keybindingService; } public run(event?:any): Promise { let sideBySide = !!(event && (event.ctrlKey || event.metaKey)); let autoDetectFailed = false; + let fileCreated = false; return this.fileService.resolveFile(this.contextService.toResource('.vscode/tasks.json')).then((success) => { return success; }, (err:any) => { @@ -198,6 +204,7 @@ class ConfigureTaskRunnerAction extends Action { }); } return contentPromise.then((content) => { + fileCreated = true; return this.fileService.createFile(this.contextService.toResource('.vscode/tasks.json'), content); }); }); @@ -208,9 +215,19 @@ class ConfigureTaskRunnerAction extends Action { options: { forceOpen: true } - }, sideBySide).then((value) => { + }, sideBySide).then((editor) => { + if (fileCreated) { + let codeEditor: ICodeEditor = editor.getControl() as ICodeEditor; + let position = { lineNumber: 5, column: 4 }; + codeEditor.revealPosition(position); + codeEditor.setPosition(position); + // Workaround for: https://github.com/Microsoft/vscode/issues/3121 + setTimeout(() => { + this.keybindingService.executeCommand('editor.action.triggerSuggest'); + }, 300); + } this.outputService.showOutput(TaskService.OutputChannel, true); - return value; + return editor; }); }, (error) => { throw new Error(nls.localize('ConfigureTaskRunnerAction.failed', "Unable to create the 'tasks.json' file inside the '.vscode' folder. Consult the task output for details.")); @@ -453,6 +470,7 @@ class TaskService extends EventEmitter implements ITaskService { private eventService: IEventService; private modelService: IModelService; private pluginService: IPluginService; + private keybindingService: IKeybindingService; private _taskSystemPromise: TPromise; private _taskSystem: ITaskSystem; @@ -467,7 +485,8 @@ class TaskService extends EventEmitter implements ITaskService { @IFileService fileService:IFileService, @IWorkspaceContextService contextService: IWorkspaceContextService, @ITelemetryService telemetryService: ITelemetryService, @ITextFileService textFileService:ITextFileService, @ILifecycleService lifecycleService: ILifecycleService, @IEventService eventService: IEventService, - @IModelService modelService: IModelService, @IPluginService pluginService: IPluginService) { + @IModelService modelService: IModelService, @IPluginService pluginService: IPluginService, + @IKeybindingService keybindingService: IKeybindingService) { super(); this.modeService = modeService; @@ -483,6 +502,7 @@ class TaskService extends EventEmitter implements ITaskService { this.eventService = eventService; this.modelService = modelService; this.pluginService = pluginService; + this.keybindingService = keybindingService; this.taskSystemListeners = []; this.clearTaskSystemPromise = false; @@ -621,7 +641,7 @@ class TaskService extends EventEmitter implements ITaskService { public configureAction(): Action { return new ConfigureTaskRunnerAction(ConfigureTaskRunnerAction.ID, ConfigureTaskRunnerAction.TEXT, this.configurationService, this.editorService, this.fileService, this.contextService, - this.outputService, this.messageService); + this.outputService, this.messageService, this.keybindingService); } public build(): TPromise { @@ -750,7 +770,7 @@ class TaskService extends EventEmitter implements ITaskService { if (needsConfig || needsTerminate) { let closeAction = new CloseMessageAction(); let action = needsConfig - ? new ConfigureTaskRunnerAction(ConfigureTaskRunnerAction.ID, ConfigureTaskRunnerAction.TEXT, this.configurationService, this.editorService, this.fileService, this.contextService, this.outputService, this.messageService) + ? this.configureAction() : new TerminateAction(TerminateAction.ID, TerminateAction.TEXT, this, this.telemetryService); closeAction.closeFunction = this.messageService.show(buildError.severity, { message: buildError.message, actions: [closeAction, action ] });