Skip to content

Commit

Permalink
Merge pull request #2436 from NTaylorMullen/nimullen/2431
Browse files Browse the repository at this point in the history
Track virtual documents.
  • Loading branch information
akshita31 authored Aug 1, 2018
2 parents 82be5e1 + 51da252 commit d00799a
Show file tree
Hide file tree
Showing 6 changed files with 173 additions and 3 deletions.
4 changes: 2 additions & 2 deletions src/features/diagnosticsProvider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,7 @@ class DiagnosticsProvider extends AbstractSupport {
// Go ahead and check for diagnostics in the currently visible editors.
for (let editor of vscode.window.visibleTextEditors) {
let document = editor.document;
if (document.languageId === 'csharp' && document.uri.scheme === 'file') {
if (document.languageId === 'csharp') {
this._validateDocument(document);
}
}
Expand Down Expand Up @@ -172,7 +172,7 @@ class DiagnosticsProvider extends AbstractSupport {
}

private _onDocumentAddOrChange(document: vscode.TextDocument): void {
if (document.languageId === 'csharp' && document.uri.scheme === 'file') {
if (document.languageId === 'csharp') {
this._validateDocument(document);
this._validateProject();
}
Expand Down
97 changes: 97 additions & 0 deletions src/features/virtualDocumentTracker.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import {workspace, TextDocument, Uri} from 'vscode';
import {OmniSharpServer} from '../omnisharp/server';
import * as serverUtils from '../omnisharp/utils';
import { FileChangeType } from '../omnisharp/protocol';
import { IDisposable } from '../Disposable';
import CompositeDisposable from '../CompositeDisposable';
import { EventStream } from '../EventStream';
import { DocumentSynchronizationFailure } from '../omnisharp/loggingEvents';

function trackCurrentVirtualDocuments(server: OmniSharpServer, eventStream: EventStream) {
let registration = server.onProjectAdded(async () => {
registration.dispose();

for (let i = 0; i < workspace.textDocuments.length; i++) {
let document = workspace.textDocuments[i];

if (!shouldIgnoreDocument(document, server)) {
await openVirtualDocument(document, server, eventStream);
}
}
});
}

function trackFutureVirtualDocuments(server: OmniSharpServer, eventStream: EventStream): IDisposable {
let onTextDocumentOpen = workspace.onDidOpenTextDocument(async document => {
if (shouldIgnoreDocument(document, server)) {
return;
}

await openVirtualDocument(document, server, eventStream);
});

let onTextDocumentClose = workspace.onDidCloseTextDocument(async document => {
if (shouldIgnoreDocument(document, server)) {
return;
}

await closeVirtualDocument(document, server, eventStream);
});

// We already track text document changes for virtual documents in our change forwarder.
return new CompositeDisposable(
onTextDocumentOpen,
onTextDocumentClose);
}

function shouldIgnoreDocument(document: TextDocument, server: OmniSharpServer): boolean {
if (document.uri.scheme === 'file' || document.languageId !== 'csharp') {
// We're only interested in non-physical CSharp documents.
return true;
}

if (!server.isRunning()) {
return true;
}

return false;
}

async function openVirtualDocument(document: TextDocument, server: OmniSharpServer, eventStream: EventStream) {
let req = { FileName: document.uri.path, changeType: FileChangeType.Create };
try {
await serverUtils.filesChanged(server, [req]);
await serverUtils.updateBuffer(server, { Buffer: document.getText(), FileName: document.fileName });
}
catch (error) {
logSynchronizationFailure(document.uri, error, server, eventStream);
}
}

async function closeVirtualDocument(document: TextDocument, server: OmniSharpServer, eventStream: EventStream) {
let req = { FileName: document.uri.path, changeType: FileChangeType.Delete };
try {
await serverUtils.filesChanged(server, [req]);
}
catch (error) {
logSynchronizationFailure(document.uri, error, server, eventStream);
}
}

function logSynchronizationFailure(uri: Uri, error: any, server: OmniSharpServer, eventStream: EventStream) {
if (server.isRunning()) {
eventStream.post(new DocumentSynchronizationFailure(uri.path, error));
}
}

export default function trackVirtualDocuments(server: OmniSharpServer, eventStream: EventStream): IDisposable {
trackCurrentVirtualDocuments(server, eventStream);
let disposable = trackFutureVirtualDocuments(server, eventStream);

return disposable;
}
7 changes: 7 additions & 0 deletions src/observers/CsharpLoggerObserver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ export class CsharpLoggerObserver extends BaseLoggerObserver {
case Event.DownloadSizeObtained.name:
this.handleDownloadSizeObtained(<Event.DownloadSizeObtained>event);
break;
case Event.DocumentSynchronizationFailure.name:
this.handleDocumentSynchronizationFailure(<Event.DocumentSynchronizationFailure>event);
break;
case Event.LatestBuildDownloadStart.name:
this.logger.appendLine("Getting latest OmniSharp version information");
break;
Expand Down Expand Up @@ -112,4 +115,8 @@ export class CsharpLoggerObserver extends BaseLoggerObserver {
this.logger.appendLine(`Installing package '${event.packageDescription}'`);
this.logger.appendLine();
}

private handleDocumentSynchronizationFailure(event: Event.DocumentSynchronizationFailure) {
this.logger.appendLine(`Failed to synchronize document '${event.documentPath}': ${event.errorMessage}`);
}
}
3 changes: 2 additions & 1 deletion src/omnisharp/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,14 +34,14 @@ import { NetworkSettingsProvider } from '../NetworkSettings';
import CompositeDisposable from '../CompositeDisposable';
import Disposable from '../Disposable';
import OptionProvider from '../observers/OptionProvider';
import trackVirtualDocuments from '../features/virtualDocumentTracker';
import { StructureProvider } from '../features/structureProvider';

export let omnisharp: OmniSharpServer;

export async function activate(context: vscode.ExtensionContext, packageJSON: any, platformInfo: PlatformInformation, provider: NetworkSettingsProvider, eventStream: EventStream, optionProvider: OptionProvider, extensionPath: string) {
const documentSelector: vscode.DocumentSelector = {
language: 'csharp',
scheme: 'file' // only files from disk
};

const options = optionProvider.GetLatestOptions();
Expand Down Expand Up @@ -81,6 +81,7 @@ export async function activate(context: vscode.ExtensionContext, packageJSON: an
localDisposables.add(vscode.languages.registerCodeActionsProvider(documentSelector, codeActionProvider));
localDisposables.add(reportDiagnostics(server, advisor));
localDisposables.add(forwardChanges(server));
localDisposables.add(trackVirtualDocuments(server, eventStream));
localDisposables.add(vscode.languages.registerFoldingRangeProvider(documentSelector, new StructureProvider(server)));
}));

Expand Down
4 changes: 4 additions & 0 deletions src/omnisharp/loggingEvents.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ export class DotNetTestsInClassDebugStart implements BaseEvent {
constructor(public className: string) { }
}

export class DocumentSynchronizationFailure implements BaseEvent {
constructor(public documentPath: string, public errorMessage: string) { }
}

export class DebuggerPrerequisiteFailure extends EventWithMessage { }
export class DebuggerPrerequisiteWarning extends EventWithMessage { }
export class CommandDotNetRestoreProgress extends EventWithMessage { }
Expand Down
61 changes: 61 additions & 0 deletions test/integrationTests/virtualDocumentTracker.integration.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

import * as vscode from 'vscode';

import { should, expect } from 'chai';
import { activateCSharpExtension } from './integrationHelpers';
import testAssetWorkspace from './testAssets/testAssetWorkspace';
import { IDisposable } from '../../src/Disposable';

const chai = require('chai');
chai.use(require('chai-arrays'));
chai.use(require('chai-fs'));

suite(`Virtual Document Tracking ${testAssetWorkspace.description}`, function () {
let virtualScheme: string = "virtual";
let virtualDocumentRegistration: IDisposable;

suiteSetup(async function () {
should();
await testAssetWorkspace.restore();
await activateCSharpExtension();

let virtualCSharpDocumentProvider = new VirtualCSharpDocumentProvider();
virtualDocumentRegistration = vscode.workspace.registerTextDocumentContentProvider(virtualScheme, virtualCSharpDocumentProvider);
});

suiteTeardown(async () => {
await testAssetWorkspace.cleanupWorkspace();
virtualDocumentRegistration.dispose();
});

test("Virtual documents are operated on.", async () => {
let virtualUri = vscode.Uri.parse(`${virtualScheme}://${testAssetWorkspace.projects[0].projectDirectoryPath}/_virtualFile.cs`);
await vscode.workspace.openTextDocument(virtualUri);

let position = new vscode.Position(2, 4);
let completionItems = <vscode.CompletionList>await vscode.commands.executeCommand("vscode.executeCompletionItemProvider", virtualUri, position);

expect(completionItems.items).to.satisfy(() => {
let item = completionItems.items.find(item => {
return item.label === "while";
});

return item;
});
});
});

class VirtualCSharpDocumentProvider implements vscode.TextDocumentContentProvider {
onDidChange?: vscode.Event<vscode.Uri>;

provideTextDocumentContent(uri: vscode.Uri, token: vscode.CancellationToken): vscode.ProviderResult<string> {
return `namespace Test
{
}`;
}
}

0 comments on commit d00799a

Please sign in to comment.