Skip to content

Commit 9232ed8

Browse files
authored
Cleanup reload dialog and processRuntimeDependencies flow. (#1428)
* Removing reload code and insert wait code Lots of refactoring to improve readability.
1 parent bc721d3 commit 9232ed8

File tree

9 files changed

+448
-460
lines changed

9 files changed

+448
-460
lines changed

Extension/src/Debugger/attachToProcess.ts

Lines changed: 46 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -20,23 +20,25 @@ export class AttachPicker {
2020
constructor(private attachItemsProvider: AttachItemsProvider) { }
2121

2222
public ShowAttachEntries(): Promise<string> {
23-
if (util.getShowReloadPrompt()) {
24-
util.showReloadOrWaitPrompt();
25-
} else {
26-
return this.attachItemsProvider.getAttachItems()
27-
.then(processEntries => {
28-
let attachPickOptions: vscode.QuickPickOptions = {
29-
matchOnDescription: true,
30-
matchOnDetail: true,
31-
placeHolder: "Select the process to attach to"
32-
};
33-
34-
return vscode.window.showQuickPick(processEntries, attachPickOptions)
35-
.then(chosenProcess => {
36-
return chosenProcess ? chosenProcess.id : Promise.reject<string>(new Error("Process not selected."));
37-
});
38-
});
39-
}
23+
return util.isExtensionReady().then(ready => {
24+
if (!ready) {
25+
util.displayExtensionNotReadyPrompt();
26+
} else {
27+
return this.attachItemsProvider.getAttachItems()
28+
.then(processEntries => {
29+
let attachPickOptions: vscode.QuickPickOptions = {
30+
matchOnDescription: true,
31+
matchOnDetail: true,
32+
placeHolder: "Select the process to attach to"
33+
};
34+
35+
return vscode.window.showQuickPick(processEntries, attachPickOptions)
36+
.then(chosenProcess => {
37+
return chosenProcess ? chosenProcess.id : Promise.reject<string>(new Error("Process not selected."));
38+
});
39+
});
40+
}
41+
});
4042
}
4143
}
4244

@@ -48,38 +50,40 @@ export class RemoteAttachPicker {
4850
private _channel: vscode.OutputChannel = null;
4951

5052
public ShowAttachEntries(args: any): Promise<string> {
51-
if (util.getShowReloadPrompt()) {
52-
util.showReloadOrWaitPrompt();
53-
} else {
54-
this._channel.clear();
53+
return util.isExtensionReady().then(ready => {
54+
if (!ready) {
55+
util.displayExtensionNotReadyPrompt();
56+
} else {
57+
this._channel.clear();
5558

56-
let pipeTransport: any = args ? args.pipeTransport : null;
59+
let pipeTransport: any = args ? args.pipeTransport : null;
5760

58-
if (pipeTransport === null) {
59-
return Promise.reject<string>(new Error("Chosen debug configuration does not contain pipeTransport"));
60-
}
61+
if (pipeTransport === null) {
62+
return Promise.reject<string>(new Error("Chosen debug configuration does not contain pipeTransport"));
63+
}
6164

62-
let pipeProgram: string = pipeTransport.pipeProgram;
63-
let pipeArgs: string[] = pipeTransport.pipeArgs;
65+
let pipeProgram: string = pipeTransport.pipeProgram;
66+
let pipeArgs: string[] = pipeTransport.pipeArgs;
6467

65-
let argList: string = RemoteAttachPicker.createArgumentList(pipeArgs);
68+
let argList: string = RemoteAttachPicker.createArgumentList(pipeArgs);
6669

67-
let pipeCmd: string = `"${pipeProgram}" ${argList}`;
70+
let pipeCmd: string = `"${pipeProgram}" ${argList}`;
6871

69-
return this.getRemoteOSAndProcesses(pipeCmd)
70-
.then(processes => {
71-
let attachPickOptions: vscode.QuickPickOptions = {
72-
matchOnDetail: true,
73-
matchOnDescription: true,
74-
placeHolder: "Select the process to attach to"
75-
};
72+
return this.getRemoteOSAndProcesses(pipeCmd)
73+
.then(processes => {
74+
let attachPickOptions: vscode.QuickPickOptions = {
75+
matchOnDetail: true,
76+
matchOnDescription: true,
77+
placeHolder: "Select the process to attach to"
78+
};
7679

77-
return vscode.window.showQuickPick(processes, attachPickOptions)
78-
.then(item => {
79-
return item ? item.id : Promise.reject<string>(new Error("Process not selected."));
80-
});
81-
});
82-
}
80+
return vscode.window.showQuickPick(processes, attachPickOptions)
81+
.then(item => {
82+
return item ? item.id : Promise.reject<string>(new Error("Process not selected."));
83+
});
84+
});
85+
}
86+
});
8387
}
8488

8589
private getRemoteOSAndProcesses(pipeCmd: string): Promise<AttachItem[]> {

Extension/src/Debugger/extension.ts

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,6 @@ export function initialize(): void {
4040
// ConfigurationSnippetProvider needs to be initiallized after configurationProvider calls getConfigurationSnippets.
4141
disposables.push(vscode.languages.registerCompletionItemProvider(launchJsonDocumentSelector, new ConfigurationSnippetProvider(configurationProvider)));
4242

43-
disposables.push(vscode.window.onDidChangeActiveTextEditor(onDidChangeActiveTextEditor));
44-
onDidChangeActiveTextEditor(vscode.window.activeTextEditor);
45-
4643
// Activate Adapter Commands
4744
registerAdapterExecutableCommands();
4845

@@ -53,18 +50,12 @@ export function dispose(): void {
5350
disposables.forEach(d => d.dispose());
5451
}
5552

56-
function onDidChangeActiveTextEditor(editor: vscode.TextEditor): void {
57-
if (util.getShowReloadPromptOnce() && editor && editor.document.fileName.endsWith(path.sep + "launch.json")) {
58-
util.showReloadOrWaitPromptOnce();
59-
}
60-
}
61-
6253
// Registers adapterExecutableCommands for cppdbg and cppvsdbg. If it is not ready, it will prompt waiting for the download.
6354
//
6455
// Note: util.extensionContext.extensionPath is needed for the commands because VsCode does not support relative paths for adapterExecutableComand
6556
function registerAdapterExecutableCommands(): void {
6657
disposables.push(vscode.commands.registerCommand('extension.cppdbgAdapterExecutableCommand', () => {
67-
return util.checkInstallLockFile().then(ready => {
58+
return util.isExtensionReady().then(ready => {
6859
if (ready) {
6960
let command: string = path.join(util.extensionContext.extensionPath, './debugAdapters/OpenDebugAD7');
7061

@@ -77,9 +68,7 @@ function registerAdapterExecutableCommands(): void {
7768
command: command
7869
};
7970
} else {
80-
util.showReloadOrWaitPromptOnce();
81-
// TODO: VsCode displays null return as "Cannot find executable 'null'". Fix if they have a way to not display their prompt.
82-
return null;
71+
throw new Error(util.extensionNotReadyString);
8372
}
8473
});
8574
}));
@@ -89,16 +78,14 @@ function registerAdapterExecutableCommands(): void {
8978
vscode.window.showErrorMessage("Debugger type 'cppvsdbg' is not avaliable for non-Windows machines.");
9079
return null;
9180
} else {
92-
return util.checkInstallLockFile().then(ready => {
81+
return util.isExtensionReady().then(ready => {
9382
if (ready) {
9483
return {
9584
command: path.join(util.extensionContext.extensionPath, './debugAdapters/vsdbg/bin/vsdbg.exe'),
9685
args: ['--interpreter=vscode']
9786
};
9887
} else {
99-
util.showReloadOrWaitPromptOnce();
100-
// TODO: VsCode displays null return as "Cannot find executable 'null'". Fix if they have a way to not display their prompt.
101-
return null;
88+
throw new Error(util.extensionNotReadyString);
10289
}
10390
});
10491
}

Extension/src/LanguageServer/extension.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ const multilineCommentRules: any = {
5959
/**
6060
* activate: set up the extension for language services
6161
*/
62-
export function activate(delayedCommandsToExecute: Set<string>): void {
62+
export function activate(activationEventOccurred: boolean): void {
6363
console.log("activating extension");
6464

6565
// Activate immediately if an activation event occurred in the previous workspace session.
@@ -69,11 +69,12 @@ export function activate(delayedCommandsToExecute: Set<string>): void {
6969
activatedPreviously.Value = false;
7070
realActivation();
7171
}
72+
7273
registerCommands();
7374
tempCommands.push(vscode.workspace.onDidOpenTextDocument(d => onDidOpenTextDocument(d)));
7475

7576
// Check if an activation event has already occurred.
76-
if (delayedCommandsToExecute.size > 0) {
77+
if (activationEventOccurred) {
7778
return onActivationEvent();
7879
}
7980

@@ -164,9 +165,6 @@ function onDidChangeActiveTextEditor(editor: vscode.TextEditor): void {
164165
let activeEditor: vscode.TextEditor = vscode.window.activeTextEditor;
165166
if (!activeEditor || (activeEditor.document.languageId != "cpp" && activeEditor.document.languageId != "c")) {
166167
activeDocument = "";
167-
if (util.getShowReloadPromptOnce() && activeEditor && activeEditor.document.fileName.endsWith(path.sep + "launch.json")) {
168-
util.showReloadOrWaitPromptOnce();
169-
}
170168
} else {
171169
activeDocument = editor.document.uri.toString();
172170
clients.activeDocumentChanged(editor.document);

Extension/src/abTesting.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
/* --------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All Rights Reserved.
3+
* See 'LICENSE' in the project root for license information.
4+
* ------------------------------------------------------------------------------------------ */
5+
'use strict';
6+
7+
import * as url from 'url';
8+
import * as https from 'https';
9+
import { ClientRequest } from 'http';
10+
import * as vscode from 'vscode';
11+
import * as fs from 'fs';
12+
import * as util from './common';
13+
14+
import * as Telemetry from './telemetry';
15+
16+
const userBucketMax: number = 100;
17+
const userBucketString: string = "CPP.UserBucket";
18+
19+
export function activate(context: vscode.ExtensionContext): void {
20+
if (context.globalState.get<number>(userBucketString, -1) == -1) {
21+
let bucket: number = Math.floor(Math.random() * userBucketMax) + 1; // Range is [1, userBucketMax].
22+
context.globalState.update(userBucketString, bucket);
23+
}
24+
25+
setInterval(() => {
26+
// Redownload occasionally to prevent an extra reload during long sessions.
27+
downloadCpptoolsJsonPkg();
28+
}, 30 * 60 * 1000); // 30 minutes.
29+
}
30+
31+
// NOTE: Code is copied from DownloadPackage in packageManager.ts, but with ~75% fewer lines.
32+
function downloadCpptoolsJson(urlString): Promise<void> {
33+
return new Promise<void>((resolve, reject) => {
34+
let parsedUrl: url.Url = url.parse(urlString);
35+
let request: ClientRequest = https.request({
36+
host: parsedUrl.host,
37+
path: parsedUrl.path,
38+
agent: util.GetHttpsProxyAgent(),
39+
rejectUnauthorized: vscode.workspace.getConfiguration().get("http.proxyStrictSSL", true)
40+
}, (response) => {
41+
if (response.statusCode == 301 || response.statusCode == 302) {
42+
let redirectUrl: string | string[];
43+
if (typeof response.headers.location === "string") {
44+
redirectUrl = response.headers.location;
45+
} else {
46+
redirectUrl = response.headers.location[0];
47+
}
48+
return resolve(downloadCpptoolsJson(redirectUrl)); // Redirect - download from new location
49+
}
50+
if (response.statusCode != 200) {
51+
return reject();
52+
}
53+
let downloadedBytes = 0; // tslint:disable-line
54+
let cppToolsJsonFile: fs.WriteStream = fs.createWriteStream(util.getExtensionFilePath("cpptools.json"));
55+
response.on('data', (data) => { downloadedBytes += data.length; });
56+
response.on('end', () => { cppToolsJsonFile.close(); });
57+
cppToolsJsonFile.on('close', () => { resolve(); });
58+
response.on('error', (error) => { reject(); });
59+
response.pipe(cppToolsJsonFile, { end: false });
60+
});
61+
request.on('error', (error) => { reject(); });
62+
request.end();
63+
});
64+
}
65+
66+
export function downloadCpptoolsJsonPkg(): Promise<void> {
67+
let hasError: boolean = false;
68+
let telemetryProperties: { [key: string]: string } = {};
69+
return downloadCpptoolsJson("https://go.microsoft.com/fwlink/?linkid=852750")
70+
.catch((error) => {
71+
// More specific error info is not likely to be helpful, and we get detailed download data from the initial install.
72+
hasError = true;
73+
})
74+
.then(() => {
75+
telemetryProperties['success'] = (!hasError).toString();
76+
Telemetry.logDebuggerEvent("cpptoolsJsonDownload", telemetryProperties);
77+
});
78+
}
79+
80+
export function processCpptoolsJson(cpptoolsString: string): Promise<void> {
81+
let cpptoolsObject: any = JSON.parse(cpptoolsString);
82+
let intelliSenseEnginePercentage: number = cpptoolsObject.intelliSenseEngine_default_percentage;
83+
84+
if (!util.packageJson.extensionFolderPath.includes(".vscode-insiders")) {
85+
let prevIntelliSenseEngineDefault: any = util.packageJson.contributes.configuration.properties["C_Cpp.intelliSenseEngine"].default;
86+
if (util.extensionContext.globalState.get<number>(userBucketString, userBucketMax + 1) <= intelliSenseEnginePercentage) {
87+
util.packageJson.contributes.configuration.properties["C_Cpp.intelliSenseEngine"].default = "Default";
88+
} else {
89+
util.packageJson.contributes.configuration.properties["C_Cpp.intelliSenseEngine"].default = "Tag Parser";
90+
}
91+
if (prevIntelliSenseEngineDefault != util.packageJson.contributes.configuration.properties["C_Cpp.intelliSenseEngine"].default) {
92+
return util.writeFileText(util.getPackageJsonPath(), util.getPackageJsonString());
93+
}
94+
}
95+
}

Extension/src/commands.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/* --------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All Rights Reserved.
3+
* See 'LICENSE' in the project root for license information.
4+
* ------------------------------------------------------------------------------------------ */
5+
'use strict';
6+
7+
import * as vscode from 'vscode';
8+
import * as LanguageServer from './LanguageServer/extension';
9+
10+
class TemporaryCommandRegistrar {
11+
// Used to save/re-execute commands used before the extension has activated (e.g. delayed by dependency downloading).
12+
private delayedCommandsToExecute: Set<string>;
13+
private tempCommands: vscode.Disposable[]; // Need to save this to unregister/dispose the temporary commands.
14+
15+
private commandsToRegister: string[] = [
16+
"C_Cpp.ConfigurationEdit",
17+
"C_Cpp.ConfigurationSelect",
18+
"C_Cpp.SwitchHeaderSource",
19+
"C_Cpp.Navigate",
20+
"C_Cpp.GoToDeclaration",
21+
"C_Cpp.PeekDeclaration",
22+
"C_Cpp.ToggleErrorSquiggles",
23+
"C_Cpp.ToggleIncludeFallback",
24+
"C_Cpp.ShowReleaseNotes",
25+
"C_Cpp.ResetDatabase",
26+
"C_Cpp.PauseParsing",
27+
"C_Cpp.ResumeParsing",
28+
"C_Cpp.ShowParsingCommands",
29+
"C_Cpp.TakeSurvey"
30+
];
31+
32+
constructor() {
33+
this.tempCommands = [];
34+
this.delayedCommandsToExecute = new Set<string>();
35+
36+
// Add temp commands that invoke the real commands after download/install is complete (preventing an error message)
37+
this.commandsToRegister.forEach(command => {
38+
this.registerTempCommand(command);
39+
});
40+
}
41+
42+
public registerTempCommand(command: string): void {
43+
this.tempCommands.push(vscode.commands.registerCommand(command, () => {
44+
this.delayedCommandsToExecute.add(command);
45+
}));
46+
}
47+
48+
public activateLanguageServer(): void {
49+
// Main activation code.
50+
this.tempCommands.forEach((command) => {
51+
command.dispose();
52+
});
53+
this.tempCommands = [];
54+
55+
LanguageServer.activate(this.delayedCommandsToExecute.size > 0);
56+
57+
this.delayedCommandsToExecute.forEach((command) => {
58+
vscode.commands.executeCommand(command);
59+
});
60+
this.delayedCommandsToExecute.clear();
61+
}
62+
}
63+
64+
let tempCommandRegistrar: TemporaryCommandRegistrar;
65+
66+
export function initializeTemporaryCommandRegistrar(): void {
67+
tempCommandRegistrar = new TemporaryCommandRegistrar();
68+
}
69+
70+
export function geTemporaryCommandRegistrarInstance(): TemporaryCommandRegistrar {
71+
return tempCommandRegistrar;
72+
}

0 commit comments

Comments
 (0)