Add Project system and completion system infrastructure and services.

- Also re-ordered some control flows to enable future scenarios.
- Added a fake foreground thread on the server to re-use a lot of tooling code.
- Did a ton of stuff in this commit, too much to put into a commit message. These bits are the basis for everything we'll be doing going forward. ;)
This commit is contained in:
N. Taylor Mullen 2018-07-30 18:16:26 -07:00
Родитель ac9875968c
Коммит 10d1797030
61 изменённых файлов: 2295 добавлений и 135 удалений

Просмотреть файл

@ -6,6 +6,9 @@ MinimumVisualStudioVersion = 15.0.26124.0
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{2BBB2AB1-2AE4-4306-AA88-FD66A90AA101}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "build", "build", "{9AD3190E-86E4-419B-9D57-C6FFEF3A01F6}"
ProjectSection(SolutionItems) = preProject
build\dependencies.props = build\dependencies.props
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.LanguageServer", "src\Microsoft.AspNetCore.Razor.LanguageServer\Microsoft.AspNetCore.Razor.LanguageServer.csproj", "{AF5FB0D8-BACD-45DE-B4A2-4CA172DCAEB6}"
EndProject
@ -17,6 +20,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "JsonRpc", "modules\csharp-l
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Protocol", "modules\csharp-language-server-protocol\src\Protocol\Protocol.csproj", "{AF14A869-234A-4874-8D97-9B28DDC89B6E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "csharp-language-server-protocol", "csharp-language-server-protocol", "{27AB8254-F634-4D21-AFF1-E078CF3A2009}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed", "src\Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed\Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed.csproj", "{427A5FBB-09EF-49BA-9B00-F3A09892811F}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Razor", "Razor", "{3C0D9AB8-562E-4736-A31D-839AF8C9D9FD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Workspaces", "modules\Razor\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj", "{A3E388BC-F625-4A6A-AD31-04E8B1DD0D91}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor", "modules\Razor\src\Microsoft.CodeAnalysis.Razor\Microsoft.CodeAnalysis.Razor.csproj", "{8CFC36F5-61B4-4F56-8311-750C2969B61D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Language", "modules\Razor\src\Microsoft.AspNetCore.Razor.Language\Microsoft.AspNetCore.Razor.Language.csproj", "{487B924C-B52C-44B0-A10C-9CCE95138F14}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -39,15 +54,37 @@ Global
{AF14A869-234A-4874-8D97-9B28DDC89B6E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AF14A869-234A-4874-8D97-9B28DDC89B6E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AF14A869-234A-4874-8D97-9B28DDC89B6E}.Release|Any CPU.Build.0 = Release|Any CPU
{427A5FBB-09EF-49BA-9B00-F3A09892811F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{427A5FBB-09EF-49BA-9B00-F3A09892811F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{427A5FBB-09EF-49BA-9B00-F3A09892811F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{427A5FBB-09EF-49BA-9B00-F3A09892811F}.Release|Any CPU.Build.0 = Release|Any CPU
{A3E388BC-F625-4A6A-AD31-04E8B1DD0D91}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{A3E388BC-F625-4A6A-AD31-04E8B1DD0D91}.Debug|Any CPU.Build.0 = Debug|Any CPU
{A3E388BC-F625-4A6A-AD31-04E8B1DD0D91}.Release|Any CPU.ActiveCfg = Release|Any CPU
{A3E388BC-F625-4A6A-AD31-04E8B1DD0D91}.Release|Any CPU.Build.0 = Release|Any CPU
{8CFC36F5-61B4-4F56-8311-750C2969B61D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{8CFC36F5-61B4-4F56-8311-750C2969B61D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{8CFC36F5-61B4-4F56-8311-750C2969B61D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8CFC36F5-61B4-4F56-8311-750C2969B61D}.Release|Any CPU.Build.0 = Release|Any CPU
{487B924C-B52C-44B0-A10C-9CCE95138F14}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{487B924C-B52C-44B0-A10C-9CCE95138F14}.Debug|Any CPU.Build.0 = Debug|Any CPU
{487B924C-B52C-44B0-A10C-9CCE95138F14}.Release|Any CPU.ActiveCfg = Release|Any CPU
{487B924C-B52C-44B0-A10C-9CCE95138F14}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{AF5FB0D8-BACD-45DE-B4A2-4CA172DCAEB6} = {2BBB2AB1-2AE4-4306-AA88-FD66A90AA101}
{6659F686-E560-416C-9390-17F89C668A8D} = {BEAA2EDB-B257-4B34-9FA3-2AD973914528}
{C8CAF4AD-6AD1-4B8C-B1F3-15B0C5632CD9} = {BEAA2EDB-B257-4B34-9FA3-2AD973914528}
{AF14A869-234A-4874-8D97-9B28DDC89B6E} = {BEAA2EDB-B257-4B34-9FA3-2AD973914528}
{6659F686-E560-416C-9390-17F89C668A8D} = {27AB8254-F634-4D21-AFF1-E078CF3A2009}
{C8CAF4AD-6AD1-4B8C-B1F3-15B0C5632CD9} = {27AB8254-F634-4D21-AFF1-E078CF3A2009}
{AF14A869-234A-4874-8D97-9B28DDC89B6E} = {27AB8254-F634-4D21-AFF1-E078CF3A2009}
{27AB8254-F634-4D21-AFF1-E078CF3A2009} = {BEAA2EDB-B257-4B34-9FA3-2AD973914528}
{427A5FBB-09EF-49BA-9B00-F3A09892811F} = {2BBB2AB1-2AE4-4306-AA88-FD66A90AA101}
{3C0D9AB8-562E-4736-A31D-839AF8C9D9FD} = {BEAA2EDB-B257-4B34-9FA3-2AD973914528}
{A3E388BC-F625-4A6A-AD31-04E8B1DD0D91} = {3C0D9AB8-562E-4736-A31D-839AF8C9D9FD}
{8CFC36F5-61B4-4F56-8311-750C2969B61D} = {3C0D9AB8-562E-4736-A31D-839AF8C9D9FD}
{487B924C-B52C-44B0-A10C-9CCE95138F14} = {3C0D9AB8-562E-4736-A31D-839AF8C9D9FD}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {ED1782EB-ABE7-4615-80E2-442006DF2826}

Просмотреть файл

@ -3,6 +3,7 @@
<MSBuildAllProjects>$(MSBuildAllProjects);$(MSBuildThisFileFullPath)</MSBuildAllProjects>
</PropertyGroup>
<PropertyGroup Label="Package Versions">
<MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>2.1.1</MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion>
<InternalAspNetCoreSdkPackageVersion>2.2.0-preview1-17090</InternalAspNetCoreSdkPackageVersion>
</PropertyGroup>

Просмотреть файл

@ -0,0 +1,23 @@
{
"comments": {
"blockComment": [ "<!--", "-->" ]
},
"brackets": [
["<!--", "-->"],
["<", ">"],
["{", "}"],
["(", ")"]
],
"autoClosingPairs": [
{ "open": "{", "close": "}"},
{ "open": "[", "close": "]"},
{ "open": "(", "close": ")" },
{ "open": "'", "close": "'" },
{ "open": "\"", "close": "\"" }
],
"surroundingPairs": [
{ "open": "'", "close": "'" },
{ "open": "\"", "close": "\"" },
{ "open": "<", "close": ">" }
]
}

Просмотреть файл

@ -11,9 +11,65 @@
"Other"
],
"activationEvents": [
"onLanguage:razor"
"onLanguage:razorcore"
],
"main": "./out/extension",
"contributes": {
"commands": [
{
"command": "extension.showRazorCSharpWindow",
"title": "Show Razor CSharp"
},
{
"command": "extension.showRazorHtmlWindow",
"title": "Show Razor Html"
}
],
"menus": {
"editor/title": [
{
"command": "extension.showRazorCSharpWindow",
"when": "resourceLangId == razor"
},
{
"command": "extension.showRazorHtmlWindow",
"when": "resourceLangId == razor"
}
]
},
"languages": [
{
"id": "razorcore",
"extensions": [
".razor"
],
"configuration": "./language-configuration.json"
}
],
"configuration": {
"title": "Razor Configuration",
"properties": {
"razor.languageServer.path": {
"type": [
"string",
"null"
],
"default": null,
"description": "Specifies the path to the Razor LanguageServer. This should be the absolute path to the language server dll."
},
"razor.languageServer.debug": {
"type": "boolean",
"default": false,
"description": "Specifies whether to wait for debug attach when launching the language server."
},
"razor.languageServer.trace": {
"type": "string",
"default": "Messages",
"description": "Specifies whether to output all messages [Verbose], some messages [Messages] or not at all [Off]."
}
}
}
},
"scripts": {
"vscode:prepublish": "npm run compile",
"compile": "tsc -p ./",
@ -23,9 +79,12 @@
},
"devDependencies": {
"typescript": "^2.6.1",
"vscode": "^1.1.6",
"tslint": "^5.8.0",
"@types/node": "^7.0.43",
"@types/mocha": "^2.2.42"
},
"dependencies": {
"vscode": "^1.1.18",
"vscode-languageclient": "^4.1.4"
}
}

Просмотреть файл

@ -0,0 +1,85 @@
/* --------------------------------------------------------------------------------------------
* 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 { CSharpProjectedDocument } from './CSharpProjectedDocument';
import { CSharpProjectedDocumentContentProvider } from './CSharpProjectedDocumentContentProvider';
export class CSharpPreviewDocumentContentProvider implements vscode.TextDocumentContentProvider {
public static readonly scheme: string = CSharpProjectedDocument.scheme + "-preview";
public static readonly previewUri: vscode.Uri = vscode.Uri.parse(CSharpPreviewDocumentContentProvider.scheme + "://razor/csharppreview");
private _onDidChange: vscode.EventEmitter<vscode.Uri>;
private _csharpProjectionProvider: CSharpProjectedDocumentContentProvider;
constructor (csharpContentProvider: CSharpProjectedDocumentContentProvider ) {
this._csharpProjectionProvider = csharpContentProvider;
this._onDidChange = new vscode.EventEmitter<vscode.Uri>();
}
public get onDidChange(): vscode.Event<vscode.Uri> {
return this._onDidChange.event;
}
public update() {
let projectedDocument = this._csharpProjectionProvider.getActiveDocument();
if (!projectedDocument) {
return;
}
this._onDidChange.fire(CSharpPreviewDocumentContentProvider.previewUri);
}
public async provideTextDocumentContent(): Promise<string> {
let projectedDocument = await this._csharpProjectionProvider.getActiveDocument();
if (!projectedDocument) {
vscode.window.showErrorMessage("For some reason the projected document isn't set.");
return "";
}
let projectedUriPath = projectedDocument.projectedUri.path;
let document = vscode.workspace.textDocuments.find((doc) => {
if (doc.uri.path.localeCompare(projectedUriPath, undefined, { sensitivity: 'base' }) === 0) {
return true;
}
return false;
});
if (document) {
let content = document.getText();
let htmlContent = `
<body>
<p>For host document: <strong>${projectedDocument.hostDocumentUri.path}</strong></p>
<hr />
<pre>${content}</pre>
<hr />
</body>`;
return htmlContent;
}
else {
return "";
}
}
public async showRazorCSharpWindow(): Promise<void> {
let activeProjectedDocument = this._csharpProjectionProvider.getActiveDocument();
if (!activeProjectedDocument) {
vscode.window.showErrorMessage("No active text editor.");
return;
}
try {
await vscode.commands.executeCommand('vscode.previewHtml', CSharpPreviewDocumentContentProvider.previewUri, vscode.ViewColumn.Two, 'Razor CSharp Output');
}
catch (error) {
vscode.window.showErrorMessage(error);
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
/* --------------------------------------------------------------------------------------------
* 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';
export class CSharpProjectedDocument {
public static readonly scheme: string = "razor-csharp";
private _projectedUri : vscode.Uri;
private _hostDocumentUri : vscode.Uri;
private constructor (projectedUri: vscode.Uri, hostDocumentUri: vscode.Uri) {
this._projectedUri = projectedUri;
this._hostDocumentUri = hostDocumentUri;
}
public get projectedUri() : vscode.Uri { return this._projectedUri; }
public get hostDocumentUri() : vscode.Uri { return this._hostDocumentUri; }
public static create(hostDocumentUri: vscode.Uri): CSharpProjectedDocument {
let extensionlessPath = hostDocumentUri.path.substring(0, hostDocumentUri.path.length - 6);
let transformedPath = extensionlessPath + ".cs";
let projectedUri = vscode.Uri.parse(this.scheme + "://" + transformedPath);
return new CSharpProjectedDocument(projectedUri, hostDocumentUri);
}
}

Просмотреть файл

@ -0,0 +1,89 @@
/* --------------------------------------------------------------------------------------------
* 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 { CSharpProjectedDocument } from './CSharpProjectedDocument';
export class CSharpProjectedDocumentContentProvider implements vscode.TextDocumentContentProvider {
private _onDidChange: vscode.EventEmitter<vscode.Uri>;
private _projectedDocuments: { [hostDocumentPath: string]: CSharpProjectedDocument };
constructor () {
this._onDidChange = new vscode.EventEmitter<vscode.Uri>();
this._projectedDocuments = {};
}
public get onDidChange(): vscode.Event<vscode.Uri> {
return this._onDidChange.event;
}
public update(uri: vscode.Uri) {
this.ensureProjectedDocument(uri).then((projectedDocument) => {
this._onDidChange.fire(projectedDocument.projectedUri);
},
(reason) => {
vscode.window.showErrorMessage("For some reason we failed to open the projected document: " + reason);
});
}
public provideTextDocumentContent(uri: vscode.Uri): vscode.ProviderResult<string> {
let projectedDocument: CSharpProjectedDocument | undefined;
for (let hostDocumentPath in this._projectedDocuments) {
let document = this._projectedDocuments[hostDocumentPath];
if (document.projectedUri.path.localeCompare(uri.path, undefined, { sensitivity: 'base' }) === 0) {
projectedDocument = document;
}
}
if (!projectedDocument) {
vscode.window.showErrorMessage("For some reason the projected document isn't set.");
return;
}
let hostDocumentUriPath = projectedDocument.hostDocumentUri.path;
let hostDocument = vscode.workspace.textDocuments.find((doc) => {
if (doc.uri.path.localeCompare(hostDocumentUriPath, undefined, { sensitivity: 'base' }) === 0) {
return true;
}
return false;
});
var content = "// " + uri + "\r\n";
if (hostDocument) {
content += "\r\n" + hostDocument.getText() + "\r\n";
}
return content;
}
private async ensureProjectedDocument(hostDocumentUri: vscode.Uri): Promise<CSharpProjectedDocument> {
let projectedDocument = this._projectedDocuments[hostDocumentUri.path];
if (!projectedDocument) {
projectedDocument = CSharpProjectedDocument.create(hostDocumentUri);
this._projectedDocuments[hostDocumentUri.path] = projectedDocument;
}
await vscode.workspace.openTextDocument(projectedDocument.projectedUri);
return projectedDocument;
}
public getDocument(hostDocumentUri: vscode.Uri): Promise<CSharpProjectedDocument> {
return this.ensureProjectedDocument(hostDocumentUri);
}
public async getActiveDocument(): Promise<CSharpProjectedDocument> {
if (!vscode.window.activeTextEditor) {
throw new Error("No active text document");
}
let projectedDocument = await this.ensureProjectedDocument(vscode.window.activeTextEditor.document.uri);
return projectedDocument;
}
}

Просмотреть файл

@ -0,0 +1,50 @@
/* --------------------------------------------------------------------------------------------
* 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 { CSharpProjectedDocumentContentProvider } from './CSharpProjectedDocumentContentProvider';
import { CSharpProjectedDocument } from './CSharpProjectedDocument';
import { CSharpPreviewDocumentContentProvider } from './CSharpPreviewDocumentContentProvider';
export class RazorCSharpFeature {
private _projectionProvider: CSharpProjectedDocumentContentProvider;
private _previewProvider: CSharpPreviewDocumentContentProvider;
constructor() {
this._projectionProvider = new CSharpProjectedDocumentContentProvider();
this._previewProvider = new CSharpPreviewDocumentContentProvider(this._projectionProvider);
}
public get ProjectionProvider() : CSharpProjectedDocumentContentProvider {
return this._projectionProvider;
}
public get PreviewProvider() : CSharpPreviewDocumentContentProvider {
return this._previewProvider;
}
public async initialize(): Promise<void> {
let activeProjectedDocument = await this._projectionProvider.getActiveDocument();
this.updateDocument(activeProjectedDocument.hostDocumentUri);
}
public updateDocument(documentUri: vscode.Uri): void {
this._projectionProvider.update(documentUri);
this._previewProvider.update();
}
public register(): vscode.Disposable {
let registrations: vscode.Disposable[] = [];
registrations.push(vscode.workspace.registerTextDocumentContentProvider(CSharpProjectedDocument.scheme, this._projectionProvider));
registrations.push(vscode.workspace.registerTextDocumentContentProvider(CSharpPreviewDocumentContentProvider.scheme, this._previewProvider));
registrations.push(vscode.commands.registerCommand('extension.showRazorCSharpWindow', () => this._previewProvider.showRazorCSharpWindow()));
let disposable = vscode.Disposable.from(...registrations);
return disposable;
}
}

Просмотреть файл

@ -0,0 +1,81 @@
/* --------------------------------------------------------------------------------------------
* 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 { HtmlProjectedDocument } from './HtmlProjectedDocument';
import { HtmlProjectedDocumentContentProvider } from './HtmlProjectedDocumentContentProvider';
export class HtmlPreviewDocumentContentProvider implements vscode.TextDocumentContentProvider {
public static readonly scheme: string = HtmlProjectedDocument.scheme + "-preview";
public static readonly previewUri: vscode.Uri = vscode.Uri.parse(HtmlPreviewDocumentContentProvider.scheme + "://razor/Htmlpreview");
private _onDidChange: vscode.EventEmitter<vscode.Uri>;
private _htmlProjectionProvider: HtmlProjectedDocumentContentProvider;
constructor (HtmlContentProvider: HtmlProjectedDocumentContentProvider ) {
this._htmlProjectionProvider = HtmlContentProvider;
this._onDidChange = new vscode.EventEmitter<vscode.Uri>();
}
public get onDidChange(): vscode.Event<vscode.Uri> {
return this._onDidChange.event;
}
public update() {
let projectedDocument = this._htmlProjectionProvider.getActiveDocument();
if (!projectedDocument) {
return;
}
this._onDidChange.fire(HtmlPreviewDocumentContentProvider.previewUri);
}
public async provideTextDocumentContent(): Promise<string> {
let projectedDocument = await this._htmlProjectionProvider.getActiveDocument();
let projectedUriPath = projectedDocument.projectedUri.path;
let document = vscode.workspace.textDocuments.find((doc) => {
if (doc.uri.path.localeCompare(projectedUriPath, undefined, { sensitivity: 'base' }) === 0) {
return true;
}
return false;
});
if (document) {
let content = document.getText();
let htmlContent = `
<body>
<p>For host document: <strong>${projectedDocument.hostDocumentUri.path}</strong></p>
<hr />
<pre>
${content}
</pre>
<hr />
</body>`;
return htmlContent;
}
else {
return "<body>No content...</body>";
}
}
public async showRazorHtmlWindow(): Promise<void> {
let activeProjectedDocument = this._htmlProjectionProvider.getActiveDocument();
if (!activeProjectedDocument) {
vscode.window.showErrorMessage("No active text editor.");
return;
}
try {
await vscode.commands.executeCommand('vscode.previewHtml', HtmlPreviewDocumentContentProvider.previewUri, vscode.ViewColumn.Two, 'Razor Html Output');
}
catch (error) {
vscode.window.showErrorMessage(error);
}
}
}

Просмотреть файл

@ -0,0 +1,30 @@
/* --------------------------------------------------------------------------------------------
* 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';
export class HtmlProjectedDocument {
public static readonly scheme: string = "razor-html";
private _projectedUri : vscode.Uri;
private _hostDocumentUri : vscode.Uri;
private constructor (projectedUri: vscode.Uri, hostDocumentUri: vscode.Uri) {
this._projectedUri = projectedUri;
this._hostDocumentUri = hostDocumentUri;
}
public get projectedUri() : vscode.Uri { return this._projectedUri; }
public get hostDocumentUri() : vscode.Uri { return this._hostDocumentUri; }
public static create(hostDocumentUri: vscode.Uri): HtmlProjectedDocument {
let extensionlessPath = hostDocumentUri.path.substring(0, hostDocumentUri.path.length - 6);
let transformedPath = extensionlessPath + ".html";
let projectedUri = vscode.Uri.parse(this.scheme + "://" + transformedPath);
return new HtmlProjectedDocument(projectedUri, hostDocumentUri);
}
}

Просмотреть файл

@ -0,0 +1,90 @@
/* --------------------------------------------------------------------------------------------
* 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 { HtmlProjectedDocument } from './HtmlProjectedDocument';
export class HtmlProjectedDocumentContentProvider implements vscode.TextDocumentContentProvider {
private _onDidChange: vscode.EventEmitter<vscode.Uri>;
private _projectedDocuments: { [hostDocumentPath: string]: HtmlProjectedDocument };
constructor () {
this._onDidChange = new vscode.EventEmitter<vscode.Uri>();
this._projectedDocuments = {};
}
public get onDidChange(): vscode.Event<vscode.Uri> {
return this._onDidChange.event;
}
public update(uri: vscode.Uri) {
this.ensureProjectedDocument(uri).then((projectedDocument) => {
this._onDidChange.fire(projectedDocument.projectedUri);
},
(reason) => {
vscode.window.showErrorMessage("For some reason we failed to open the projected HTML document: " + reason);
});
}
public provideTextDocumentContent(uri: vscode.Uri): vscode.ProviderResult<string> {
let projectedDocument: HtmlProjectedDocument | undefined;
for (let hostDocumentPath in this._projectedDocuments) {
let document = this._projectedDocuments[hostDocumentPath];
if (document.projectedUri.path.localeCompare(uri.path, undefined, { sensitivity: 'base' }) === 0) {
projectedDocument = document;
}
}
if (!projectedDocument) {
vscode.window.showErrorMessage("For some reason the projected html document isn't set.");
return;
}
let hostDocumentUriPath = projectedDocument.hostDocumentUri.path;
let hostDocument = vscode.workspace.textDocuments.find((doc) => {
if (doc.uri.path.localeCompare(hostDocumentUriPath, undefined, { sensitivity: 'base' }) === 0) {
return true;
}
return false;
});
let content = "";
if (hostDocument) {
content = hostDocument.getText();
}
return content;
}
private async ensureProjectedDocument(hostDocumentUri: vscode.Uri): Promise<HtmlProjectedDocument> {
let projectedDocument = this._projectedDocuments[hostDocumentUri.path];
if (!projectedDocument) {
projectedDocument = HtmlProjectedDocument.create(hostDocumentUri);
this._projectedDocuments[hostDocumentUri.path] = projectedDocument;
}
await vscode.workspace.openTextDocument(projectedDocument.projectedUri);
return projectedDocument;
}
public getDocument(hostDocumentUri: vscode.Uri): Promise<HtmlProjectedDocument> {
return this.ensureProjectedDocument(hostDocumentUri);
}
public async getActiveDocument(): Promise<HtmlProjectedDocument> {
if (!vscode.window.activeTextEditor) {
throw new Error("No active text document");
}
let projectedDocument = await this.ensureProjectedDocument(vscode.window.activeTextEditor.document.uri);
return projectedDocument;
}
}

Просмотреть файл

@ -0,0 +1,50 @@
/* --------------------------------------------------------------------------------------------
* 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 { HtmlProjectedDocumentContentProvider } from './HtmlProjectedDocumentContentProvider';
import { HtmlPreviewDocumentContentProvider } from './HtmlPreviewDocumentContentProvider';
import { HtmlProjectedDocument } from './HtmlProjectedDocument';
export class RazorHtmlFeature {
private _projectionProvider: HtmlProjectedDocumentContentProvider;
private _previewProvider: HtmlPreviewDocumentContentProvider;
constructor() {
this._projectionProvider = new HtmlProjectedDocumentContentProvider();
this._previewProvider = new HtmlPreviewDocumentContentProvider(this._projectionProvider);
}
public get ProjectionProvider() : HtmlProjectedDocumentContentProvider {
return this._projectionProvider;
}
public get PreviewProvider() : HtmlPreviewDocumentContentProvider {
return this._previewProvider;
}
public async initialize(): Promise<void> {
let activeProjectedDocument = await this._projectionProvider.getActiveDocument();
this.updateDocument(activeProjectedDocument.hostDocumentUri);
}
public updateDocument(documentUri: vscode.Uri): void {
this._projectionProvider.update(documentUri);
this._previewProvider.update();
}
public register(): vscode.Disposable {
let registrations: vscode.Disposable[] = [];
registrations.push(vscode.workspace.registerTextDocumentContentProvider(HtmlProjectedDocument.scheme, this._projectionProvider));
registrations.push(vscode.workspace.registerTextDocumentContentProvider(HtmlPreviewDocumentContentProvider.scheme, this._previewProvider));
registrations.push(vscode.commands.registerCommand('extension.showRazorHtmlWindow', () => this._previewProvider.showRazorHtmlWindow()));
let disposable = vscode.Disposable.from(...registrations);
return disposable;
}
}

Просмотреть файл

@ -0,0 +1,14 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
export class AddProjectRequest {
constructor (filePath: string, configurationName: string) {
this.filePath = filePath;
this.configurationName = configurationName;
}
public readonly filePath: string;
public readonly configurationName: string;
}

Просмотреть файл

@ -0,0 +1,18 @@
/* --------------------------------------------------------------------------------------------
* 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';
export class LanguageQueryRequest {
constructor (hostDocumentUri: vscode.Uri, projectedCSharpDocumentUri: vscode.Uri, position: vscode.Position) {
this.hostDocumentUri = hostDocumentUri.path;
this.projectedCSharpDocumentUri = projectedCSharpDocumentUri.path;
this.hostDocumentPosition = position;
}
public readonly hostDocumentUri: string;
public readonly projectedCSharpDocumentUri: string;
public readonly hostDocumentPosition: vscode.Position;
}

Просмотреть файл

@ -0,0 +1,16 @@
/* --------------------------------------------------------------------------------------------
* 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';
export class LanguageQueryResponse {
constructor (textDocumentUri: vscode.Uri, position: vscode.Position) {
this.textDocumentUri = textDocumentUri.path;
this.position = position;
}
public readonly textDocumentUri: string;
public readonly position: vscode.Position;
}

Просмотреть файл

@ -0,0 +1,37 @@
/* --------------------------------------------------------------------------------------------
* 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 { RazorCSharpFeature } from './CSharp/RazorCSharpFeature';
import { RazorHtmlFeature } from './Html/RazorHtmlFeature';
export class RazorCompletionItemProvider implements vscode.CompletionItemProvider {
private _csharpFeature: RazorCSharpFeature;
private _htmlFeature: RazorHtmlFeature;
constructor(csharpFeature: RazorCSharpFeature, htmlFeature: RazorHtmlFeature) {
this._csharpFeature = csharpFeature;
this._htmlFeature = htmlFeature;
}
public async provideCompletionItems(document: vscode.TextDocument, position: vscode.Position, token: vscode.CancellationToken, context: vscode.CompletionContext): Promise<vscode.CompletionItem[] | vscode.CompletionList> {
let projectedDocument = await this._htmlFeature.ProjectionProvider.getDocument(document.uri);
let completionList = await vscode.commands.executeCommand<vscode.CompletionList | vscode.CompletionItem[]>(
"vscode.executeCompletionItemProvider",
projectedDocument.projectedUri,
position,
context.triggerCharacter);
if (!completionList) {
completionList = {
isIncomplete: true,
items: []
};
}
return completionList;
}
}

Просмотреть файл

@ -0,0 +1,57 @@
/* --------------------------------------------------------------------------------------------
* 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 { LanguageClient } from 'vscode-languageclient/lib/main';
// import { RazorLanguage } from './RazorLanguage';
// class RazorDocumentTracker implements vscode.Disposable {
// private _client: LanguageClient;
// constructor(client: LanguageClient) {
// this._client = client;
// }
// public dispose(): void {
// }
// private async trackCurrentDocumentsAsync() {
// for (let i = 0; i < vscode.workspace.textDocuments.length; i++) {
// let document = vscode.workspace.textDocuments[i];
// if (this.isRazorDocument(document)) {
// }
// }
// }
// private trackFutureDocuments() {
// }
// private isRazorDocument(document: vscode.TextDocument): boolean {
// if (document.languageId === RazorLanguage.id) {
// return true;
// }
// return false;
// }
// }
// export function trackRazorDocuments(client: LanguageClient): vscode.Disposable {
// let documentTracker = new RazorDocumentTracker(client);
// return documentTracker;
// }
// var projectUris = await vscode.workspace.findFiles("**/*.csproj");
// for (let i = 0; i < projectUris.length; i++) {
// let request = new AddProjectRequest(projectUris[i].fsPath, "MVC-2.0");
// await client.sendRequest<AddProjectRequest>("projects/addProject", request);
// }

Просмотреть файл

@ -0,0 +1,13 @@
/* --------------------------------------------------------------------------------------------
* 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';
export class RazorLanguage {
public static id: string = "razorcore";
public static documentSelector: vscode.DocumentSelector = [ { pattern: '**/*.razor' } ];
public static languageConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('razor');
public static serverConfig: vscode.WorkspaceConfiguration = vscode.workspace.getConfiguration('razor.languageServer');
}

Просмотреть файл

@ -0,0 +1,75 @@
/* --------------------------------------------------------------------------------------------
* 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 { LanguageClient, LanguageClientOptions, ServerOptions } from 'vscode-languageclient/lib/main';
import { RazorLanguage } from './RazorLanguage';
import { RazorLanguageServerOptions } from './RazorLanguageServerOptions';
import { EventEmitter } from 'events';
export class RazorLanguageServerClient implements vscode.Disposable {
private static Events =
{
ServerStart: "ServerStart",
ServerStop: "ServerStop"
};
private _clientOptions: LanguageClientOptions;
private _serverOptions: ServerOptions;
private _client: LanguageClient;
private _startDisposable: vscode.Disposable | undefined;
private _eventBus: EventEmitter;
constructor(options: RazorLanguageServerOptions) {
this._clientOptions = {
documentSelector: <any>RazorLanguage.documentSelector, // No idea why I need to cast here.
outputChannel: options.outputChannel
};
// TODO: Resolve dotnet path or self-host server executable
let args = [options.serverDllPath, '-lsp'];
if (options.debug) {
args[2] = "--debug";
}
this._serverOptions = {
run: { command: 'dotnet', args: args },
debug: { command: 'dotnet', args: args }
};
this._client = new LanguageClient('razorLanguageServer', 'Razor Language Server', this._serverOptions, this._clientOptions);
this._eventBus = new EventEmitter();
}
public onStart(listener: () => any): vscode.Disposable {
this._eventBus.addListener(RazorLanguageServerClient.Events.ServerStart, listener);
let disposable = new vscode.Disposable(() => this._eventBus.removeListener(RazorLanguageServerClient.Events.ServerStart, listener));
return disposable;
}
public onStop(listener: () => any): vscode.Disposable {
this._eventBus.addListener(RazorLanguageServerClient.Events.ServerStop, listener);
let disposable = new vscode.Disposable(() => this._eventBus.removeListener(RazorLanguageServerClient.Events.ServerStop, listener));
return disposable;
}
public async start(): Promise<void> {
this._startDisposable = await this._client.start();
await this._client.onReady();
this._eventBus.emit(RazorLanguageServerClient.Events.ServerStart);
}
public dispose(): void {
if (this._startDisposable) {
this._startDisposable.dispose();
}
this._eventBus.emit(RazorLanguageServerClient.Events.ServerStop);
}
}

Просмотреть файл

@ -0,0 +1,14 @@
/* --------------------------------------------------------------------------------------------
* 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 { Trace } from 'vscode-jsonrpc';
export interface RazorLanguageServerOptions {
serverDllPath: string;
outputChannel?: vscode.OutputChannel;
debug?: boolean;
trace?: Trace;
}

Просмотреть файл

@ -0,0 +1,45 @@
/* --------------------------------------------------------------------------------------------
* 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 { Trace } from 'vscode-jsonrpc';
import { RazorLanguage } from './RazorLanguage';
import { RazorLanguageServerOptions } from './RazorLanguageServerOptions';
export function resolveRazorLanguageServerOptions(): RazorLanguageServerOptions {
let languageServerDllPath = RazorLanguage.serverConfig.get<string>("path");
if (!languageServerDllPath) {
throw new Error("Razor VSCode extension does not currently support dynamic resolution of language server.");
}
let debugLanguageServer = RazorLanguage.serverConfig.get<boolean>("debug");
let outputChannel = vscode.window.createOutputChannel("Razor Language Server");
let traceString = RazorLanguage.serverConfig.get<string>("trace");
let trace: Trace;
if (traceString === "Off") {
trace = Trace.Off;
}
else if (traceString === "Messages") {
trace = Trace.Messages;
}
else if (traceString === "Verbose") {
trace = Trace.Verbose;
}
else {
console.log("Invalid trace settign for Razor language server. Defaulting to 'Off'");
trace = Trace.Off;
}
let options: RazorLanguageServerOptions = {
serverDllPath: languageServerDllPath,
debug: debugLanguageServer,
outputChannel: outputChannel,
trace: trace
};
return options;
}

Просмотреть файл

@ -1,37 +1,47 @@
'use strict';
// The module 'vscode' contains the VS Code extensibility API
// Import the module and reference it with the alias vscode in your code below
/* --------------------------------------------------------------------------------------------
* 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 { ExtensionContext } from 'vscode';
import { RazorLanguage } from './RazorLanguage';
import { resolveRazorLanguageServerOptions } from './RazorLanguageServerOptionsResolver';
import { RazorLanguageServerClient } from './RazorLanguageServerClient';
import { RazorCSharpFeature } from './CSharp/RazorCSharpFeature';
import { RazorHtmlFeature } from './Html/RazorHtmlFeature';
import { RazorCompletionItemProvider } from './RazorCompletionItemProvider';
// this method is called when your extension is activated
// your extension is activated the very first time the command is executed
export function activate(context: vscode.ExtensionContext) {
export async function activate(context: ExtensionContext) {
let languageServerOptions = resolveRazorLanguageServerOptions();
let languageServerClient = new RazorLanguageServerClient(languageServerOptions);
let csharpFeature = new RazorCSharpFeature();
let htmlFeature = new RazorHtmlFeature();
let localRegistrations: vscode.Disposable[] = [];
// Use the console to output diagnostic information (console.log) and errors (console.error)
// This line of code will only be executed once when your extension is activated
console.log('Congratulations, your extension "helloworld" is now active!');
let onStartRegistration = languageServerClient.onStart(() => {
localRegistrations.push(vscode.languages.registerCompletionItemProvider(RazorLanguage.id, new RazorCompletionItemProvider(csharpFeature, htmlFeature)));
localRegistrations.push(csharpFeature.register());
localRegistrations.push(htmlFeature.register());
// The command has been defined in the package.json file
// Now provide the implementation of the command with registerCommand
// The commandId parameter must match the command field in package.json
let disposable = vscode.commands.registerCommand('extension.sayHello', () => {
// The code you place here will be executed every time your command is executed
let editor = vscode.window.activeTextEditor;
if (!editor) {
return; // No open text editor
}
let selection = editor.selection;
let text = editor.document.getText(selection);
// Display a message box to the user
vscode.window.showInformationMessage('Selected characters: ' + text.length);
localRegistrations.push(vscode.workspace.onDidChangeTextDocument((args: vscode.TextDocumentChangeEvent) => {
if (vscode.window.activeTextEditor && args.document === vscode.window.activeTextEditor.document) {
csharpFeature.updateDocument(args.document.uri);
htmlFeature.updateDocument(args.document.uri);
}
}));
});
context.subscriptions.push(disposable);
}
let onStopRegistration = languageServerClient.onStop(() => {
for (let i = 0; i < localRegistrations.length; i++) {
localRegistrations[i].dispose();
}
localRegistrations.length = 0;
});
// this method is called when your extension is deactivated
export function deactivate() {
await languageServerClient.start();
await csharpFeature.initialize();
await htmlFeature.initialize();
context.subscriptions.push(languageServerClient, onStartRegistration, onStopRegistration);
}

1
modules/Razor Submodule

@ -0,0 +1 @@
Subproject commit 94a131414627d4eda52d1ffd6649277134f906a3

@ -1 +1 @@
Subproject commit d3468c2380f9a2b364d658b68107238eaaf7ecf7
Subproject commit a5cdb62fd5714e778b90241656d0786180b26c5c

Просмотреть файл

@ -0,0 +1,51 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
internal class DefaultDocumentSnapshotShim : DocumentSnapshotShim
{
private readonly DocumentSnapshot _snapshot;
public DefaultDocumentSnapshotShim(DocumentSnapshot snapshot)
{
_snapshot = snapshot;
}
public override string FilePath => _snapshot.FilePath;
public override string TargetPath => _snapshot.TargetPath;
public override Task<RazorCodeDocument> GetGeneratedOutputAsync() => _snapshot.GetGeneratedOutputAsync();
public override IReadOnlyList<DocumentSnapshotShim> GetImports()
{
var imports = new List<DocumentSnapshotShim>();
var innerImports = _snapshot.GetImports();
for (var i = 0; i < innerImports.Count; i++)
{
imports.Add(new DefaultDocumentSnapshotShim(innerImports[i]));
}
return imports;
}
public override Task<SourceText> GetTextAsync() => _snapshot.GetTextAsync();
public override Task<VersionStamp> GetTextVersionAsync() => _snapshot.GetTextVersionAsync();
public override bool TryGetGeneratedOutput(out RazorCodeDocument result) => _snapshot.TryGetGeneratedOutput(out result);
public override bool TryGetText(out SourceText result) => _snapshot.TryGetText(out result);
public override bool TryGetTextVersion(out VersionStamp result) => _snapshot.TryGetTextVersion(out result);
}
}

Просмотреть файл

@ -0,0 +1,35 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
internal class DefaultForegroundDispatcherShim : ForegroundDispatcherShim
{
private readonly ForegroundDispatcher _foregroundDispatcher;
public DefaultForegroundDispatcherShim(ForegroundDispatcher foregroundDispatcher)
{
if (foregroundDispatcher == null)
{
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
_foregroundDispatcher = foregroundDispatcher;
}
public override bool IsForegroundThread => _foregroundDispatcher.IsForegroundThread;
public override TaskScheduler ForegroundScheduler => _foregroundDispatcher.ForegroundScheduler;
public override TaskScheduler BackgroundScheduler => _foregroundDispatcher.BackgroundScheduler;
public override void AssertForegroundThread([CallerMemberName] string caller = null) => _foregroundDispatcher.AssertForegroundThread(caller);
public override void AssertBackgroundThread([CallerMemberName] string caller = null) => _foregroundDispatcher.AssertBackgroundThread(caller);
}
}

Просмотреть файл

@ -0,0 +1,27 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
internal class DefaultHostDocumentShim : HostDocumentShim
{
public DefaultHostDocumentShim(HostDocument hostDocument)
{
if (hostDocument == null)
{
throw new ArgumentNullException(nameof(hostDocument));
}
InnerHostDocument = hostDocument;
}
public HostDocument InnerHostDocument { get; }
public override string FilePath => InnerHostDocument.FilePath;
public override string TargetPath => InnerHostDocument.TargetPath;
}
}

Просмотреть файл

@ -0,0 +1,28 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
internal class DefaultHostProjectShim : HostProjectShim
{
public DefaultHostProjectShim(HostProject hostProject)
{
if (hostProject == null)
{
throw new ArgumentNullException(nameof(hostProject));
}
InnerHostProject = hostProject;
}
public HostProject InnerHostProject { get; }
public override RazorConfiguration Configuration => InnerHostProject.Configuration;
public override string FilePath => InnerHostProject.FilePath;
}
}

Просмотреть файл

@ -0,0 +1,171 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
internal class DefaultProjectSnapshotManagerShim : ProjectSnapshotManagerShim
{
public DefaultProjectSnapshotManagerShim(ProjectSnapshotManagerBase projectSnapshotManager)
{
if (projectSnapshotManager == null)
{
throw new ArgumentNullException(nameof(projectSnapshotManager));
}
InnerProjectSnapshotManager = projectSnapshotManager;
InnerProjectSnapshotManager.Changed += OnInnerSnapshotManagerChanged;
}
public ProjectSnapshotManagerBase InnerProjectSnapshotManager { get; }
public override IReadOnlyList<ProjectSnapshotShim> Projects
{
get
{
var projects = new List<ProjectSnapshotShim>();
for (var i = 0; i < InnerProjectSnapshotManager.Projects.Count; i++)
{
var projectShim = new DefaultProjectSnapshotShim(InnerProjectSnapshotManager.Projects[i]);
projects.Add(projectShim);
}
return projects;
}
}
public override Workspace Workspace => InnerProjectSnapshotManager.Workspace;
#pragma warning disable 67
public override event EventHandler<ProjectChangeEventArgsShim> Changed;
#pragma warning restore 67
public override void DocumentAdded(HostProjectShim hostProject, HostDocumentShim hostDocument, TextLoader textLoader)
{
if (!(hostProject is DefaultHostProjectShim defaultHostProject))
{
throw new ArgumentException("Cannot understand non-default implementations of host project.");
}
if (!(hostDocument is DefaultHostDocumentShim defaultHostDocument))
{
throw new ArgumentException("Cannot understand non-default implementations of host document.");
}
InnerProjectSnapshotManager.DocumentAdded(defaultHostProject.InnerHostProject, defaultHostDocument.InnerHostDocument, textLoader);
}
public override void DocumentChanged(string projectFilePath, string documentFilePath, TextLoader textLoader) => InnerProjectSnapshotManager.DocumentChanged(projectFilePath, documentFilePath, textLoader);
public override void DocumentChanged(string projectFilePath, string documentFilePath, SourceText sourceText) => InnerProjectSnapshotManager.DocumentChanged(projectFilePath, documentFilePath, sourceText);
public override void DocumentClosed(string projectFilePath, string documentFilePath, TextLoader textLoader) => InnerProjectSnapshotManager.DocumentClosed(projectFilePath, documentFilePath, textLoader);
public override void DocumentOpened(string projectFilePath, string documentFilePath, SourceText sourceText) => InnerProjectSnapshotManager.DocumentOpened(projectFilePath, documentFilePath, sourceText);
public override void DocumentRemoved(HostProjectShim hostProject, HostDocumentShim hostDocument)
{
if (!(hostProject is DefaultHostProjectShim defaultHostProject))
{
throw new ArgumentException("Cannot understand non-default implementations of host project.");
}
if (!(hostDocument is DefaultHostDocumentShim defaultHostDocument))
{
throw new ArgumentException("Cannot understand non-default implementations of host document.");
}
InnerProjectSnapshotManager.DocumentRemoved(defaultHostProject.InnerHostProject, defaultHostDocument.InnerHostDocument);
}
public override ProjectSnapshotShim GetLoadedProject(string filePath)
{
var loadedProject = InnerProjectSnapshotManager.GetLoadedProject(filePath);
return new DefaultProjectSnapshotShim(loadedProject);
}
public override ProjectSnapshotShim GetOrCreateProject(string filePath)
{
var project = InnerProjectSnapshotManager.GetOrCreateProject(filePath);
return new DefaultProjectSnapshotShim(project);
}
public override void HostProjectAdded(HostProjectShim hostProject)
{
if (!(hostProject is DefaultHostProjectShim defaultHostProject))
{
throw new ArgumentException("Cannot understand non-default implementations of host project.");
}
InnerProjectSnapshotManager.HostProjectAdded(defaultHostProject.InnerHostProject);
}
public override void HostProjectChanged(HostProjectShim hostProject)
{
if (!(hostProject is DefaultHostProjectShim defaultHostProject))
{
throw new ArgumentException("Cannot understand non-default implementations of host project.");
}
InnerProjectSnapshotManager.HostProjectChanged(defaultHostProject.InnerHostProject);
}
public override void HostProjectRemoved(HostProjectShim hostProject)
{
if (!(hostProject is DefaultHostProjectShim defaultHostProject))
{
throw new ArgumentException("Cannot understand non-default implementations of host project.");
}
InnerProjectSnapshotManager.HostProjectRemoved(defaultHostProject.InnerHostProject);
}
public override bool IsDocumentOpen(string documentFilePath) => InnerProjectSnapshotManager.IsDocumentOpen(documentFilePath);
public override void ReportError(Exception exception) => InnerProjectSnapshotManager.ReportError(exception);
public override void ReportError(Exception exception, ProjectSnapshotShim project)
{
if (!(project is DefaultProjectSnapshotShim defaultProjectSnapshot))
{
throw new ArgumentException("Cannot understand non-default implementations of project snapshot.");
}
InnerProjectSnapshotManager.ReportError(exception, defaultProjectSnapshot.InnerProjectSnapshot);
}
public override void ReportError(Exception exception, HostProjectShim hostProject)
{
if (!(hostProject is DefaultHostProjectShim defaultHostProject))
{
throw new ArgumentException("Cannot understand non-default implementations of host project.");
}
InnerProjectSnapshotManager.ReportError(exception, defaultHostProject.InnerHostProject);
}
public override void ReportError(Exception exception, Project workspaceProject) => InnerProjectSnapshotManager.ReportError(exception, workspaceProject);
public override void WorkspaceProjectAdded(Project workspaceProject) => InnerProjectSnapshotManager.WorkspaceProjectAdded(workspaceProject);
public override void WorkspaceProjectChanged(Project workspaceProject) => InnerProjectSnapshotManager.WorkspaceProjectChanged(workspaceProject);
public override void WorkspaceProjectRemoved(Project workspaceProject) => InnerProjectSnapshotManager.WorkspaceProjectRemoved(workspaceProject);
private void OnInnerSnapshotManagerChanged(object sender, ProjectChangeEventArgs args)
{
var shimArgs = new ProjectChangeEventArgsShim(args.ProjectFilePath, args.DocumentFilePath, (ProjectChangeKindShim)args.Kind);
Changed?.Invoke(this, shimArgs);
}
}
}

Просмотреть файл

@ -0,0 +1,55 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Linq;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
internal class DefaultProjectSnapshotManagerShimAccessor : ProjectSnapshotManagerShimAccessor
{
private readonly ForegroundDispatcher _foregroundDispatcher;
private readonly ErrorReporter _errorReporter;
private ProjectSnapshotManagerShim _instance;
public DefaultProjectSnapshotManagerShimAccessor(
ForegroundDispatcher foregroundDispatcher,
ErrorReporter errorReporter)
{
if (foregroundDispatcher == null)
{
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
if (errorReporter == null)
{
throw new ArgumentNullException(nameof(errorReporter));
}
_foregroundDispatcher = foregroundDispatcher;
_errorReporter = errorReporter;
}
public override ProjectSnapshotManagerShim Instance
{
get
{
if (_instance == null)
{
var workspace = new AdhocWorkspace();
var projectSnapshotManager = new DefaultProjectSnapshotManager(
_foregroundDispatcher,
_errorReporter,
Enumerable.Empty<ProjectSnapshotChangeTrigger>(),
workspace);
_instance = new DefaultProjectSnapshotManagerShim(projectSnapshotManager);
}
return _instance;
}
}
}
}

Просмотреть файл

@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
internal class DefaultProjectSnapshotShim : ProjectSnapshotShim
{
public DefaultProjectSnapshotShim(ProjectSnapshot projectSnapshot)
{
if (projectSnapshot == null)
{
throw new ArgumentNullException(nameof(projectSnapshot));
}
InnerProjectSnapshot = projectSnapshot;
}
public ProjectSnapshot InnerProjectSnapshot { get; }
public override HostProjectShim HostProject
{
get
{
if (InnerProjectSnapshot is DefaultProjectSnapshot defaultSnapshot)
{
new DefaultHostProjectShim(defaultSnapshot.HostProject);
}
return null;
}
}
public override RazorConfiguration Configuration => InnerProjectSnapshot.Configuration;
public override IEnumerable<string> DocumentFilePaths => InnerProjectSnapshot.DocumentFilePaths;
public override string FilePath => InnerProjectSnapshot.FilePath;
public override bool IsInitialized => InnerProjectSnapshot.IsInitialized;
public override VersionStamp Version => InnerProjectSnapshot.Version;
public override Project WorkspaceProject => InnerProjectSnapshot.WorkspaceProject;
public override DocumentSnapshotShim GetDocument(string filePath)
{
var document = InnerProjectSnapshot.GetDocument(filePath);
return new DefaultDocumentSnapshotShim(document);
}
public override RazorProjectEngine GetProjectEngine() => InnerProjectSnapshot.GetProjectEngine();
public override Task<IReadOnlyList<TagHelperDescriptor>> GetTagHelpersAsync() => InnerProjectSnapshot.GetTagHelpersAsync();
public override bool TryGetTagHelpers(out IReadOnlyList<TagHelperDescriptor> result) => InnerProjectSnapshot.TryGetTagHelpers(out result);
}
}

Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
internal class DefaultRazorConfigurationResolver : RazorConfigurationResolver
{
private static readonly IReadOnlyDictionary<string, RazorConfiguration> SupportedConfigurations = new Dictionary<string, RazorConfiguration>(StringComparer.OrdinalIgnoreCase)
{
[FallbackRazorConfiguration.MVC_1_0.ConfigurationName] = FallbackRazorConfiguration.MVC_1_0,
[FallbackRazorConfiguration.MVC_1_1.ConfigurationName] = FallbackRazorConfiguration.MVC_1_1,
[FallbackRazorConfiguration.MVC_2_0.ConfigurationName] = FallbackRazorConfiguration.MVC_2_0,
[FallbackRazorConfiguration.MVC_2_1.ConfigurationName] = FallbackRazorConfiguration.MVC_2_1,
};
public override bool TryResolve(string configurationName, out RazorConfiguration configuration)
{
if (configurationName == null)
{
throw new ArgumentNullException(nameof(configurationName));
}
if (SupportedConfigurations.TryGetValue(configurationName, out configuration))
{
return true;
}
return false;
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public abstract class DocumentSnapshotShim
{
public abstract string FilePath { get; }
public abstract string TargetPath { get; }
public abstract IReadOnlyList<DocumentSnapshotShim> GetImports();
public abstract Task<SourceText> GetTextAsync();
public abstract Task<VersionStamp> GetTextVersionAsync();
public abstract Task<RazorCodeDocument> GetGeneratedOutputAsync();
public abstract bool TryGetText(out SourceText result);
public abstract bool TryGetTextVersion(out VersionStamp result);
public abstract bool TryGetGeneratedOutput(out RazorCodeDocument result);
}
}

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public abstract class ForegroundDispatcherShim
{
public abstract bool IsForegroundThread { get; }
public abstract TaskScheduler ForegroundScheduler { get; }
public abstract TaskScheduler BackgroundScheduler { get; }
public abstract void AssertForegroundThread([CallerMemberName] string caller = null);
public abstract void AssertBackgroundThread([CallerMemberName] string caller = null);
}
}

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public abstract class HostDocumentShim
{
public abstract string FilePath { get; }
public abstract string TargetPath { get; }
public static HostDocumentShim Create(string filePath, string targetPath)
{
var hostDocument = new HostDocument(filePath, targetPath);
var hostDocumentShim = new DefaultHostDocumentShim(hostDocument);
return hostDocumentShim;
}
}
}

Просмотреть файл

@ -0,0 +1,32 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public abstract class HostProjectShim
{
public abstract RazorConfiguration Configuration { get; }
public abstract string FilePath { get; }
public static HostProjectShim Create(string filePath, RazorConfiguration configuration)
{
if (filePath == null)
{
throw new ArgumentNullException(nameof(filePath));
}
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
var hostProject = new HostProject(filePath, configuration);
return new DefaultHostProjectShim(hostProject);
}
}
}

Просмотреть файл

@ -0,0 +1,23 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.Extensions.DependencyInjection;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
public static class IServiceCollectionExtensions
{
public static IServiceCollection AddRazorShims(this IServiceCollection services)
{
services.AddSingleton<ForegroundDispatcher, VSCodeForegroundDispatcher>();
services.AddSingleton<ForegroundDispatcherShim, DefaultForegroundDispatcherShim>();
services.AddSingleton<ErrorReporter, DefaultErrorReporter>();
services.AddSingleton<ProjectSnapshotManagerShimAccessor, DefaultProjectSnapshotManagerShimAccessor>();
services.AddSingleton<RazorConfigurationResolver, DefaultRazorConfigurationResolver>();
return services;
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Description>Temporary assembly until the csharp language server is strong name signed.</Description>
<EnableApiCheck>false</EnableApiCheck>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\modules\Razor\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="$(MicrosoftExtensionsDependencyInjectionAbstractionsPackageVersion)" />
</ItemGroup>
</Project>

Просмотреть файл

@ -0,0 +1,39 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public class ProjectChangeEventArgsShim : EventArgs
{
public ProjectChangeEventArgsShim(string projectFilePath, ProjectChangeKindShim kind)
{
if (projectFilePath == null)
{
throw new ArgumentNullException(nameof(projectFilePath));
}
ProjectFilePath = projectFilePath;
Kind = kind;
}
public ProjectChangeEventArgsShim(string projectFilePath, string documentFilePath, ProjectChangeKindShim kind)
{
if (projectFilePath == null)
{
throw new ArgumentNullException(nameof(projectFilePath));
}
ProjectFilePath = projectFilePath;
DocumentFilePath = documentFilePath;
Kind = kind;
}
public string ProjectFilePath { get; }
public string DocumentFilePath { get; }
public ProjectChangeKindShim Kind { get; }
}
}

Просмотреть файл

@ -0,0 +1,17 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public enum ProjectChangeKindShim
{
ProjectAdded,
ProjectRemoved,
ProjectChanged,
DocumentAdded,
DocumentRemoved,
// This could be a state change (opened/closed) or a content change.
DocumentChanged,
}
}

Просмотреть файл

@ -0,0 +1,58 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public abstract class ProjectSnapshotManagerShim
{
public abstract event EventHandler<ProjectChangeEventArgsShim> Changed;
public abstract IReadOnlyList<ProjectSnapshotShim> Projects { get; }
public abstract bool IsDocumentOpen(string documentFilePath);
public abstract ProjectSnapshotShim GetLoadedProject(string filePath);
public abstract ProjectSnapshotShim GetOrCreateProject(string filePath);
public abstract Workspace Workspace { get; }
public abstract void DocumentAdded(HostProjectShim hostProject, HostDocumentShim hostDocument, TextLoader textLoader);
public abstract void DocumentOpened(string projectFilePath, string documentFilePath, SourceText sourceText);
public abstract void DocumentClosed(string projectFilePath, string documentFilePath, TextLoader textLoader);
public abstract void DocumentChanged(string projectFilePath, string documentFilePath, TextLoader textLoader);
public abstract void DocumentChanged(string projectFilePath, string documentFilePath, SourceText sourceText);
public abstract void DocumentRemoved(HostProjectShim hostProject, HostDocumentShim hostDocument);
public abstract void HostProjectAdded(HostProjectShim hostProject);
public abstract void HostProjectChanged(HostProjectShim hostProject);
public abstract void HostProjectRemoved(HostProjectShim hostProject);
public abstract void WorkspaceProjectAdded(Project workspaceProject);
public abstract void WorkspaceProjectChanged(Project workspaceProject);
public abstract void WorkspaceProjectRemoved(Project workspaceProject);
public abstract void ReportError(Exception exception);
public abstract void ReportError(Exception exception, ProjectSnapshotShim project);
public abstract void ReportError(Exception exception, HostProjectShim hostProject);
public abstract void ReportError(Exception exception, Project workspaceProject);
}
}

Просмотреть файл

@ -0,0 +1,10 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public abstract class ProjectSnapshotManagerShimAccessor
{
public abstract ProjectSnapshotManagerShim Instance { get; }
}
}

Просмотреть файл

@ -0,0 +1,36 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public abstract class ProjectSnapshotShim
{
public abstract HostProjectShim HostProject { get; }
public abstract RazorConfiguration Configuration { get; }
public abstract IEnumerable<string> DocumentFilePaths { get; }
public abstract string FilePath { get; }
public abstract bool IsInitialized { get; }
public abstract VersionStamp Version { get; }
public abstract Project WorkspaceProject { get; }
public abstract RazorProjectEngine GetProjectEngine();
public abstract DocumentSnapshotShim GetDocument(string filePath);
public abstract Task<IReadOnlyList<TagHelperDescriptor>> GetTagHelpersAsync();
public abstract bool TryGetTagHelpers(out IReadOnlyList<TagHelperDescriptor> result);
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
public abstract class RazorConfigurationResolver
{
public abstract bool TryResolve(string configurationName, out RazorConfiguration configuration);
}
}

Просмотреть файл

@ -0,0 +1,57 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed
{
internal class VSCodeForegroundDispatcher : ForegroundDispatcher
{
public override bool IsForegroundThread => Thread.CurrentThread.ManagedThreadId == ForegroundTaskScheduler.Instance.ForegroundThreadId;
public override TaskScheduler ForegroundScheduler { get; } = ForegroundTaskScheduler.Instance;
public override TaskScheduler BackgroundScheduler { get; } = TaskScheduler.Default;
internal class ForegroundTaskScheduler : TaskScheduler
{
public static ForegroundTaskScheduler Instance = new ForegroundTaskScheduler();
private readonly Thread _thread;
private readonly BlockingCollection<Task> _tasks = new BlockingCollection<Task>();
private ForegroundTaskScheduler()
{
_thread = new Thread(ThreadStart)
{
IsBackground = true,
};
_thread.Start();
}
public int ForegroundThreadId => _thread.ManagedThreadId;
public override int MaximumConcurrencyLevel => 1;
protected override void QueueTask(Task task) => _tasks.Add(task);
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => TryExecuteTask(task);
protected override IEnumerable<Task> GetScheduledTasks() => _tasks.ToArray();
private void ThreadStart()
{
while (true)
{
var task = _tasks.Take();
TryExecuteTask(task);
}
}
}
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using OmniSharp.Extensions.JsonRpc;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
[Parallel, Method("razor/languageDocumentQuery")]
public interface IRazorLanguageQueryHandler : IJsonRpcRequestHandler<RazorLanguageQueryParams, RazorLanguageQueryResponse>
{
}
}

Просмотреть файл

@ -0,0 +1,56 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
public abstract class LanguageServerHandlerBase
{
private readonly ILanguageServer _router;
private static string LastLogType = string.Empty;
public LanguageServerHandlerBase(ILanguageServer router)
{
if (router == null)
{
throw new ArgumentNullException(nameof(router));
}
_router = router;
}
protected void LogToClient(string message)
{
var messageBuilder = new StringBuilder();
var typeName = GetType().Name;
lock (LastLogType)
{
if (LastLogType != typeName)
{
LastLogType = typeName;
messageBuilder
.AppendLine()
.AppendLine(typeName);
}
}
messageBuilder
.Append(" ")
.Append(DateTime.Now.ToString("HH:mm:ss"))
.Append("\t\t")
.Append(message);
_router.Window.LogMessage(new LogMessageParams()
{
Type = MessageType.Log,
Message = messageBuilder.ToString()
});
}
}
}

Просмотреть файл

@ -10,6 +10,7 @@
<ItemGroup>
<ProjectReference Include="..\..\modules\csharp-language-server-protocol\src\Server\Server.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed\Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed.csproj" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,6 +1,11 @@
using System;
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.LanguageServer.Projects;
using Microsoft.Extensions.Logging;
using OmniSharp.Extensions.LanguageServer.Server;
@ -15,6 +20,19 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
public static async Task MainAsync(string[] args)
{
for (var i = 0; i < args.Length; i++)
{
if (args[i].IndexOf("debug", StringComparison.OrdinalIgnoreCase) >= 0)
{
while (!Debugger.IsAttached)
{
Thread.Sleep(1000);
}
break;
}
}
var server = await OmniSharp.Extensions.LanguageServer.Server.LanguageServer.From(options =>
options
.WithInput(Console.OpenStandardInput())
@ -22,7 +40,11 @@ namespace Microsoft.AspNetCore.Razor.LanguageServer
.WithLoggerFactory(new LoggerFactory())
.AddDefaultLoggingProvider()
.WithMinimumLogLevel(LogLevel.Trace)
.WithHandler<TextDocumentHandler>());
.WithHandler<RazorDocumentSynchronizationHandler>()
.WithHandler<RazorCompletionHandler>()
.WithHandler<RazorLanguageService>()
.WithHandler<RazorProjectService>()
.WithServices(services => services.AddRazorShims()));
await server.WaitForExit;
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using OmniSharp.Extensions.JsonRpc;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Projects
{
[Parallel, Method("projects/addDocument")]
public interface IRazorAddDocumentHandler : IJsonRpcNotificationHandler<RazorAddDocumentParams>
{
}
}

Просмотреть файл

@ -0,0 +1,12 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using OmniSharp.Extensions.JsonRpc;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Projects
{
[Parallel, Method("projects/addProject")]
public interface IRazorAddProjectHandler : IJsonRpcNotificationHandler<RazorAddProjectParams>
{
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using MediatR;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Projects
{
public class RazorAddDocumentParams : IRequest
{
public TextDocumentItem TextDocument { get; set; }
public string ProjectFilePath { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,14 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using MediatR;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Projects
{
public class RazorAddProjectParams : IRequest
{
public string FilePath { get; set; }
public string ConfigurationName { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,107 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Projects
{
internal class RazorProjectService : LanguageServerHandlerBase, IRazorAddProjectHandler, IRazorAddDocumentHandler
{
private readonly ProjectSnapshotManagerShimAccessor _projectSnapshotManagerAccessor;
private readonly RazorConfigurationResolver _configurationResolver;
private readonly ForegroundDispatcherShim _foregroundDispatcher;
public RazorProjectService(
ProjectSnapshotManagerShimAccessor projectSnapshotManagerAccessor,
RazorConfigurationResolver configurationResolver,
ForegroundDispatcherShim foregroundDispatcher,
ILanguageServer router) : base(router)
{
if (projectSnapshotManagerAccessor == null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerAccessor));
}
if (configurationResolver == null)
{
throw new ArgumentNullException(nameof(configurationResolver));
}
if (foregroundDispatcher == null)
{
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
_projectSnapshotManagerAccessor = projectSnapshotManagerAccessor;
_configurationResolver = configurationResolver;
_foregroundDispatcher = foregroundDispatcher;
}
public async Task<Unit> Handle(RazorAddProjectParams notification, CancellationToken cancellationToken)
{
if (notification == null)
{
throw new ArgumentNullException(nameof(notification));
}
if (!_configurationResolver.TryResolve(notification.ConfigurationName, out var razorConfiguration))
{
LogToClient($"Could not resolve Razor configuration '{notification.ConfigurationName}'. Falling back to default.");
razorConfiguration = RazorConfiguration.Default;
}
await AddProjectOnForegroundAsync(notification, razorConfiguration);
return Unit.Value;
}
public async Task<Unit> Handle(RazorAddDocumentParams notification, CancellationToken cancellationToken)
{
if (notification == null)
{
throw new ArgumentNullException(nameof(notification));
}
await AddDocumentOnForegroundAsync(notification.ProjectFilePath, notification.TextDocument);
return Unit.Value;
}
private Task AddDocumentOnForegroundAsync(string projectFilePath, TextDocumentItem textDocument)
{
return Task.Factory.StartNew(() =>
{
var projectSnapshot = _projectSnapshotManagerAccessor.Instance.GetLoadedProject(projectFilePath);
if (projectSnapshot == null)
{
// No active project to track the document. Treat this as a misc Razor file.
return;
}
var hostDocument = HostDocumentShim.Create(textDocument.Uri.AbsolutePath, textDocument.Uri.AbsolutePath);
var sourceText = SourceText.From(textDocument.Text);
var textAndVersion = TextAndVersion.Create(sourceText, VersionStamp.Default);
var textLoader = TextLoader.From(textAndVersion);
_projectSnapshotManagerAccessor.Instance.DocumentAdded(projectSnapshot.HostProject, hostDocument, textLoader);
}, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler);
}
private Task AddProjectOnForegroundAsync(RazorAddProjectParams notification, RazorConfiguration razorConfiguration)
{
return Task.Factory.StartNew(() =>
{
var hostProject = HostProjectShim.Create(notification.FilePath, razorConfiguration);
_projectSnapshotManagerAccessor.Instance.HostProjectAdded(hostProject);
}, CancellationToken.None, TaskCreationOptions.None, _foregroundDispatcher.ForegroundScheduler);
}
}
}

Просмотреть файл

@ -0,0 +1,60 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
public class RazorCompletionHandler : LanguageServerHandlerBase, ICompletionHandler
{
private CompletionCapability _capability;
public RazorCompletionHandler(ILanguageServer router) : base(router)
{
}
public void SetCapability(CompletionCapability capability)
{
LogToClient("Setting capability");
_capability = capability;
}
public Task<CompletionList> Handle(CompletionParams request, CancellationToken cancellationToken)
{
LogToClient("Handling completion request.");
var completionItems = new List<CompletionItem>()
{
new CompletionItem()
{
Label = "taylor",
InsertText = "taylor",
Detail = "The taylor directive.",
Documentation = "The taylor directive which is awesome.",
FilterText = "taylor",
SortText = "Taylor",
Kind = CompletionItemKind.Text
}
};
var completionList = new CompletionList(completionItems, isIncomplete: true);
return Task.FromResult(completionList);
}
public CompletionRegistrationOptions GetRegistrationOptions()
{
return new CompletionRegistrationOptions()
{
DocumentSelector = RazorDocument.Selector,
ResolveProvider = true,
};
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
public static class RazorDocument
{
public static DocumentSelector Selector { get; } = new DocumentSelector(
new DocumentFilter()
{
Pattern = "**/*.razor"
});
}
}

Просмотреть файл

@ -0,0 +1,109 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
using MediatR;
using Microsoft.AspNetCore.Razor.LanguageServer.StrongNamed;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using OmniSharp.Extensions.LanguageServer.Protocol.Server.Capabilities;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
public class RazorDocumentSynchronizationHandler : LanguageServerHandlerBase, ITextDocumentSyncHandler
{
private SynchronizationCapability _capability;
private readonly ProjectSnapshotManagerShimAccessor _projectSnapshotManagerAccessor;
public RazorDocumentSynchronizationHandler(
ILanguageServer router,
ProjectSnapshotManagerShimAccessor projectSnapshotManagerAccessor) : base(router)
{
if (router == null)
{
throw new ArgumentNullException(nameof(router));
}
if (projectSnapshotManagerAccessor == null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerAccessor));
}
_projectSnapshotManagerAccessor = projectSnapshotManagerAccessor;
}
public TextDocumentSyncKind Change { get; } = TextDocumentSyncKind.Incremental;
public void SetCapability(SynchronizationCapability capability)
{
LogToClient("Setting Capability");
_capability = capability;
}
public Task<Unit> Handle(DidChangeTextDocumentParams notification, CancellationToken token)
{
LogToClient("Changed Document");
return Unit.Task;
}
public Task<Unit> Handle(DidOpenTextDocumentParams notification, CancellationToken token)
{
LogToClient("Opened Document");
return Unit.Task;
}
public Task<Unit> Handle(DidCloseTextDocumentParams notification, CancellationToken token)
{
LogToClient("Closed Document");
return Unit.Task;
}
public Task<Unit> Handle(DidSaveTextDocumentParams notification, CancellationToken token)
{
LogToClient("Saved Document");
return Unit.Task;
}
public TextDocumentAttributes GetTextDocumentAttributes(Uri uri)
{
LogToClient("Asked for attributes");
return new TextDocumentAttributes(uri, "razor");
}
TextDocumentChangeRegistrationOptions IRegistration<TextDocumentChangeRegistrationOptions>.GetRegistrationOptions()
{
return new TextDocumentChangeRegistrationOptions()
{
DocumentSelector = RazorDocument.Selector,
SyncKind = Change
};
}
TextDocumentRegistrationOptions IRegistration<TextDocumentRegistrationOptions>.GetRegistrationOptions()
{
return new TextDocumentRegistrationOptions()
{
DocumentSelector = RazorDocument.Selector,
};
}
TextDocumentSaveRegistrationOptions IRegistration<TextDocumentSaveRegistrationOptions>.GetRegistrationOptions()
{
return new TextDocumentSaveRegistrationOptions()
{
DocumentSelector = RazorDocument.Selector,
IncludeText = true
};
}
}
}

Просмотреть файл

@ -0,0 +1,21 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using MediatR;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
public class RazorLanguageQueryParams : IRequest<RazorLanguageQueryResponse>
{
public Uri HostDocumentUri { get; set; }
public Uri ProjectedCSharpDocumentUri { get; set; }
// TODO: Not implemented on client.
public Uri ProjectedHtmlDocumentUri { get; set; }
public Position HostDocumentPosition { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,15 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
public class RazorLanguageQueryResponse
{
public Uri TextDocumentUri { get; set; }
public Position Position { get; set; }
}
}

Просмотреть файл

@ -0,0 +1,22 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Threading;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
internal class RazorLanguageService : IRazorLanguageQueryHandler
{
public Task<RazorLanguageQueryResponse> Handle(RazorLanguageQueryParams request, CancellationToken cancellationToken)
{
var response = new RazorLanguageQueryResponse()
{
Position = request.HostDocumentPosition,
TextDocumentUri = request.ProjectedCSharpDocumentUri,
};
return Task.FromResult(response);
}
}
}

Просмотреть файл

@ -1,98 +0,0 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using OmniSharp.Extensions.LanguageServer.Protocol;
using OmniSharp.Extensions.LanguageServer.Protocol.Client.Capabilities;
using OmniSharp.Extensions.LanguageServer.Protocol.Models;
using OmniSharp.Extensions.LanguageServer.Protocol.Server;
using OmniSharp.Extensions.LanguageServer.Protocol.Server.Capabilities;
namespace Microsoft.AspNetCore.Razor.LanguageServer
{
public class TextDocumentHandler : ITextDocumentSyncHandler
{
private readonly ILanguageServer _router;
private readonly DocumentSelector _documentSelector = new DocumentSelector(
new DocumentFilter()
{
Pattern = "**/*.cshtml"
}
);
private SynchronizationCapability _capability;
public TextDocumentHandler(ILanguageServer router)
{
_router = router;
}
public TextDocumentSyncKind Change { get; } = TextDocumentSyncKind.Full;
public Task Handle(DidChangeTextDocumentParams notification, CancellationToken token)
{
_router.Window.LogMessage(new LogMessageParams()
{
Type = MessageType.Log,
Message = "Hello World!!!!"
});
return Task.CompletedTask;
}
TextDocumentChangeRegistrationOptions IRegistration<TextDocumentChangeRegistrationOptions>.GetRegistrationOptions()
{
return new TextDocumentChangeRegistrationOptions()
{
DocumentSelector = _documentSelector,
SyncKind = Change
};
}
public void SetCapability(SynchronizationCapability capability)
{
_capability = capability;
}
public async Task Handle(DidOpenTextDocumentParams notification, CancellationToken token)
{
await Task.Yield();
_router.Window.LogMessage(new LogMessageParams()
{
Type = MessageType.Log,
Message = "Hello World!!!!"
});
}
TextDocumentRegistrationOptions IRegistration<TextDocumentRegistrationOptions>.GetRegistrationOptions()
{
return new TextDocumentRegistrationOptions()
{
DocumentSelector = _documentSelector,
};
}
public Task Handle(DidCloseTextDocumentParams notification, CancellationToken token)
{
return Task.CompletedTask;
}
public Task Handle(DidSaveTextDocumentParams notification, CancellationToken token)
{
return Task.CompletedTask;
}
TextDocumentSaveRegistrationOptions IRegistration<TextDocumentSaveRegistrationOptions>.GetRegistrationOptions()
{
return new TextDocumentSaveRegistrationOptions()
{
DocumentSelector = _documentSelector,
IncludeText = true
};
}
public TextDocumentAttributes GetTextDocumentAttributes(Uri uri)
{
return new TextDocumentAttributes(uri, "razor");
}
}
}