Skip to content

Commit d6fb88b

Browse files
Merge branch 'master' into release
2 parents b6a8115 + 8161ce8 commit d6fb88b

File tree

10 files changed

+132
-21
lines changed

10 files changed

+132
-21
lines changed

src/main.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import { ProjectStatusBarObserver } from './observers/ProjectStatusBarObserver';
3030
import CSharpExtensionExports from './CSharpExtensionExports';
3131
import { Options } from './omnisharp/options';
3232
import { vscodeNetworkSettingsProvider, NetworkSettingsProvider } from './NetworkSettings';
33+
import { ErrorMessageObserver } from './observers/ErrorMessageObserver';
3334

3435
export async function activate(context: vscode.ExtensionContext): Promise<CSharpExtensionExports> {
3536

@@ -67,6 +68,9 @@ export async function activate(context: vscode.ExtensionContext): Promise<CSharp
6768
let informationMessageObserver = new InformationMessageObserver(vscode);
6869
eventStream.subscribe(informationMessageObserver.post);
6970

71+
let errorMessageObserver = new ErrorMessageObserver(vscode);
72+
eventStream.subscribe(errorMessageObserver.post);
73+
7074
let omnisharpStatusBar = new StatusBarItemAdapter(vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left, Number.MIN_VALUE));
7175
let omnisharpStatusBarObserver = new OmnisharpStatusBarObserver(omnisharpStatusBar);
7276
eventStream.subscribe(omnisharpStatusBarObserver.post);
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
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+
7+
import { BaseEvent, ZipError } from "../omnisharp/loggingEvents";
8+
import { vscode } from "../vscodeAdapter";
9+
10+
export class ErrorMessageObserver {
11+
12+
constructor(private vscode: vscode) {
13+
}
14+
15+
public post = (event: BaseEvent) => {
16+
switch (event.constructor.name) {
17+
case ZipError.name:
18+
this.handleZipError(<ZipError>event);
19+
break;
20+
}
21+
}
22+
23+
private async handleZipError(event: ZipError) {
24+
await showErrorMessage(this.vscode, event.message);
25+
}
26+
}
27+
28+
async function showErrorMessage(vscode: vscode, message: string, ...items: string[]) {
29+
try {
30+
await vscode.window.showErrorMessage(message, ...items);
31+
}
32+
catch (err) {
33+
console.log(err);
34+
}
35+
}

src/observers/WarningMessageObserver.ts

Lines changed: 13 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,21 +20,7 @@ export class WarningMessageObserver {
2020
this.warningMessageDebouncer = new Subject<BaseEvent>();
2121
this.warningMessageDebouncer.debounceTime(1500, scheduler).subscribe(async event => {
2222
let message = "Some projects have trouble loading. Please review the output for more details.";
23-
let value: MessageItemWithCommand;
24-
try {
25-
value = await this.vscode.window.showWarningMessage<MessageItemWithCommand>(message, { title: "Show Output", command: 'o.showOutput' });
26-
}
27-
catch (err){
28-
console.log(err);
29-
}
30-
if (value) {
31-
try {
32-
await this.vscode.commands.executeCommand<string>(value.command);
33-
}
34-
catch (err) {
35-
console.log(err);
36-
}
37-
}
23+
await showWarningMessage(this.vscode, message, { title: "Show Output", command: 'o.showOutput' });
3824
});
3925
}
4026

@@ -54,4 +40,16 @@ export class WarningMessageObserver {
5440
this.warningMessageDebouncer.next(event);
5541
}
5642
}
43+
}
44+
45+
async function showWarningMessage(vscode: vscode, message: string, ...items: MessageItemWithCommand[]) {
46+
try {
47+
let value = await vscode.window.showWarningMessage<MessageItemWithCommand>(message, ...items);
48+
if (value && value.command) {
49+
await vscode.commands.executeCommand<string>(value.command);
50+
}
51+
}
52+
catch (err) {
53+
console.log(err);
54+
}
5755
}

src/omnisharp/loggingEvents.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ export class DownloadSizeObtained implements BaseEvent {
118118
constructor(public packageSize: number) { }
119119
}
120120

121+
export class ZipError implements BaseEvent {
122+
constructor(public message: string) { }
123+
}
124+
121125
export class DebuggerPrerequisiteFailure extends EventWithMessage { }
122126
export class DebuggerPrerequisiteWarning extends EventWithMessage { }
123127
export class CommandDotNetRestoreProgress extends EventWithMessage { }

src/packageManager/ZipInstaller.ts

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as mkdirp from 'mkdirp';
88
import * as path from 'path';
99
import * as yauzl from 'yauzl';
1010
import { EventStream } from "../EventStream";
11-
import { InstallationStart } from "../omnisharp/loggingEvents";
11+
import { InstallationStart, ZipError } from "../omnisharp/loggingEvents";
1212
import { NestedError } from '../NestedError';
1313

1414
export async function InstallZip(buffer: Buffer, description: string, destinationInstallPath: string, binaries: string[], eventStream: EventStream): Promise<void> {
@@ -17,7 +17,9 @@ export async function InstallZip(buffer: Buffer, description: string, destinatio
1717
return new Promise<void>((resolve, reject) => {
1818
yauzl.fromBuffer(buffer, { lazyEntries: true }, (err, zipFile) => {
1919
if (err) {
20-
return reject(new NestedError('Immediate zip file error', err));
20+
let message = "C# Extension was unable to download its dependencies. Please check your internet connection. If you use a proxy server, please visit https://aka.ms/VsCodeCsharpNetworking";
21+
eventStream.post(new ZipError(message));
22+
return reject(new NestedError(message));
2123
}
2224

2325
zipFile.readEntry();

src/vscodeAdapter.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -900,6 +900,7 @@ export interface vscode {
900900
activeTextEditor: TextEditor | undefined;
901901
showInformationMessage: (message: string, ...items: string[]) => Thenable<string | undefined>;
902902
showWarningMessage: <T extends MessageItem>(message: string, ...items: T[]) => Thenable<T | undefined>;
903+
showErrorMessage(message: string, ...items: string[]): Thenable<string | undefined>;
903904
};
904905
workspace: {
905906
getConfiguration: (section?: string, resource?: Uri) => WorkspaceConfiguration;

test-plan.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,15 @@ The easist way to verify that a project was successfully loaded is to open a .cs
9292
* In a project that uses globbing (.NET Core), use the VS Code file explorer to add a new file next to the csproj. Intellisense/sighelp/etc should be available in the new file
9393
* Add a new file and reference a type in it from a different file. Deleting from disk the file containing the referenced type should produce error messages
9494

95-
#### Omnisharp Options
95+
#### OmniSharp Options
9696

97-
#### omnisharp.useMono (for Linux)
97+
#### omnisharp.useGlobalMono (for Linux/Mac)
98+
This option can be set to any of the following values:
99+
* "auto" - Will launch OmniSharp using mono if version>=5.2.0 is installed but will launch using the run script if that is not so.
100+
* "always" - Will launch OmniSharp using mono if version>=5.2.0 is installed and will throw an error otherwise.
101+
* "never" - Launches OmniSharp without using the global mono
102+
103+
The value of OmniSharp path displayed in the OmniSharp log can be used to know if OmniSharp has launched using mono or not. If it is running using global mono, the path will end with "OmniSharp.exe" else the path will end with "run".
98104
For using this option, mono version greater than or equal to 5.2.0 must be installed. If that is not so, setting this option to true, should give an error.
99105
* If the option is not set, the OmniSharp path displayed in the "OmniSharp Log" should end with "run"
100106
* If the option is set, the OmniSharp path as mentioned above should end with "OmniSharp.exe"
@@ -108,6 +114,13 @@ The easist way to verify that a project was successfully loaded is to open a .cs
108114
* All the above configurations should work, with and without setting the useMono option on Linux
109115
* The above behavior should be exhibited when a new vscode window is opened, as well as if the setting is modified and a "Restart OmniSharp"(Ctrl+Shift+P --> OmniSharp: Restart OmniSharp) is performed.
110116

117+
#### Status Bar Item
118+
The status bar item(s) must appear on the left side of the VS Code's status bar
119+
* When the extension is setting up the dependencies, the status bar item should show "Downloading packages"/"Installing packages".
120+
* Once the server has started, there should be two status bar items:
121+
* OmniSharp status Bar item - It should show a green flame (indicating that the OmniSharp server is running) and clicking on it should show the OmniSharp log channel
122+
* Project status bar item - It should show and a folder icon and the name of the currently selected project/solution. Clicking on this element should show a command palette menu to select other projects/solutions in the workspace.
123+
111124
[1] For example,
112125
```
113126
mkdir project

test/unitTests/Packages/ZipInstaller.test.ts

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import { CreateTmpDir, TmpAsset } from '../../../src/CreateTmpAsset';
1111
import { InstallZip } from '../../../src/packageManager/ZipInstaller';
1212
import { EventStream } from '../../../src/EventStream';
1313
import { PlatformInformation } from '../../../src/platform';
14-
import { BaseEvent, InstallationStart } from '../../../src/omnisharp/loggingEvents';
14+
import { BaseEvent, InstallationStart, ZipError } from '../../../src/omnisharp/loggingEvents';
1515
import { Files, Binaries, createTestZipAsync } from '../testAssets/CreateTestZip';
1616

1717
chai.use(require("chai-as-promised"));
@@ -65,10 +65,23 @@ suite('ZipInstaller', () => {
6565
}
6666
});
6767

68-
test('Error is thrown when the file is not a zip', async () => {
68+
test('Error is thrown when the buffer contains an invalid zip', async () => {
6969
expect(InstallZip(new Buffer("My file", "utf8"), "Text File", installationPath, [], eventStream)).to.be.rejected;
7070
});
7171

72+
test('Error event is created when the buffer contains an invalid zip', async () => {
73+
try {
74+
await InstallZip(new Buffer("some content", "utf8"), "Text File", installationPath, [], eventStream);
75+
}
76+
catch{
77+
let eventSequence: BaseEvent[] = [
78+
new InstallationStart("Text File"),
79+
new ZipError("C# Extension was unable to download its dependencies. Please check your internet connection. If you use a proxy server, please visit https://aka.ms/VsCodeCsharpNetworking")
80+
];
81+
expect(eventBus).to.be.deep.equal(eventSequence);
82+
}
83+
});
84+
7285
teardown(async () => {
7386
if (tmpInstallDir) {
7487
tmpInstallDir.dispose();
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
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+
import { use as chaiUse, expect, should } from 'chai';
7+
import { vscode } from '../../../src/vscodeAdapter';
8+
import { getFakeVsCode } from '../testAssets/Fakes';
9+
import 'rxjs/add/observable/fromPromise';
10+
import 'rxjs/add/operator/timeout';
11+
import { ErrorMessageObserver } from '../../../src/observers/ErrorMessageObserver';
12+
import { ZipError } from '../../../src/omnisharp/loggingEvents';
13+
14+
chaiUse(require('chai-as-promised'));
15+
chaiUse(require('chai-string'));
16+
17+
suite("ErrorMessageObserver", () => {
18+
suiteSetup(() => should());
19+
20+
let vscode: vscode = getFakeVsCode();
21+
let errorMessage: string;
22+
let observer = new ErrorMessageObserver(vscode);
23+
24+
vscode.window.showErrorMessage = async (message: string, ...items: string[]) => {
25+
errorMessage = message;
26+
return Promise.resolve<string>("Done");
27+
};
28+
29+
setup(() => {
30+
errorMessage = undefined;
31+
});
32+
33+
test('ZipError: Error message is shown', () => {
34+
let event = new ZipError("This is an error");
35+
observer.post(event);
36+
expect(errorMessage).to.be.equal("This is an error");
37+
});
38+
});

test/unitTests/testAssets/Fakes.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,9 @@ export function getFakeVsCode(): vscode.vscode {
132132
},
133133
showWarningMessage: <T extends MessageItem>(message: string, ...items: T[]) => {
134134
throw new Error("Not Implemented");
135+
},
136+
showErrorMessage: (message: string, ...items: string[]) => {
137+
throw new Error("Not Implemented");
135138
}
136139
},
137140
workspace: {

0 commit comments

Comments
 (0)