Skip to content

Commit a91af2e

Browse files
Merge pull request #115 from DustinCampbell/add-tasks-json-automagically
Prompt user to add build task if missing
2 parents 10eb3a8 + cc60974 commit a91af2e

File tree

7 files changed

+413
-95
lines changed

7 files changed

+413
-95
lines changed

package.json

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -104,11 +104,6 @@
104104
"command": "dotnet.restore",
105105
"title": "Restore Packages",
106106
"category": "dotnet"
107-
},
108-
{
109-
"command": "csharp.addTasksJson",
110-
"title": "Add tasks.json (if missing)",
111-
"category": "Debugger"
112107
}
113108
],
114109
"keybindings": [

src/features/commands.ts

Lines changed: 1 addition & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,8 @@ export default function registerCommands(server: OmnisharpServer, extensionPath:
2323
let d5 = vscode.commands.registerCommand('o.execute-last-command', () => dnxExecuteLastCommand(server));
2424
let d6 = vscode.commands.registerCommand('o.showOutput', () => server.getChannel().show(vscode.ViewColumn.Three));
2525
let d7 = vscode.commands.registerCommand('dotnet.restore', () => dotnetRestore(server));
26-
let d8 = vscode.commands.registerCommand('csharp.addTasksJson', () => addTasksJson(server, extensionPath));
2726

28-
return vscode.Disposable.from(d1, d2, d3, d4, d5, d6, d7, d8);
27+
return vscode.Disposable.from(d1, d2, d3, d4, d5, d6, d7);
2928
}
3029

3130
function pickProjectAndStart(server: OmnisharpServer) {
@@ -198,57 +197,4 @@ function getFolderPath(fileOrFolderPath: string): Promise<string> {
198197
? path.dirname(fileOrFolderPath)
199198
: fileOrFolderPath;
200199
});
201-
}
202-
203-
function getExpectedVsCodeFolderPath(solutionPathOrFolder: string): Promise<string> {
204-
return getFolderPath(solutionPathOrFolder).then(folder =>
205-
path.join(folder, '.vscode'));
206-
}
207-
208-
export function addTasksJson(server: OmnisharpServer, extensionPath: string) {
209-
return new Promise<string>((resolve, reject) => {
210-
if (!server.isRunning()) {
211-
return reject('OmniSharp is not running.');
212-
}
213-
214-
let solutionPathOrFolder = server.getSolutionPathOrFolder();
215-
if (!solutionPathOrFolder)
216-
{
217-
return reject('No solution or folder open.');
218-
}
219-
220-
return getExpectedVsCodeFolderPath(solutionPathOrFolder).then(vscodeFolder => {
221-
let tasksJsonPath = path.join(vscodeFolder, 'tasks.json');
222-
223-
return fs.existsAsync(tasksJsonPath).then(e => {
224-
if (e) {
225-
return vscode.window.showInformationMessage(`${tasksJsonPath} already exists.`).then(_ => {
226-
return resolve(tasksJsonPath);
227-
});
228-
}
229-
else {
230-
let templatePath = path.join(extensionPath, 'template-tasks.json');
231-
232-
return fs.existsAsync(templatePath).then(e => {
233-
if (!e) {
234-
return reject('Could not find template-tasks.json file in extension.');
235-
}
236-
237-
return fs.ensureDirAsync(vscodeFolder).then(ok => {
238-
if (ok) {
239-
let oldFile = fs.createReadStream(templatePath);
240-
let newFile = fs.createWriteStream(tasksJsonPath);
241-
oldFile.pipe(newFile);
242-
243-
return resolve(tasksJsonPath);
244-
}
245-
else {
246-
return reject(`Could not create ${vscodeFolder} directory.`);
247-
}
248-
});
249-
});
250-
}
251-
});
252-
});
253-
});
254200
}

src/omnisharpMain.ts

Lines changed: 25 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,45 +22,46 @@ import registerCommands from './features/commands';
2222
import {StdioOmnisharpServer} from './omnisharpServer';
2323
import forwardChanges from './features/changeForwarding';
2424
import reportStatus from './features/omnisharpStatus';
25-
import {Disposable, ExtensionContext, DocumentSelector, languages} from 'vscode';
2625
import {installCoreClrDebug} from './coreclr-debug';
26+
import {promptToAddBuildTaskIfNecessary} from './tasks';
27+
import * as vscode from 'vscode';
2728

28-
export function activate(context: ExtensionContext): any {
29+
export function activate(context: vscode.ExtensionContext): any {
2930

30-
const _selector: DocumentSelector = {
31+
const _selector: vscode.DocumentSelector = {
3132
language: 'csharp',
3233
scheme: 'file' // only files from disk
3334
};
3435

3536
const server = new StdioOmnisharpServer();
3637
const advisor = new Advisor(server); // create before server is started
37-
const disposables: Disposable[] = [];
38-
const localDisposables: Disposable[] = [];
38+
const disposables: vscode.Disposable[] = [];
39+
const localDisposables: vscode.Disposable[] = [];
3940

4041
disposables.push(server.onServerStart(() => {
4142
// register language feature provider on start
42-
localDisposables.push(languages.registerDefinitionProvider(_selector, new DefinitionProvider(server)));
43-
localDisposables.push(languages.registerCodeLensProvider(_selector, new CodeLensProvider(server)));
44-
localDisposables.push(languages.registerDocumentHighlightProvider(_selector, new DocumentHighlightProvider(server)));
45-
localDisposables.push(languages.registerDocumentSymbolProvider(_selector, new DocumentSymbolProvider(server)));
46-
localDisposables.push(languages.registerReferenceProvider(_selector, new ReferenceProvider(server)));
47-
localDisposables.push(languages.registerHoverProvider(_selector, new HoverProvider(server)));
48-
localDisposables.push(languages.registerRenameProvider(_selector, new RenameProvider(server)));
49-
localDisposables.push(languages.registerDocumentRangeFormattingEditProvider(_selector, new FormatProvider(server)));
50-
localDisposables.push(languages.registerOnTypeFormattingEditProvider(_selector, new FormatProvider(server), '}', ';'));
51-
localDisposables.push(languages.registerCompletionItemProvider(_selector, new CompletionItemProvider(server), '.', '<'));
52-
localDisposables.push(languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(server)));
53-
localDisposables.push(languages.registerSignatureHelpProvider(_selector, new SignatureHelpProvider(server), '(', ','));
43+
localDisposables.push(vscode.languages.registerDefinitionProvider(_selector, new DefinitionProvider(server)));
44+
localDisposables.push(vscode.languages.registerCodeLensProvider(_selector, new CodeLensProvider(server)));
45+
localDisposables.push(vscode.languages.registerDocumentHighlightProvider(_selector, new DocumentHighlightProvider(server)));
46+
localDisposables.push(vscode.languages.registerDocumentSymbolProvider(_selector, new DocumentSymbolProvider(server)));
47+
localDisposables.push(vscode.languages.registerReferenceProvider(_selector, new ReferenceProvider(server)));
48+
localDisposables.push(vscode.languages.registerHoverProvider(_selector, new HoverProvider(server)));
49+
localDisposables.push(vscode.languages.registerRenameProvider(_selector, new RenameProvider(server)));
50+
localDisposables.push(vscode.languages.registerDocumentRangeFormattingEditProvider(_selector, new FormatProvider(server)));
51+
localDisposables.push(vscode.languages.registerOnTypeFormattingEditProvider(_selector, new FormatProvider(server), '}', ';'));
52+
localDisposables.push(vscode.languages.registerCompletionItemProvider(_selector, new CompletionItemProvider(server), '.', '<'));
53+
localDisposables.push(vscode.languages.registerWorkspaceSymbolProvider(new WorkspaceSymbolProvider(server)));
54+
localDisposables.push(vscode.languages.registerSignatureHelpProvider(_selector, new SignatureHelpProvider(server), '(', ','));
5455
const codeActionProvider = new CodeActionProvider(server);
5556
localDisposables.push(codeActionProvider);
56-
localDisposables.push(languages.registerCodeActionsProvider(_selector, codeActionProvider));
57+
localDisposables.push(vscode.languages.registerCodeActionsProvider(_selector, codeActionProvider));
5758
localDisposables.push(reportDiagnostics(server, advisor));
5859
localDisposables.push(forwardChanges(server));
5960
}));
6061

6162
disposables.push(server.onServerStop(() => {
6263
// remove language feature providers on stop
63-
Disposable.from(...localDisposables).dispose();
64+
vscode.Disposable.from(...localDisposables).dispose();
6465
}));
6566

6667
disposables.push(registerCommands(server, context.extensionPath));
@@ -71,14 +72,17 @@ export function activate(context: ExtensionContext): any {
7172
server.autoStart(context.workspaceState.get<string>('lastSolutionPathOrFolder'));
7273

7374
// stop server on deactivate
74-
disposables.push(new Disposable(() => {
75+
disposables.push(new vscode.Disposable(() => {
7576
advisor.dispose();
7677
server.stop();
7778
}));
7879

80+
// Check to see if there is a tasks.json with a "build" task and prompt the user to add it if missing.
81+
promptToAddBuildTaskIfNecessary();
82+
7983
// install coreclr-debug
8084
installCoreClrDebug(context);
81-
85+
8286
context.subscriptions.push(...disposables);
8387
}
8488

src/tasks.ts

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
'use strict';
7+
8+
import * as fs from 'fs-extra-promise';
9+
import * as path from 'path';
10+
import * as vscode from 'vscode';
11+
import * as tasks from 'vscode-tasks';
12+
13+
function promptToAddBuildTask(): Promise<boolean> {
14+
return new Promise<boolean>((resolve, reject) => {
15+
const item = { title: 'Yes' }
16+
17+
vscode.window.showInformationMessage('Would you like to add a build task for your project?', item).then(selection => {
18+
return selection
19+
? resolve(true)
20+
: resolve(false);
21+
});
22+
});
23+
}
24+
25+
function createBuildTaskDescription(): tasks.TaskDescription {
26+
return {
27+
taskName: "build",
28+
args: [],
29+
isBuildCommand: true,
30+
problemMatcher: "$msCompile"
31+
};
32+
}
33+
34+
function createTasksConfiguration(): tasks.TaskConfiguration {
35+
return {
36+
version: "0.1.0",
37+
command: "dotnet",
38+
isShellCommand: true,
39+
args: [],
40+
tasks: [ createBuildTaskDescription() ]
41+
};
42+
}
43+
44+
function writeTasksJson(tasksJsonPath: string, tasksConfig: tasks.TaskConfiguration) {
45+
const tasksJsonText = JSON.stringify(tasksConfig, null, ' ');
46+
fs.writeFileSync(tasksJsonPath, tasksJsonText);
47+
}
48+
49+
export function promptToAddBuildTaskIfNecessary() {
50+
if (!vscode.workspace.rootPath) {
51+
return;
52+
}
53+
54+
// If there is no project.json, we won't bother to prompt the user for tasks.json.
55+
const projectJsonPath = path.join(vscode.workspace.rootPath, 'project.json');
56+
if (!fs.existsSync(projectJsonPath)) {
57+
return;
58+
}
59+
60+
const vscodeFolder = path.join(vscode.workspace.rootPath, '.vscode');
61+
const tasksJsonPath = path.join(vscodeFolder, 'tasks.json');
62+
63+
fs.ensureDirAsync(vscodeFolder).then(() => {
64+
fs.existsAsync(tasksJsonPath).then(exists => {
65+
if (exists) {
66+
fs.readFileAsync(tasksJsonPath).then(text => {
67+
const fileText = text.toString();
68+
let tasksConfig: tasks.TaskConfiguration = JSON.parse(fileText);
69+
let buildTask = tasksConfig.tasks.find(td => td.taskName === 'build');
70+
if (!buildTask) {
71+
promptToAddBuildTask().then(shouldAdd => {
72+
if (shouldAdd) {
73+
buildTask = createBuildTaskDescription();
74+
tasksConfig.tasks.push(buildTask);
75+
writeTasksJson(tasksJsonPath, tasksConfig);
76+
}
77+
});
78+
}
79+
});
80+
}
81+
else {
82+
promptToAddBuildTask().then(shouldAdd => {
83+
if (shouldAdd) {
84+
const tasksConfig = createTasksConfiguration();
85+
writeTasksJson(tasksJsonPath, tasksConfig);
86+
}
87+
});
88+
}
89+
});
90+
});
91+
}

src/typings/vscode-extension-telemetry.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
16
declare module 'vscode-extension-telemetry' {
27
export default class TelemetryReporter {
38
constructor(extensionId: string,extensionVersion: string, key: string);

0 commit comments

Comments
 (0)