Remove Omnisharp logic from main branch (#9027)

This commit is contained in:
Allison Chou 2023-07-27 10:58:29 -07:00 коммит произвёл GitHub
Родитель d59a761805
Коммит b3c1f61021
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
257 изменённых файлов: 64 добавлений и 21791 удалений

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

@ -66,10 +66,6 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.LanguageServer.Test.Common", "src\Razor\test\Microsoft.AspNetCore.Razor.LanguageServer.Test.Common\Microsoft.AspNetCore.Razor.LanguageServer.Test.Common.csproj", "{9D300F9A-1F78-45C9-B4BB-476EF12E40F8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.OmniSharpPlugin", "src\Razor\src\Microsoft.AspNetCore.Razor.OmniSharpPlugin\Microsoft.AspNetCore.Razor.OmniSharpPlugin.csproj", "{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test", "src\Razor\test\Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test\Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test.csproj", "{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServerClient.Razor", "src\Razor\src\Microsoft.VisualStudio.LanguageServerClient.Razor\Microsoft.VisualStudio.LanguageServerClient.Razor.csproj", "{70E70B52-EB70-42D1-B785-8618BD0B950E}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServerClient.Razor.Test", "src\Razor\test\Microsoft.VisualStudio.LanguageServerClient.Razor.Test\Microsoft.VisualStudio.LanguageServerClient.Razor.Test.csproj", "{F6E8EEA2-BDD8-4AAF-A0CE-9E33A9A7CE8E}"
@ -171,8 +167,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Compiler Tests", "Compiler
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Microbenchmarks.Generator", "src\Compiler\perf\Microsoft.AspNetCore.Razor.Microbenchmarks.Generator\Microsoft.AspNetCore.Razor.Microbenchmarks.Generator.csproj", "{7400A168-2552-49C7-93E3-D4DAA90C216F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp", "src\Razor\src\Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp\Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.csproj", "{3E2B6DF5-524F-4909-8A66-7F8C6383620A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace", "src\Razor\src\Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace\Microsoft.AspNetCore.Razor.ExternalAccess.RoslynWorkspace.csproj", "{2223B8FD-D98A-47BE-94A9-6A3A6B8557B8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.ProjectEngineHost", "src\Razor\src\Microsoft.AspNetCore.Razor.ProjectEngineHost\Microsoft.AspNetCore.Razor.ProjectEngineHost.csproj", "{2FB4801C-A083-4F08-A4FB-C4910985DE31}"
@ -409,22 +403,6 @@ Global
{9D300F9A-1F78-45C9-B4BB-476EF12E40F8}.Release|Any CPU.Build.0 = Release|Any CPU
{9D300F9A-1F78-45C9-B4BB-476EF12E40F8}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{9D300F9A-1F78-45C9-B4BB-476EF12E40F8}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD}.Debug|Any CPU.Build.0 = Debug|Any CPU
{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD}.Release|Any CPU.ActiveCfg = Release|Any CPU
{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD}.Release|Any CPU.Build.0 = Release|Any CPU
{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE}.Release|Any CPU.Build.0 = Release|Any CPU
{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{70E70B52-EB70-42D1-B785-8618BD0B950E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{70E70B52-EB70-42D1-B785-8618BD0B950E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{70E70B52-EB70-42D1-B785-8618BD0B950E}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
@ -721,14 +699,6 @@ Global
{7400A168-2552-49C7-93E3-D4DAA90C216F}.Release|Any CPU.Build.0 = Release|Any CPU
{7400A168-2552-49C7-93E3-D4DAA90C216F}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{7400A168-2552-49C7-93E3-D4DAA90C216F}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{3E2B6DF5-524F-4909-8A66-7F8C6383620A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E2B6DF5-524F-4909-8A66-7F8C6383620A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E2B6DF5-524F-4909-8A66-7F8C6383620A}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{3E2B6DF5-524F-4909-8A66-7F8C6383620A}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{3E2B6DF5-524F-4909-8A66-7F8C6383620A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{3E2B6DF5-524F-4909-8A66-7F8C6383620A}.Release|Any CPU.Build.0 = Release|Any CPU
{3E2B6DF5-524F-4909-8A66-7F8C6383620A}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{3E2B6DF5-524F-4909-8A66-7F8C6383620A}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{2223B8FD-D98A-47BE-94A9-6A3A6B8557B8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2223B8FD-D98A-47BE-94A9-6A3A6B8557B8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2223B8FD-D98A-47BE-94A9-6A3A6B8557B8}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
@ -809,8 +779,6 @@ Global
{6C8A42B5-B41C-4334-959F-684E647A24E1} = {92463391-81BE-462B-AC3C-78C6C760741F}
{FBAE9975-77BE-411B-A1A3-4790C8A367EF} = {92463391-81BE-462B-AC3C-78C6C760741F}
{9D300F9A-1F78-45C9-B4BB-476EF12E40F8} = {92463391-81BE-462B-AC3C-78C6C760741F}
{305354FD-5ED7-4E89-8B1D-58FCCA3E08AD} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{4ED6CC87-11C4-4ECD-B9A1-AFC5C2DACABE} = {92463391-81BE-462B-AC3C-78C6C760741F}
{70E70B52-EB70-42D1-B785-8618BD0B950E} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{F6E8EEA2-BDD8-4AAF-A0CE-9E33A9A7CE8E} = {92463391-81BE-462B-AC3C-78C6C760741F}
{35FEC0EA-09B5-45D2-832D-D6FEBA364871} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
@ -855,7 +823,6 @@ Global
{97DE8703-467C-49A7-BCE4-42FF1FEC8AC2} = {FB7C870E-A173-4F75-BE63-4EF39C79A759}
{A9F9B5E5-C5C2-4860-BE56-038C70ADBAC9} = {FB7C870E-A173-4F75-BE63-4EF39C79A759}
{7400A168-2552-49C7-93E3-D4DAA90C216F} = {C2C98051-0F39-47F2-80B6-E72B29159F2C}
{3E2B6DF5-524F-4909-8A66-7F8C6383620A} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{2223B8FD-D98A-47BE-94A9-6A3A6B8557B8} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{2FB4801C-A083-4F08-A4FB-C4910985DE31} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{70C6EAF1-202B-481B-ADD4-D30DF1396BDE} = {92463391-81BE-462B-AC3C-78C6C760741F}

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

@ -9,7 +9,6 @@ Created with https://www.sankeymatic.com/build/
Input:
```
OmniSharp [1] MS.AspNetCore.Razor.LanguageServer.Common
RoslynWorkspace [1] ProjectEngineHost
MS.AspNetCore.Razor.LanguageServer [1] MS.AspNetCore.Razor.LanguageServer.Common
MS.AspNetCore.Razor.LanguageServer.Common [1] Compiler
@ -114,13 +113,6 @@ target the broadest set of frameworks.
- Microsoft.VisualStudio.Mac.LanguageServices.Razor
- Microsoft.VisualStudio.Mac.RazorAddin
### Visual Studio Code (OmniSharp Plug-in)
- Target Framework: `net472`
- Projects:
- Microsoft.AspNetCore.Razor.OmniSharpPlugin
- Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp
### Miscellaneous / Test hosting
- Target Framework: net7.0
@ -170,7 +162,3 @@ target the broadest set of frameworks.
### Visual Studio (Mac) Tests
- Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test (`net472`)
### Visual Studio Code (OmniSharp Plug-in) Tests
- Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test (`net472`)

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

@ -82,27 +82,7 @@ In most cases, this is because the option _Use previews of the .NET Core SDK_ in
## Building with Visual Studio Code
Note, the [Visual Studio Code C# Extension](https://marketplace.visualstudio.com/items?itemName=ms-dotnettools.csharp) is required.
1. Run `Restore.cmd` on the command line.
1. Launch the `razor` repo in VS Code.
2. Open VS Code settings (`CTRL+,`) and navigate to the `Razor > Plugin: Path` setting:
![image](https://user-images.githubusercontent.com/16968319/192892840-ae2b102c-a282-472f-b1f1-ef3dad671874.png)
3. Set path to `C:\path_to_razor_repo\artifacts\bin\Microsoft.AspNetCore.Razor.OmniSharpPlugin\Debug\net472\Microsoft.AspNetCore.Razor.OmniSharpPlugin.dll`.
4. Launch extension via `Run and Debug -> Run Extension`.
5. Install missing assets if prompted.
### If you want to make changes within the Razor language server
1. Make the changes, then run `Build.cmd -pack`.
2. To debug through the language server code, open VS Code settings and check the box `Razor > Language Server: Debug`.
![image](https://user-images.githubusercontent.com/16968319/192892444-1e4e514a-d41a-4aea-b739-cecee48d12d6.png)
3. Attach your Visual Studio instance to `rzls.exe`.
### If you want to make changes within Razor VS Code
(i.e. anywhere within the `Microsoft.AspNetCore.Razor.VSCode` folder)
1. Make the changes, then delete the existing `node_modules` folder within `Microsoft.AspNetCore.Razor.VSCode.Extension` if one exists. (Deleting the `node_modules` folder is supposed to be unnecessary, but there is currently a bug preventing changes from being detected - tracked by [#6788](https://github.com/dotnet/razor-tooling/issues/6788)).
2. Run `Restore.cmd`.
3. When debugging, ensure breakpoints are set within the `*.js` equivalent of a given `*.ts` file. This file can generally be found in the `node_modules` folder within `Microsoft.AspNetCore.Razor.VSCode.Extension`.
Outside of Razor's language server and C# workspace logic, the bulk of our VS Code logic now lives in the [dotnet/vscode-csharp](https://github.com/dotnet/vscode-csharp) repo.
## Building on command-line

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

@ -1,3 +0,0 @@
[*.cs]
# RS0016: Add public types and members to the declared API
dotnet_diagnostic.RS0016.severity = warning

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

@ -1,80 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.LanguageServer;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
public class OmniSharpBackgroundDocumentGenerator : IOmniSharpProjectSnapshotManagerChangeTrigger
{
private readonly BackgroundDocumentGenerator _backgroundDocumentGenerator;
public OmniSharpBackgroundDocumentGenerator(
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
RemoteTextLoaderFactory remoteTextLoaderFactory,
IEnumerable<OmniSharpDocumentProcessedListener> documentProcessedListeners)
{
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
if (remoteTextLoaderFactory is null)
{
throw new ArgumentNullException(nameof(remoteTextLoaderFactory));
}
if (documentProcessedListeners is null)
{
throw new ArgumentNullException(nameof(documentProcessedListeners));
}
var wrappedListeners = documentProcessedListeners.Select(listener => new WrappedDocumentProcessedListener(remoteTextLoaderFactory, listener));
_backgroundDocumentGenerator = new BackgroundDocumentGenerator(projectSnapshotManagerDispatcher.InternalDispatcher, wrappedListeners);
}
public void Initialize(OmniSharpProjectSnapshotManager projectManager)
{
_backgroundDocumentGenerator.Initialize(projectManager.InternalProjectSnapshotManager);
}
private class WrappedDocumentProcessedListener : DocumentProcessedListener
{
private readonly RemoteTextLoaderFactory _remoteTextLoaderFactory;
private readonly OmniSharpDocumentProcessedListener _innerDocumentProcessedListener;
internal WrappedDocumentProcessedListener(
RemoteTextLoaderFactory remoteTextLoaderFactory,
OmniSharpDocumentProcessedListener innerDocumentProcessedListener)
{
if (remoteTextLoaderFactory is null)
{
throw new ArgumentNullException(nameof(remoteTextLoaderFactory));
}
if (innerDocumentProcessedListener is null)
{
throw new ArgumentNullException(nameof(innerDocumentProcessedListener));
}
_remoteTextLoaderFactory = remoteTextLoaderFactory;
_innerDocumentProcessedListener = innerDocumentProcessedListener;
}
public override void DocumentProcessed(RazorCodeDocument codeDocument, IDocumentSnapshot document)
{
var omniSharpDocument = new OmniSharpDocumentSnapshot(document);
_innerDocumentProcessedListener.DocumentProcessed(codeDocument, omniSharpDocument);
}
public override void Initialize(ProjectSnapshotManager projectManager)
{
var omniSharpProjectManager = new OmniSharpProjectSnapshotManager((ProjectSnapshotManagerBase)projectManager, _remoteTextLoaderFactory);
_innerDocumentProcessedListener.Initialize(omniSharpProjectManager);
}
}
}

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

@ -1,14 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
public abstract class OmniSharpDocumentProcessedListener
{
public abstract void Initialize(OmniSharpProjectSnapshotManager projectManager);
public abstract void DocumentProcessed(RazorCodeDocument codeDocument, OmniSharpDocumentSnapshot document);
}

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

@ -1,58 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
public sealed class OmniSharpDocumentSnapshot
{
private readonly IDocumentSnapshot _documentSnapshot;
private readonly object _projectLock;
private OmniSharpHostDocument? _hostDocument;
private OmniSharpProjectSnapshot? _project;
internal OmniSharpDocumentSnapshot(IDocumentSnapshot documentSnapshot)
{
if (documentSnapshot is null)
{
throw new ArgumentNullException(nameof(documentSnapshot));
}
_documentSnapshot = documentSnapshot;
_projectLock = new object();
}
public OmniSharpHostDocument HostDocument
{
get
{
if (_hostDocument is null)
{
var defaultDocumentSnapshot = (DocumentSnapshot)_documentSnapshot;
var hostDocument = defaultDocumentSnapshot.State.HostDocument;
_hostDocument = new OmniSharpHostDocument(hostDocument.FilePath, hostDocument.TargetPath, hostDocument.FileKind);
}
return _hostDocument;
}
}
public string? FileKind => _documentSnapshot.FileKind;
public string? FilePath => _documentSnapshot.FilePath;
public OmniSharpProjectSnapshot Project
{
get
{
lock (_projectLock)
{
_project ??= new OmniSharpProjectSnapshot(_documentSnapshot.Project);
}
return _project;
}
}
}

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

@ -1,32 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
public sealed class OmniSharpHostDocument
{
public OmniSharpHostDocument(string filePath, string targetPath, string kind)
{
InternalHostDocument = new HostDocument(filePath, targetPath, kind);
if (targetPath.Contains("/"))
{
throw new FormatException("TargetPath's must use '\\' instead of '/'");
}
if (targetPath.StartsWith("\\", StringComparison.Ordinal))
{
throw new FormatException("TargetPath's can't start with '\\'");
}
}
public string FilePath => InternalHostDocument.FilePath;
internal string TargetPath => InternalHostDocument.TargetPath;
internal string FileKind => InternalHostDocument.FileKind;
internal HostDocument InternalHostDocument { get; }
}

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

@ -1,21 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
public sealed class OmniSharpHostDocumentComparer : IEqualityComparer<OmniSharpHostDocument>
{
public static readonly OmniSharpHostDocumentComparer Instance = new();
private OmniSharpHostDocumentComparer()
{
}
public bool Equals(OmniSharpHostDocument? x, OmniSharpHostDocument? y) =>
HostDocumentComparer.Instance.Equals(x?.InternalHostDocument, y?.InternalHostDocument);
public int GetHashCode(OmniSharpHostDocument hostDocument) =>
HostDocumentComparer.Instance.GetHashCode(hostDocument.InternalHostDocument);
}

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

@ -1,28 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.AspNetCore.Razor.Telemetry;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp;
[Shared]
[ExportWorkspaceServiceFactory(typeof(TagHelperResolver), ServiceLayer.Default)]
internal class ExportedTagHelperResolverFactory : IWorkspaceServiceFactory
{
private readonly ITelemetryReporter _telemetryReporter;
[ImportingConstructor]
public ExportedTagHelperResolverFactory()
{
_telemetryReporter = new OmniSharpTelemetryReporter();
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return new DefaultTagHelperResolver(_telemetryReporter);
}
}

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

@ -1,16 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.Workspaces.Extensions;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Extensions;
public static class OmniSharpRazorCodeDocumentExtensions
{
public static SourceText GetInternalCSharpSourceText(this RazorCodeDocument codeDocument)
{
return codeDocument.GetCSharpSourceText();
}
}

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

@ -1,11 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp;
public class FallbackRazorConfiguration
{
public static RazorConfiguration SelectConfiguration(Version version) => CodeAnalysis.Razor.ProjectSystem.FallbackRazorConfiguration.SelectConfiguration(version);
}

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

@ -1,11 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>$(DefaultNetCoreTargetFrameworks);$(DefaultNetFxTargetFramework)</TargetFrameworks>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="../Microsoft.AspNetCore.Razor.LanguageServer.Common/Microsoft.AspNetCore.Razor.LanguageServer.Common.csproj" />
</ItemGroup>
</Project>

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

@ -1,12 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.LanguageServer;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp;
public class OmniSharpLanguageServerFeatureOptions
{
internal LanguageServerFeatureOptions InternalLanguageServerFeatureOptions { get; } = new DefaultLanguageServerFeatureOptions();
}

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

@ -1,9 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public interface IOmniSharpProjectSnapshotManagerChangeTrigger
{
void Initialize(OmniSharpProjectSnapshotManager projectManager);
}

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

@ -1,34 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public sealed class OmniSharpHostProject
{
public OmniSharpHostProject(string projectFilePath, string intermediateOutputPath, RazorConfiguration razorConfiguration, string rootNamespace)
{
if (projectFilePath is null)
{
throw new ArgumentNullException(nameof(projectFilePath));
}
if (intermediateOutputPath is null)
{
throw new ArgumentNullException(nameof(intermediateOutputPath));
}
if (razorConfiguration is null)
{
throw new ArgumentNullException(nameof(razorConfiguration));
}
InternalHostProject = new HostProject(projectFilePath, intermediateOutputPath, razorConfiguration, rootNamespace);
}
public OmniSharpProjectKey Key => new OmniSharpProjectKey(InternalHostProject.Key);
internal HostProject InternalHostProject { get; }
}

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

@ -1,38 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public class OmniSharpProjectChangeEventArgs : EventArgs
{
internal OmniSharpProjectChangeEventArgs(ProjectChangeEventArgs args) : this(
OmniSharpProjectSnapshot.Convert(args.Older),
OmniSharpProjectSnapshot.Convert(args.Newer),
args.DocumentFilePath,
(OmniSharpProjectChangeKind)args.Kind)
{
}
public OmniSharpProjectChangeEventArgs(OmniSharpProjectSnapshot? older, OmniSharpProjectSnapshot? newer, string? documentFilePath, OmniSharpProjectChangeKind kind)
{
if (older is null && newer is null)
{
throw new ArgumentException("Both projects cannot be null.");
}
Older = older;
Newer = newer;
DocumentFilePath = documentFilePath;
Kind = kind;
}
public OmniSharpProjectSnapshot? Older { get; }
public OmniSharpProjectSnapshot? Newer { get; }
public string? DocumentFilePath { get; }
public OmniSharpProjectChangeKind Kind { get; }
}

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

@ -1,15 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public enum OmniSharpProjectChangeKind
{
ProjectAdded = ProjectChangeKind.ProjectAdded,
ProjectRemoved = ProjectChangeKind.ProjectRemoved,
ProjectChanged = ProjectChangeKind.ProjectChanged,
DocumentAdded = ProjectChangeKind.DocumentAdded,
DocumentRemoved = ProjectChangeKind.DocumentRemoved,
}

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

@ -1,22 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public sealed class OmniSharpProjectKey
{
public static OmniSharpProjectKey? From(CodeAnalysis.Project workspaceProject)
{
var key = ProjectKey.From(workspaceProject);
return key is null ? null : new(key.Value);
}
internal ProjectKey Key { get; }
internal OmniSharpProjectKey(ProjectKey key)
{
this.Key = key;
}
}

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

@ -1,56 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
using Microsoft.AspNetCore.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces.ProjectSystem;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public sealed class OmniSharpProjectSnapshot
{
internal readonly IProjectSnapshot InternalProjectSnapshot;
internal OmniSharpProjectSnapshot(IProjectSnapshot projectSnapshot)
{
InternalProjectSnapshot = projectSnapshot;
}
public OmniSharpProjectKey Key => new OmniSharpProjectKey(InternalProjectSnapshot.Key);
public string FilePath => InternalProjectSnapshot.FilePath;
public IEnumerable<string> DocumentFilePaths => InternalProjectSnapshot.DocumentFilePaths;
public ProjectWorkspaceState? ProjectWorkspaceState => InternalProjectSnapshot.ProjectWorkspaceState;
public OmniSharpDocumentSnapshot? GetDocument(string filePath)
{
var documentSnapshot = InternalProjectSnapshot.GetDocument(filePath);
if (documentSnapshot is null)
{
return null;
}
var internalDocumentSnapshot = new OmniSharpDocumentSnapshot(documentSnapshot);
return internalDocumentSnapshot;
}
public void Serialize(string publishFilePath, JsonSerializer serializer, StreamWriter writer)
{
var projectRazorJson = InternalProjectSnapshot.ToProjectRazorJson(publishFilePath);
serializer.Serialize(writer, projectRazorJson);
}
internal static OmniSharpProjectSnapshot? Convert(IProjectSnapshot? projectSnapshot)
{
if (projectSnapshot is null)
{
return null;
}
return new OmniSharpProjectSnapshot(projectSnapshot);
}
}

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

@ -1,91 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Immutable;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public class OmniSharpProjectSnapshotManager
{
private readonly RemoteTextLoaderFactory _remoteTextLoaderFactory;
internal OmniSharpProjectSnapshotManager(
ProjectSnapshotManagerBase projectSnapshotManager,
RemoteTextLoaderFactory remoteTextLoaderFactory)
{
if (projectSnapshotManager is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManager));
}
if (remoteTextLoaderFactory is null)
{
throw new ArgumentNullException(nameof(remoteTextLoaderFactory));
}
InternalProjectSnapshotManager = projectSnapshotManager;
_remoteTextLoaderFactory = remoteTextLoaderFactory;
InternalProjectSnapshotManager.Changed += ProjectSnapshotManager_Changed;
}
internal ProjectSnapshotManagerBase InternalProjectSnapshotManager { get; }
public IReadOnlyList<OmniSharpProjectSnapshot> Projects => InternalProjectSnapshotManager.GetProjects().Select(project => OmniSharpProjectSnapshot.Convert(project)!).ToList();
public event EventHandler<OmniSharpProjectChangeEventArgs>? Changed;
public OmniSharpProjectSnapshot GetLoadedProject(OmniSharpProjectKey projectKey)
{
var projectSnapshot = InternalProjectSnapshotManager.GetLoadedProject(projectKey.Key);
// Forgiving null because we should only return null when projectSnapshot is null
var converted = OmniSharpProjectSnapshot.Convert(projectSnapshot)!;
return converted;
}
public ImmutableArray<OmniSharpProjectKey> GetAllProjectKeys(string projectFilePath)
{
var keys = InternalProjectSnapshotManager.GetAllProjectKeys(projectFilePath);
return ImmutableArray<OmniSharpProjectKey>.Empty.AddRange(keys.Select(k => new OmniSharpProjectKey(k)));
}
public void ProjectAdded(OmniSharpHostProject hostProject)
{
InternalProjectSnapshotManager.ProjectAdded(hostProject.InternalHostProject);
}
public void ProjectConfigurationChanged(OmniSharpHostProject hostProject)
{
InternalProjectSnapshotManager.ProjectConfigurationChanged(hostProject.InternalHostProject);
}
public void DocumentAdded(OmniSharpHostProject hostProject, OmniSharpHostDocument hostDocument)
{
var textLoader = _remoteTextLoaderFactory.Create(hostDocument.FilePath);
InternalProjectSnapshotManager.DocumentAdded(hostProject.InternalHostProject.Key, hostDocument.InternalHostDocument, textLoader);
}
public void DocumentChanged(string projectFilePath, string documentFilePath)
{
var textLoader = _remoteTextLoaderFactory.Create(documentFilePath);
foreach (var projectKey in InternalProjectSnapshotManager.GetAllProjectKeys(projectFilePath))
{
InternalProjectSnapshotManager.DocumentChanged(projectKey, documentFilePath, textLoader);
}
}
public void DocumentRemoved(OmniSharpHostProject hostProject, OmniSharpHostDocument hostDocument)
{
InternalProjectSnapshotManager.DocumentRemoved(hostProject.InternalHostProject.Key, hostDocument.InternalHostDocument);
}
private void ProjectSnapshotManager_Changed(object? sender, ProjectChangeEventArgs args)
{
var convertedArgs = new OmniSharpProjectChangeEventArgs(args);
Changed?.Invoke(this, convertedArgs);
}
}

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

@ -1,73 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public class OmniSharpProjectSnapshotManagerAccessor
{
private readonly RemoteTextLoaderFactory _remoteTextLoaderFactory;
private readonly IEnumerable<IOmniSharpProjectSnapshotManagerChangeTrigger> _projectChangeTriggers;
private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly Workspace _workspace;
private OmniSharpProjectSnapshotManager? _instance;
public OmniSharpProjectSnapshotManagerAccessor(
RemoteTextLoaderFactory remoteTextLoaderFactory,
IEnumerable<IOmniSharpProjectSnapshotManagerChangeTrigger> projectChangeTriggers,
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
Workspace workspace)
{
if (remoteTextLoaderFactory is null)
{
throw new ArgumentNullException(nameof(remoteTextLoaderFactory));
}
if (projectChangeTriggers is null)
{
throw new ArgumentNullException(nameof(projectChangeTriggers));
}
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
if (workspace is null)
{
throw new ArgumentNullException(nameof(workspace));
}
_remoteTextLoaderFactory = remoteTextLoaderFactory;
_projectChangeTriggers = projectChangeTriggers;
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_workspace = workspace;
}
public OmniSharpProjectSnapshotManager Instance
{
get
{
if (_instance is null)
{
var projectSnapshotManager = new DefaultProjectSnapshotManager(
ErrorReporter.Instance,
Array.Empty<ProjectSnapshotChangeTrigger>(),
_workspace);
var instance = new OmniSharpProjectSnapshotManager(projectSnapshotManager, _remoteTextLoaderFactory);
_instance = instance;
foreach (var changeTrigger in _projectChangeTriggers)
{
changeTrigger.Initialize(instance);
}
}
return _instance;
}
}
}

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

@ -1,39 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Workspaces;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public class OmniSharpProjectSnapshotManagerDispatcher
{
public OmniSharpProjectSnapshotManagerDispatcher()
{
InternalDispatcher = new InternalOmniSharpProjectSnapshotManagerDispatcher();
}
internal ProjectSnapshotManagerDispatcher InternalDispatcher { get; private protected set; }
public Task RunOnDispatcherThreadAsync(Action action, CancellationToken cancellationToken)
=> InternalDispatcher.RunOnDispatcherThreadAsync(action, cancellationToken);
public TaskScheduler DispatcherScheduler => InternalDispatcher.DispatcherScheduler;
public void AssertDispatcherThread([CallerMemberName] string? caller = null) => InternalDispatcher.AssertDispatcherThread(caller);
private class InternalOmniSharpProjectSnapshotManagerDispatcher : ProjectSnapshotManagerDispatcherBase
{
private const string ThreadName = "Razor." + nameof(OmniSharpProjectSnapshotManagerDispatcher);
internal InternalOmniSharpProjectSnapshotManagerDispatcher() : base(ThreadName)
{
}
public override void LogException(Exception ex)
{
// We don't currently have logging mechanisms in place for O#.
}
}
}

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

@ -1,32 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public class OmniSharpProjectWorkspaceStateGenerator : IOmniSharpProjectSnapshotManagerChangeTrigger
{
// Internal for testing
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
internal OmniSharpProjectWorkspaceStateGenerator()
#pragma warning restore CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.
{
}
public OmniSharpProjectWorkspaceStateGenerator(OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher)
{
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
InternalWorkspaceStateGenerator = new DefaultProjectWorkspaceStateGenerator(projectSnapshotManagerDispatcher.InternalDispatcher);
}
internal DefaultProjectWorkspaceStateGenerator InternalWorkspaceStateGenerator { get; }
public void Initialize(OmniSharpProjectSnapshotManager projectManager) => InternalWorkspaceStateGenerator.Initialize(projectManager.InternalProjectSnapshotManager);
public virtual void Update(CodeAnalysis.Project workspaceProject, OmniSharpProjectSnapshot projectSnapshot) => InternalWorkspaceStateGenerator.Update(workspaceProject, projectSnapshot.InternalProjectSnapshot, CancellationToken.None);
}

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

@ -1,44 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Collections.Immutable;
using Microsoft.AspNetCore.Razor.Telemetry;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp;
internal class OmniSharpTelemetryReporter : ITelemetryReporter
{
public void ReportEvent(string name, Severity severity)
{
}
public void ReportEvent(string name, Severity severity, ImmutableDictionary<string, object?> values)
{
}
public void ReportFault(Exception exception, string? message, params object?[] @params)
{
}
public IDisposable BeginBlock(string name, Severity severity)
{
return NullScope.Instance;
}
public IDisposable BeginBlock(string name, Severity severity, ImmutableDictionary<string, object?> values)
{
return NullScope.Instance;
}
public IDisposable TrackLspRequest(string lspMethodName, string lspServerName, Guid correlationId)
{
return NullScope.Instance;
}
private class NullScope : IDisposable
{
public static NullScope Instance { get; } = new NullScope();
private NullScope() { }
public void Dispose() { }
}
}

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

@ -1,113 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Diagnostics;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Razor.Workspaces;
using Microsoft.VisualStudio.Threading;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
public class OmniSharpWorkspaceProjectStateChangeDetector : IOmniSharpProjectSnapshotManagerChangeTrigger
{
public OmniSharpWorkspaceProjectStateChangeDetector(
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator,
OmniSharpLanguageServerFeatureOptions languageServerFeatureOptions)
{
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
if (workspaceStateGenerator is null)
{
throw new ArgumentNullException(nameof(workspaceStateGenerator));
}
InternalWorkspaceProjectStateChangeDetector = new ProjectSnapshotManagerWorkspaceProjectStateChangeDetector(
projectSnapshotManagerDispatcher.InternalDispatcher,
workspaceStateGenerator.InternalWorkspaceStateGenerator,
languageServerFeatureOptions.InternalLanguageServerFeatureOptions);
}
private WorkspaceProjectStateChangeDetector InternalWorkspaceProjectStateChangeDetector { get; }
public void Initialize(OmniSharpProjectSnapshotManager projectManager)
{
InternalWorkspaceProjectStateChangeDetector.Initialize(projectManager.InternalProjectSnapshotManager);
}
private class ProjectSnapshotManagerWorkspaceProjectStateChangeDetector : WorkspaceProjectStateChangeDetector
{
private readonly ProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
internal ProjectSnapshotManagerWorkspaceProjectStateChangeDetector(
ProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
ProjectWorkspaceStateGenerator workspaceStateGenerator,
LanguageServerFeatureOptions languageServerFeatureOptions)
: base(workspaceStateGenerator, projectSnapshotManagerDispatcher, languageServerFeatureOptions)
{
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
}
// We override the InitializeSolution in order to enforce calls to this to be on the project snapshot manager's
// thread. OmniSharp currently has an issue where they update the Solution on multiple different threads resulting
// in change events dispatching through the Workspace on multiple different threads. This normalizes
// that abnormality.
protected override void InitializeSolution(Solution solution)
{
_ = InitializeSolutionAsync(solution, CancellationToken.None);
}
private async Task InitializeSolutionAsync(Solution solution, CancellationToken cancellationToken)
{
try
{
await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
() =>
{
base.InitializeSolution(solution);
},
cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
Debug.Fail("Unexpected error when initializing solution: " + ex);
}
}
// We override Workspace_WorkspaceChanged in order to enforce calls to this to be on the project snapshot manager's
// thread. OmniSharp currently has an issue where they update the Solution on multiple different threads resulting
// in change events dispatching through the Workspace on multiple different threads. This normalizes
// that abnormality.
internal override void Workspace_WorkspaceChanged(object? sender, WorkspaceChangeEventArgs args)
{
Workspace_WorkspaceChangedAsync(sender, args).Forget();
}
private async Task Workspace_WorkspaceChangedAsync(object? sender, WorkspaceChangeEventArgs args)
{
try
{
await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
() =>
{
base.Workspace_WorkspaceChanged(sender, args);
},
CancellationToken.None).ConfigureAwait(false);
}
catch (Exception ex)
{
Debug.Fail("Unexpected error when handling a workspace changed event: " + ex);
}
}
}
}

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

@ -1,25 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
[Shared]
[ExportWorkspaceServiceFactory(typeof(ProjectSnapshotProjectEngineFactory))]
internal class ProjectSnapshotProjectEngineFactoryFactory : IWorkspaceServiceFactory
{
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
if (workspaceServices is null)
{
throw new ArgumentNullException(nameof(workspaceServices));
}
return new DefaultProjectSnapshotProjectEngineFactory(new FallbackProjectEngineFactory(), MefProjectEngineFactories.Factories);
}
}

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

@ -1,6 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

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

@ -1 +0,0 @@
#nullable enable

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

@ -1,80 +0,0 @@
#nullable enable
abstract Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentProcessedListener.DocumentProcessed(Microsoft.AspNetCore.Razor.Language.RazorCodeDocument! codeDocument, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentSnapshot! document) -> void
abstract Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentProcessedListener.Initialize(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager! projectManager) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpBackgroundDocumentGenerator
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpBackgroundDocumentGenerator.Initialize(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager! projectManager) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpBackgroundDocumentGenerator.OmniSharpBackgroundDocumentGenerator(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerDispatcher! projectSnapshotManagerDispatcher, Microsoft.AspNetCore.Razor.LanguageServer.Common.RemoteTextLoaderFactory! remoteTextLoaderFactory, System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentProcessedListener!>! documentProcessedListeners) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentProcessedListener
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentProcessedListener.OmniSharpDocumentProcessedListener() -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentSnapshot
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentSnapshot.FileKind.get -> string?
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentSnapshot.FilePath.get -> string?
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentSnapshot.HostDocument.get -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocument!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentSnapshot.Project.get -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocument
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocument.FilePath.get -> string!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocument.OmniSharpHostDocument(string! filePath, string! targetPath, string! kind) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocumentComparer
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocumentComparer.Equals(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocument? x, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocument? y) -> bool
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocumentComparer.GetHashCode(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocument! hostDocument) -> int
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Extensions.OmniSharpRazorCodeDocumentExtensions
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.FallbackRazorConfiguration
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.FallbackRazorConfiguration.FallbackRazorConfiguration() -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.OmniSharpLanguageServerFeatureOptions
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.OmniSharpLanguageServerFeatureOptions.OmniSharpLanguageServerFeatureOptions() -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.IOmniSharpProjectSnapshotManagerChangeTrigger
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.IOmniSharpProjectSnapshotManagerChangeTrigger.Initialize(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager! projectManager) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpHostProject
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpHostProject.Key.get -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectKey!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpHostProject.OmniSharpHostProject(string! projectFilePath, string! intermediateOutputPath, Microsoft.AspNetCore.Razor.Language.RazorConfiguration! razorConfiguration, string! rootNamespace) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeEventArgs
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeEventArgs.DocumentFilePath.get -> string?
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeEventArgs.Kind.get -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeEventArgs.Newer.get -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot?
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeEventArgs.Older.get -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot?
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeEventArgs.OmniSharpProjectChangeEventArgs(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot? older, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot? newer, string? documentFilePath, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind kind) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind.DocumentAdded = 3 -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind.DocumentRemoved = 4 -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind.ProjectAdded = 0 -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind.ProjectChanged = 2 -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind.ProjectRemoved = 1 -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeKind
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectKey
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot.DocumentFilePaths.get -> System.Collections.Generic.IEnumerable<string!>!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot.FilePath.get -> string!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot.GetDocument(string! filePath) -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpDocumentSnapshot?
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot.Key.get -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectKey!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot.ProjectWorkspaceState.get -> Microsoft.AspNetCore.Razor.ProjectSystem.ProjectWorkspaceState?
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot.Serialize(string! publishFilePath, Newtonsoft.Json.JsonSerializer! serializer, System.IO.StreamWriter! writer) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager.Changed -> System.EventHandler<Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectChangeEventArgs!>?
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager.DocumentAdded(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpHostProject! hostProject, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocument! hostDocument) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager.DocumentChanged(string! projectFilePath, string! documentFilePath) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager.DocumentRemoved(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpHostProject! hostProject, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocument! hostDocument) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager.GetAllProjectKeys(string! projectFilePath) -> System.Collections.Immutable.ImmutableArray<Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectKey!>
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager.GetLoadedProject(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectKey! projectKey) -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager.ProjectAdded(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpHostProject! hostProject) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager.ProjectConfigurationChanged(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpHostProject! hostProject) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager.Projects.get -> System.Collections.Generic.IReadOnlyList<Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot!>!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerAccessor
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerAccessor.Instance.get -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerAccessor.OmniSharpProjectSnapshotManagerAccessor(Microsoft.AspNetCore.Razor.LanguageServer.Common.RemoteTextLoaderFactory! remoteTextLoaderFactory, System.Collections.Generic.IEnumerable<Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.IOmniSharpProjectSnapshotManagerChangeTrigger!>! projectChangeTriggers, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerDispatcher! projectSnapshotManagerDispatcher, Microsoft.CodeAnalysis.Workspace! workspace) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerDispatcher
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerDispatcher.AssertDispatcherThread(string? caller = null) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerDispatcher.DispatcherScheduler.get -> System.Threading.Tasks.TaskScheduler!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerDispatcher.OmniSharpProjectSnapshotManagerDispatcher() -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(System.Action! action, System.Threading.CancellationToken cancellationToken) -> System.Threading.Tasks.Task!
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectWorkspaceStateGenerator
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectWorkspaceStateGenerator.Initialize(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager! projectManager) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectWorkspaceStateGenerator.OmniSharpProjectWorkspaceStateGenerator(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerDispatcher! projectSnapshotManagerDispatcher) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpWorkspaceProjectStateChangeDetector
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpWorkspaceProjectStateChangeDetector.Initialize(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManager! projectManager) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpWorkspaceProjectStateChangeDetector.OmniSharpWorkspaceProjectStateChangeDetector(Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshotManagerDispatcher! projectSnapshotManagerDispatcher, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectWorkspaceStateGenerator! workspaceStateGenerator, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.OmniSharpLanguageServerFeatureOptions! languageServerFeatureOptions) -> void
Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Serialization.JsonConverterCollectionExtensions
static Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Extensions.OmniSharpRazorCodeDocumentExtensions.GetInternalCSharpSourceText(this Microsoft.AspNetCore.Razor.Language.RazorCodeDocument! codeDocument) -> Microsoft.CodeAnalysis.Text.SourceText!
static Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.FallbackRazorConfiguration.SelectConfiguration(System.Version! version) -> Microsoft.AspNetCore.Razor.Language.RazorConfiguration!
static Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectKey.From(Microsoft.CodeAnalysis.Project! workspaceProject) -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectKey?
static Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Serialization.JsonConverterCollectionExtensions.RegisterOmniSharpRazorConverters(this Newtonsoft.Json.JsonConverterCollection! collection) -> void
static readonly Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocumentComparer.Instance -> Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document.OmniSharpHostDocumentComparer!
virtual Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectWorkspaceStateGenerator.Update(Microsoft.CodeAnalysis.Project! workspaceProject, Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project.OmniSharpProjectSnapshot! projectSnapshot) -> void

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

@ -1,39 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.AspNetCore.Razor.Serialization.Converters;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Serialization;
public static class JsonConverterCollectionExtensions
{
public static void RegisterOmniSharpRazorConverters(this JsonConverterCollection collection)
{
collection.RegisterRazorConverters();
collection.Add(OmniSharpProjectSnapshotHandleJsonConverter.Instance);
}
private class OmniSharpProjectSnapshotHandleJsonConverter : JsonConverter
{
internal static readonly OmniSharpProjectSnapshotHandleJsonConverter Instance = new();
public override bool CanConvert(Type objectType)
{
return typeof(OmniSharpProjectSnapshot).IsAssignableFrom(objectType);
}
public override object ReadJson(JsonReader reader, Type objectType, object? existingValue, JsonSerializer serializer)
{
throw new NotImplementedException();
}
public override void WriteJson(JsonWriter writer, object? value, JsonSerializer serializer)
{
var snapshot = (OmniSharpProjectSnapshot)value!;
serializer.Serialize(writer, snapshot.InternalProjectSnapshot);
}
}
}

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

@ -1,299 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Extensions;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.Extensions.Logging;
using OmniSharp;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
// This class is responsible for listening to document processed events and then synchronizing their existence in the C# workspace.
// Key scenarios are:
// 1. A Razor document is not open - Publish Razor documents C# content to workspace under a background convention file path (i.e. Index.razor__bg__virtual.cs)
// 2. A Razor document is already open - Active C# content for the open doc already exists in the workspace (i.e. Index.razor__virtual.cs), noop.
// 3. A Razor document gets opened - Remove background generated C# content from workspace so active C# content gets prioritized
// 4. A Razor document gets closed - Need to transition active C# content to background C# content in the workspace.
//
// Since we don't have LSP access to fully understand if a document opens/closes we utilize the convention of our active and background generated C#
// file paths to understand if a Razor document is open or closed.
[Shared]
[Export(typeof(OmniSharpDocumentProcessedListener))]
internal class BackgroundDocumentProcessedPublisher : OmniSharpDocumentProcessedListener
{
// File paths need to align with the file path that's used to create virutal document buffers in the RazorDocumentFactory.ts.
// The purpose of the alignment is to ensure that when a Razor virtual C# buffer opens we can properly detect its existence.
internal const string ActiveVirtualDocumentSuffix = "__virtual.cs";
internal const string BackgroundVirtualDocumentSuffix = "__bg" + ActiveVirtualDocumentSuffix;
private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly OmniSharpWorkspace _workspace;
private readonly ILogger _logger;
private OmniSharpProjectSnapshotManager _projectManager;
private readonly object _workspaceChangedLock;
[ImportingConstructor]
public BackgroundDocumentProcessedPublisher(
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
OmniSharpWorkspace workspace,
ILoggerFactory loggerFactory)
{
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
if (workspace is null)
{
throw new ArgumentNullException(nameof(workspace));
}
if (loggerFactory is null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_workspace = workspace;
_logger = loggerFactory.CreateLogger<BackgroundDocumentProcessedPublisher>();
_workspaceChangedLock = new object();
_workspace.WorkspaceChanged += Workspace_WorkspaceChanged;
}
// A Razor file has been processed, this portion is responsible for the decision of whether we need to create or update
// the Razor documents background C# representation.
public override void DocumentProcessed(RazorCodeDocument codeDocument, OmniSharpDocumentSnapshot document)
{
if (document is null)
{
throw new ArgumentNullException(nameof(document));
}
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
lock (_workspaceChangedLock)
{
if (FileKinds.IsComponentImport(document.FileKind))
{
// Razor component imports don't have any C# to generate anyways, don't do the work. This doesn't capture _ViewImports.cshtml because we never
// associated a FileKind with those files.
return;
}
var openVirtualFilePath = document.FilePath + ActiveVirtualDocumentSuffix;
var openDocument = _workspace.GetDocument(openVirtualFilePath);
if (openDocument != null)
{
// This document is open in the editor, no reason for us to populate anything in the workspace the editor will do that.
return;
}
var backgroundVirtualFilePath = document.FilePath + BackgroundVirtualDocumentSuffix;
var currentDocument = _workspace.GetDocument(backgroundVirtualFilePath);
if (currentDocument is null)
{
// Background document doesn't exist, we need to create it
var roslynProject = GetRoslynProject(document.Project);
if (roslynProject is null)
{
// There's no Roslyn project associated with the Razor document.
_logger.LogTrace("Could not find a Roslyn project for Razor virtual document '{backgroundVirtualFilePath}'.", backgroundVirtualFilePath);
return;
}
var documentId = DocumentId.CreateNewId(roslynProject.Id);
var name = Path.GetFileName(backgroundVirtualFilePath);
var emptyTextLoader = new EmptyTextLoader(backgroundVirtualFilePath);
var documentInfo = DocumentInfo.Create(documentId, name, filePath: backgroundVirtualFilePath, loader: emptyTextLoader);
_workspace.AddDocument(documentInfo);
currentDocument = _workspace.GetDocument(backgroundVirtualFilePath);
Debug.Assert(currentDocument != null, "We just added the document, it should definitely be there.");
}
// Update document content
var sourceText = codeDocument.GetInternalCSharpSourceText();
_workspace.OnDocumentChanged(currentDocument.Id, sourceText);
}
}
public override void Initialize(OmniSharpProjectSnapshotManager projectManager)
{
if (projectManager is null)
{
throw new ArgumentNullException(nameof(projectManager));
}
_projectManager = projectManager;
_projectManager.Changed += ProjectManager_Changed;
}
// Here we're specifically listening for cases when a user opens a Razor document and an active C# content gets created.
internal void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs args)
{
lock (_workspaceChangedLock)
{
switch (args.Kind)
{
case WorkspaceChangeKind.DocumentAdded:
{
// We could technically listen for DocumentAdded here but just because a document gets added doesn't mean it has content included.
// Therefore we need to wait for content to populated for Razor files so we don't preemptively remove the corresponding background
// C# before the active C# content has been populated.
var project = args.NewSolution.GetProject(args.ProjectId);
var document = project.GetDocument(args.DocumentId);
if (document.FilePath is null)
{
break;
}
if (document.FilePath.EndsWith(ActiveVirtualDocumentSuffix, StringComparison.Ordinal) && !document.FilePath.EndsWith(BackgroundVirtualDocumentSuffix, StringComparison.Ordinal))
{
// Document from editor got opened, clear out any background documents of the same type
var razorDocumentFilePath = GetRazorDocumentFilePath(document);
var backgroundDocumentFilePath = GetBackgroundVirtualDocumentFilePath(razorDocumentFilePath);
var backgroundDocument = GetRoslynDocument(project, backgroundDocumentFilePath);
if (backgroundDocument != null)
{
_workspace.RemoveDocument(backgroundDocument.Id);
}
}
break;
}
case WorkspaceChangeKind.DocumentRemoved:
{
var project = args.OldSolution.GetProject(args.ProjectId);
var document = project.GetDocument(args.DocumentId);
if (document.FilePath is null)
{
break;
}
if (document.FilePath.EndsWith(ActiveVirtualDocumentSuffix, StringComparison.Ordinal) && !document.FilePath.EndsWith(BackgroundVirtualDocumentSuffix, StringComparison.Ordinal))
{
var razorDocumentFilePath = GetRazorDocumentFilePath(document);
if (File.Exists(razorDocumentFilePath))
{
// Razor document closed because the backing C# virtual document went away
var backgroundDocumentFilePath = GetBackgroundVirtualDocumentFilePath(razorDocumentFilePath);
var newName = Path.GetFileName(backgroundDocumentFilePath);
var delegatedTextLoader = new DelegatedTextLoader(document);
var movedDocumentInfo = DocumentInfo.Create(args.DocumentId, newName, loader: delegatedTextLoader, filePath: backgroundDocumentFilePath);
_workspace.AddDocument(movedDocumentInfo);
}
}
}
break;
}
}
}
// When the Razor project manager forgets about a document we need remove its background C# representation
// so that content doesn't get stale.
private void ProjectManager_Changed(object sender, OmniSharpProjectChangeEventArgs args)
{
switch (args.Kind)
{
case OmniSharpProjectChangeKind.DocumentRemoved:
var roslynProject = GetRoslynProject(args.Older);
if (roslynProject is null)
{
// Project no longer exists
return;
}
var backgroundVirtualFilePath = GetBackgroundVirtualDocumentFilePath(args.DocumentFilePath);
var backgroundDocument = GetRoslynDocument(roslynProject, backgroundVirtualFilePath);
if (backgroundDocument is null)
{
// No background document associated
return;
}
// There's still a background document associated with the removed Razor document.
_workspace.RemoveDocument(backgroundDocument.Id);
break;
}
}
private Project GetRoslynProject(OmniSharpProjectSnapshot project)
{
var roslynProject = _workspace.CurrentSolution.Projects.FirstOrDefault(roslynProject => string.Equals(roslynProject.FilePath, project.FilePath, FilePathComparison.Instance));
return roslynProject;
}
private static Document GetRoslynDocument(Project project, string backgroundDocumentFilePath)
{
var roslynDocument = project.Documents.FirstOrDefault(document => string.Equals(document.FilePath, backgroundDocumentFilePath, FilePathComparison.Instance));
return roslynDocument;
}
private static string GetRazorDocumentFilePath(Document document)
{
if (document.FilePath.EndsWith(BackgroundVirtualDocumentSuffix, StringComparison.Ordinal))
{
var razorDocumentFilePath = document.FilePath.Substring(0, document.FilePath.Length - BackgroundVirtualDocumentSuffix.Length);
return razorDocumentFilePath;
}
else if (document.FilePath.EndsWith(ActiveVirtualDocumentSuffix, StringComparison.Ordinal))
{
var razorDocumentFilePath = document.FilePath.Substring(0, document.FilePath.Length - ActiveVirtualDocumentSuffix.Length);
return razorDocumentFilePath;
}
Debug.Fail($"The caller should have ensured that '{document.FilePath}' is associated with a Razor file path.");
return null;
}
private static string GetBackgroundVirtualDocumentFilePath(string razorDocumentFilePath)
{
var backgroundDocumentFilePath = razorDocumentFilePath + BackgroundVirtualDocumentSuffix;
return backgroundDocumentFilePath;
}
private class DelegatedTextLoader : TextLoader
{
private readonly Document _document;
public DelegatedTextLoader(Document document)
{
if (document is null)
{
throw new ArgumentNullException(nameof(document));
}
_document = document;
}
public async override Task<TextAndVersion> LoadTextAndVersionAsync(LoadTextOptions options, CancellationToken cancellationToken)
{
var sourceText = await _document.GetTextAsync(cancellationToken);
var textVersion = await _document.GetTextVersionAsync(cancellationToken);
var textAndVersion = TextAndVersion.Create(sourceText, textVersion);
return textAndVersion;
}
}
}

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

@ -1,24 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Linq;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
public abstract class CoreProjectConfigurationProvider : ProjectConfigurationProvider
{
// Internal for testing
internal const string DotNetCoreRazorCapability = "DotNetCoreRazor";
internal const string DotNetCoreWebCapability = "DotNetCoreWeb";
internal const string DotNetCoreRazorConfigurationCapability = "DotNetCoreRazorConfiguration";
protected bool HasRazorCoreCapability(ProjectConfigurationProviderContext context) =>
context.ProjectCapabilities.Contains(DotNetCoreRazorCapability) ||
context.ProjectCapabilities.Contains(DotNetCoreWebCapability);
protected bool HasRazorCoreConfigurationCapability(ProjectConfigurationProviderContext context) =>
context.ProjectCapabilities.Contains(DotNetCoreRazorConfigurationCapability);
}

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

@ -1,213 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Serialization;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
[Shared]
[Export(typeof(ProjectChangePublisher))]
[Export(typeof(IOmniSharpProjectSnapshotManagerChangeTrigger))]
internal class DefaultProjectChangePublisher : ProjectChangePublisher, IOmniSharpProjectSnapshotManagerChangeTrigger
{
private const string TempFileExt = ".temp";
// Internal for testing
internal readonly Dictionary<string, Task> DeferredPublishTasks;
private readonly ILogger<DefaultProjectChangePublisher> _logger;
private readonly JsonSerializer _serializer;
private readonly Dictionary<string, string> _publishFilePathMappings;
private readonly Dictionary<string, OmniSharpProjectSnapshot> _pendingProjectPublishes;
private readonly object _publishLock;
private OmniSharpProjectSnapshotManager _projectManager;
[ImportingConstructor]
public DefaultProjectChangePublisher(ILoggerFactory loggerFactory)
{
if (loggerFactory is null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger<DefaultProjectChangePublisher>();
_serializer = new JsonSerializer()
{
Formatting = Formatting.Indented,
};
_serializer.Converters.RegisterOmniSharpRazorConverters();
_publishFilePathMappings = new Dictionary<string, string>(FilePathComparer.Instance);
DeferredPublishTasks = new Dictionary<string, Task>(FilePathComparer.Instance);
_pendingProjectPublishes = new Dictionary<string, OmniSharpProjectSnapshot>(FilePathComparer.Instance);
_publishLock = new object();
}
// Internal settable for testing
// 250ms between publishes to prevent bursts of changes yet still be responsive to changes.
internal int EnqueueDelay { get; set; } = 250;
public void Initialize(OmniSharpProjectSnapshotManager projectManager)
{
if (projectManager is null)
{
throw new ArgumentNullException(nameof(projectManager));
}
_projectManager = projectManager;
_projectManager.Changed += ProjectManager_Changed;
}
public override void SetPublishFilePath(string projectFilePath, string publishFilePath)
{
lock (_publishLock)
{
_publishFilePathMappings[projectFilePath] = publishFilePath;
}
}
// Virtual for testing
protected virtual void SerializeToFile(OmniSharpProjectSnapshot projectSnapshot, string publishFilePath)
{
// We need to avoid having an incomplete file at any point, but our
// project configuration is large enough that it will be written as multiple operations.
var tempFilePath = string.Concat(publishFilePath, TempFileExt);
var tempFileInfo = new FileInfo(tempFilePath);
if (tempFileInfo.Exists)
{
// This could be caused by failures during serialization or early process termination.
tempFileInfo.Delete();
}
// This needs to be in explicit brackets because the operation needs to be completed
// by the time we move the tempfile into its place
using (var writer = tempFileInfo.CreateText())
{
projectSnapshot.Serialize(publishFilePath, _serializer, writer);
}
var fileInfo = new FileInfo(publishFilePath);
if (fileInfo.Exists)
{
fileInfo.Delete();
}
File.Move(tempFileInfo.FullName, publishFilePath);
}
// Internal for testing
internal void Publish(OmniSharpProjectSnapshot projectSnapshot)
{
if (projectSnapshot is null)
{
throw new ArgumentNullException(nameof(projectSnapshot));
}
lock (_publishLock)
{
string publishFilePath = null;
try
{
if (!_publishFilePathMappings.TryGetValue(projectSnapshot.FilePath, out publishFilePath))
{
return;
}
SerializeToFile(projectSnapshot, publishFilePath);
}
catch (Exception ex)
{
_logger.LogWarning(@"Could not update Razor project configuration file '{publishFilePath}':
{ex}", publishFilePath, ex);
}
}
}
// Internal for testing
internal void EnqueuePublish(OmniSharpProjectSnapshot projectSnapshot)
{
lock (_publishLock)
{
_pendingProjectPublishes[projectSnapshot.FilePath] = projectSnapshot;
if (!DeferredPublishTasks.TryGetValue(projectSnapshot.FilePath, out var update) || update.IsCompleted)
{
DeferredPublishTasks[projectSnapshot.FilePath] = PublishAfterDelayAsync(projectSnapshot.FilePath);
}
}
}
// Internal for testing
internal void ProjectManager_Changed(object sender, OmniSharpProjectChangeEventArgs args)
{
switch (args.Kind)
{
case OmniSharpProjectChangeKind.DocumentRemoved:
case OmniSharpProjectChangeKind.DocumentAdded:
case OmniSharpProjectChangeKind.ProjectChanged:
// These changes can come in bursts so we don't want to overload the publishing system. Therefore,
// we enqueue publishes and then publish the latest project after a delay.
if (args.Newer.ProjectWorkspaceState != null)
{
EnqueuePublish(args.Newer);
}
break;
case OmniSharpProjectChangeKind.ProjectRemoved:
RemovePublishingData(args.Older);
break;
// We don't care about ProjectAdded scenarios because a newly added project does not have a workspace state associated with it meaning
// it isn't interesting for us to serialize quite yet.
}
}
internal void RemovePublishingData(OmniSharpProjectSnapshot projectSnapshot)
{
lock (_publishLock)
{
var oldProjectFilePath = projectSnapshot.FilePath;
if (!_publishFilePathMappings.TryGetValue(oldProjectFilePath, out var configurationFilePath))
{
// If we don't track the value in PublishFilePathMappings that means it's already been removed, do nothing.
return;
}
if (_pendingProjectPublishes.TryGetValue(oldProjectFilePath, out _))
{
// Project was removed while a delayed publish was in flight. Clear the in-flight publish so it noops.
_pendingProjectPublishes.Remove(oldProjectFilePath);
}
}
}
private async Task PublishAfterDelayAsync(string projectFilePath)
{
await Task.Delay(EnqueueDelay);
lock (_publishLock)
{
if (!_pendingProjectPublishes.TryGetValue(projectFilePath, out var projectSnapshot))
{
// Project was removed while waiting for the publish delay.
return;
}
_pendingProjectPublishes.Remove(projectFilePath);
Publish(projectSnapshot);
}
}
}

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

@ -1,108 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Execution;
using Microsoft.Build.Framework;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
// This class enables us to re-evaluate MSBuild project instances. Doing such a thing isn't directly
// supported by the ProjectInstance type because they're meant to be a snapshot of an MSBuild project
// at a certain point in time. Therefore, we re-create the MSBuild project environment by lifting all
// configuration values from the project instance and re-creating our own MSBuild project collection
// that can duplicate the work that OmniSharp does.
//
// Project re-evaluation is required for two reasons:
// 1. Razor file additions/deletions. OmniSharp tells us when a change happens to impact the csproj
// configuration but not the opaque items of a project such as content/initial compile items.
// 2. When OmniSharp initially evaluates the users project they don't do a true design time build.
// Because of this several bits of Razor information get left out in the initial project instance,
// we then need to force the execution of the appropriate targets to populate that information on
// the project instance.
[Shared]
[Export(typeof(ProjectInstanceEvaluator))]
public class DefaultProjectInstanceEvaluator : ProjectInstanceEvaluator
{
internal const string TargetFrameworkPropertyName = "TargetFramework";
internal const string TargetFrameworksPropertyName = "TargetFrameworks";
private const string CompileTargetName = "Compile";
private const string CoreCompileTargetName = "CoreCompile";
private const string RazorGenerateDesignTimeTargetName = "RazorGenerateDesignTime";
private const string RazorGenerateComponentDesignTimeTargetName = "RazorGenerateComponentDesignTime";
private static readonly IEnumerable<ILogger> s_emptyMSBuildLoggers = Enumerable.Empty<ILogger>();
private readonly object _evaluationLock = new object();
[ImportingConstructor]
public DefaultProjectInstanceEvaluator()
{
}
public override ProjectInstance Evaluate(ProjectInstance projectInstance)
{
if (projectInstance is null)
{
throw new ArgumentNullException(nameof(projectInstance));
}
lock (_evaluationLock)
{
var refreshTargets = new List<string>()
{
// These are the default targets for the project instance that OmniSharp runs.
CompileTargetName,
CoreCompileTargetName
};
if (projectInstance.Targets.ContainsKey(RazorGenerateDesignTimeTargetName))
{
refreshTargets.Add(RazorGenerateDesignTimeTargetName);
}
if (projectInstance.Targets.ContainsKey(RazorGenerateComponentDesignTimeTargetName))
{
refreshTargets.Add(RazorGenerateComponentDesignTimeTargetName);
}
if (refreshTargets.Count > 2)
{
var projectCollection = new ProjectCollection(projectInstance.GlobalProperties);
var project = projectCollection.LoadProject(projectInstance.ProjectFileLocation.File, projectInstance.ToolsVersion);
SetTargetFrameworkIfNeeded(project);
var refreshedProjectInstance = project.CreateProjectInstance();
// Force a Razor information refresh
refreshedProjectInstance.Build(refreshTargets.ToArray(), s_emptyMSBuildLoggers);
return refreshedProjectInstance;
}
return projectInstance;
}
}
private static void SetTargetFrameworkIfNeeded(Project evaluatedProject)
{
var targetFramework = evaluatedProject.GetPropertyValue(TargetFrameworkPropertyName);
var targetFrameworksRaw = evaluatedProject.GetPropertyValue(TargetFrameworksPropertyName);
var targetFrameworks = targetFrameworksRaw
.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries)
.Select(framework => framework.Trim())
.ToArray();
if (string.IsNullOrWhiteSpace(targetFramework) && targetFrameworks.Length > 0)
{
// Pick first target framework to replicate what OmniSharp does.
targetFramework = targetFrameworks[0];
evaluatedProject.SetProperty(TargetFrameworkPropertyName, targetFramework);
evaluatedProject.ReevaluateIfNecessary();
}
}
}

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

@ -1,62 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Composition;
using System.Threading;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.AspNetCore.Razor.OmniSharpPlugin;
namespace Microsoft.AspNetCore.Razor.LanguageServer.Common;
[Shared]
[Export(typeof(IRazorDocumentChangeListener))]
[Export(typeof(IOmniSharpProjectSnapshotManagerChangeTrigger))]
internal class DocumentChangedSynchronizationService : IOmniSharpProjectSnapshotManagerChangeTrigger, IRazorDocumentChangeListener
{
private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private OmniSharpProjectSnapshotManager _projectManager;
[ImportingConstructor]
public DocumentChangedSynchronizationService(OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher)
{
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
}
public void Initialize(OmniSharpProjectSnapshotManager projectManager)
{
if (projectManager is null)
{
throw new ArgumentNullException(nameof(projectManager));
}
_projectManager = projectManager;
}
public void RazorDocumentChanged(RazorFileChangeEventArgs args)
{
if (args is null)
{
throw new ArgumentNullException(nameof(args));
}
if (args.Kind != RazorFileChangeKind.Changed)
{
return;
}
var projectFilePath = args.UnevaluatedProjectInstance.ProjectFileLocation.File;
var documentFilePath = args.FilePath;
_ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
() => _projectManager.DocumentChanged(projectFilePath, documentFilePath),
CancellationToken.None).ConfigureAwait(false);
}
}

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

@ -1,31 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
internal class EmptyTextLoader : TextLoader
{
private readonly string _filePath;
private readonly VersionStamp _version;
public EmptyTextLoader(string filePath)
{
_filePath = filePath;
_version = VersionStamp.Create(); // Version will never change so this can be reused.
}
public override Task<TextAndVersion> LoadTextAndVersionAsync(LoadTextOptions options, CancellationToken cancellationToken)
{
// Providing an encoding here is important for debuggability. Without this edit-and-continue
// won't work for projects with Razor files.
return Task.FromResult(TextAndVersion.Create(SourceText.From(string.Empty, Encoding.UTF8), _version, _filePath));
}
}

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

@ -1,85 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.IO;
using System.Reflection.Metadata;
using System.Reflection.PortableExecutable;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
internal class FallbackConfigurationProvider : CoreProjectConfigurationProvider
{
public static FallbackConfigurationProvider Instance = new FallbackConfigurationProvider();
// Internal for testing
internal const string ReferencePathWithRefAssembliesItemType = "ReferencePathWithRefAssemblies";
internal const string MvcAssemblyFileName = "Microsoft.AspNetCore.Mvc.Razor.dll";
public override bool TryResolveConfiguration(ProjectConfigurationProviderContext context, out ProjectConfiguration configuration)
{
if (!HasRazorCoreCapability(context))
{
configuration = null;
return false;
}
var compilationReferences = context.ProjectInstance.GetItems(ReferencePathWithRefAssembliesItemType);
string mvcReferenceFullPath = null;
foreach (var compilationReference in compilationReferences)
{
var assemblyFullPath = compilationReference.EvaluatedInclude;
if (assemblyFullPath.EndsWith(MvcAssemblyFileName, FilePathComparison.Instance))
{
var potentialPathSeparator = assemblyFullPath[assemblyFullPath.Length - MvcAssemblyFileName.Length - 1];
if (potentialPathSeparator == '/' || potentialPathSeparator == '\\')
{
mvcReferenceFullPath = assemblyFullPath;
break;
}
}
}
if (mvcReferenceFullPath is null)
{
configuration = null;
return false;
}
var version = GetAssemblyVersion(mvcReferenceFullPath);
if (version is null)
{
configuration = null;
return false;
}
var razorConfiguration = FallbackRazorConfiguration.SelectConfiguration(version);
configuration = new ProjectConfiguration(razorConfiguration, Array.Empty<OmniSharpHostDocument>(), rootNamespace: null);
return true;
}
// Protected virtual for testing
protected virtual Version GetAssemblyVersion(string filePath)
{
try
{
using (var stream = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete))
using (var reader = new PEReader(stream))
{
var metadataReader = reader.GetMetadataReader();
var assemblyDefinition = metadataReader.GetAssemblyDefinition();
return assemblyDefinition.Version;
}
}
catch
{
// We're purposely silencing any kinds of I/O exceptions here, just in case something wacky is going on.
return null;
}
}
}

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

@ -1,31 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Runtime.InteropServices;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
internal static class FilePathComparer
{
private static StringComparer s_instance;
public static StringComparer Instance
{
get
{
if (s_instance is null && RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
s_instance = StringComparer.Ordinal;
}
else if (s_instance is null)
{
s_instance = StringComparer.OrdinalIgnoreCase;
}
return s_instance;
}
}
}

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

@ -1,31 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Runtime.InteropServices;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
internal static class FilePathComparison
{
private static StringComparison? s_instance;
public static StringComparison Instance
{
get
{
if (s_instance is null && RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
s_instance = StringComparison.Ordinal;
}
else if (s_instance is null)
{
s_instance = StringComparison.OrdinalIgnoreCase;
}
return s_instance.Value;
}
}
}

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

@ -1,11 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
internal interface IRazorDocumentChangeListener
{
void RazorDocumentChanged(RazorFileChangeEventArgs args);
}

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

@ -1,11 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
internal interface IRazorDocumentOutputChangeListener
{
void RazorDocumentOutputChanged(RazorFileChangeEventArgs args);
}

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

@ -1,290 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.Build.Execution;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
[Shared]
[Export(typeof(ProjectConfigurationProvider))]
internal class LatestProjectConfigurationProvider : CoreProjectConfigurationProvider
{
// Internal for testing
internal const string RazorGenerateWithTargetPathItemType = "RazorGenerateWithTargetPath";
internal const string RazorComponentWithTargetPathItemType = "RazorComponentWithTargetPath";
internal const string RazorTargetPathMetadataName = "TargetPath";
internal const string RootNamespaceProperty = "RootNamespace";
private const string RazorLangVersionProperty = "RazorLangVersion";
private const string RazorDefaultConfigurationProperty = "RazorDefaultConfiguration";
private const string RazorExtensionItemType = "RazorExtension";
private const string RazorConfigurationItemType = "RazorConfiguration";
private const string RazorConfigurationItemTypeExtensionsProperty = "Extensions";
public override bool TryResolveConfiguration(ProjectConfigurationProviderContext context, out ProjectConfiguration configuration)
{
if (!HasRazorCoreCapability(context))
{
configuration = null;
return false;
}
if (!HasRazorCoreConfigurationCapability(context))
{
// Razor project is < 2.1, we don't handle that.
configuration = null;
return false;
}
var projectInstance = context.ProjectInstance;
if (!TryGetConfiguration(projectInstance, out configuration))
{
configuration = null;
return false;
}
return true;
}
// Internal for testing
internal static bool TryGetConfiguration(
ProjectInstance projectInstance,
out ProjectConfiguration configuration)
{
if (!TryGetDefaultConfiguration(projectInstance, out var defaultConfiguration))
{
configuration = null;
return false;
}
if (!TryGetLanguageVersion(projectInstance, out var languageVersion))
{
configuration = null;
return false;
}
if (!TryGetConfigurationItem(defaultConfiguration, projectInstance.Items, out var configurationItem))
{
configuration = null;
return false;
}
var configuredExtensionNames = GetConfiguredExtensionNames(configurationItem);
var rootNamespace = GetRootNamespace(projectInstance);
var extensions = GetExtensions(configuredExtensionNames, projectInstance.Items);
var razorConfiguration = new ProjectSystemRazorConfiguration(languageVersion, configurationItem.EvaluatedInclude, extensions);
var hostDocuments = GetHostDocuments(projectInstance.Items);
configuration = new ProjectConfiguration(razorConfiguration, hostDocuments, rootNamespace);
return true;
}
// Internal for testing
internal static string GetRootNamespace(ProjectInstance projectInstance)
{
var rootNamespace = projectInstance.GetPropertyValue(RootNamespaceProperty);
if (string.IsNullOrEmpty(rootNamespace))
{
return null;
}
return rootNamespace;
}
// Internal for testing
internal static IReadOnlyList<OmniSharpHostDocument> GetHostDocuments(ICollection<ProjectItemInstance> projectItems)
{
var hostDocuments = new HashSet<OmniSharpHostDocument>();
foreach (var item in projectItems)
{
if (item.ItemType == RazorGenerateWithTargetPathItemType)
{
var filePath = Path.Combine(item.Project.Directory, item.EvaluatedInclude);
var originalTargetPath = item.GetMetadataValue(RazorTargetPathMetadataName);
var normalizedTargetPath = NormalizeTargetPath(originalTargetPath);
var hostDocument = new OmniSharpHostDocument(filePath, normalizedTargetPath, FileKinds.Legacy);
hostDocuments.Add(hostDocument);
}
else if (item.ItemType == RazorComponentWithTargetPathItemType)
{
var filePath = Path.Combine(item.Project.Directory, item.EvaluatedInclude);
var originalTargetPath = item.GetMetadataValue(RazorTargetPathMetadataName);
var normalizedTargetPath = NormalizeTargetPath(originalTargetPath);
var fileKind = FileKinds.GetComponentFileKindFromFilePath(filePath);
var hostDocument = new OmniSharpHostDocument(filePath, normalizedTargetPath, fileKind);
hostDocuments.Add(hostDocument);
}
}
return hostDocuments.ToList();
}
// Internal for testing
internal static bool TryGetDefaultConfiguration(ProjectInstance projectInstance, out string defaultConfiguration)
{
defaultConfiguration = projectInstance.GetPropertyValue(RazorDefaultConfigurationProperty);
if (string.IsNullOrEmpty(defaultConfiguration))
{
defaultConfiguration = null;
return false;
}
return true;
}
// Internal for testing
internal static bool TryGetLanguageVersion(ProjectInstance projectInstance, out RazorLanguageVersion languageVersion)
{
var languageVersionValue = projectInstance.GetPropertyValue(RazorLangVersionProperty);
if (string.IsNullOrEmpty(languageVersionValue))
{
languageVersion = null;
return false;
}
if (!RazorLanguageVersion.TryParse(languageVersionValue, out languageVersion))
{
languageVersion = RazorLanguageVersion.Latest;
}
return true;
}
// Internal for testing
internal static bool TryGetConfigurationItem(
string configuration,
IEnumerable<ProjectItemInstance> projectItems,
out ProjectItemInstance configurationItem)
{
foreach (var item in projectItems)
{
if (item.ItemType == RazorConfigurationItemType && item.EvaluatedInclude == configuration)
{
configurationItem = item;
return true;
}
}
configurationItem = null;
return false;
}
// Internal for testing
internal static string[] GetConfiguredExtensionNames(ProjectItemInstance configurationItem)
{
var extensionNamesValue = configurationItem.GetMetadataValue(RazorConfigurationItemTypeExtensionsProperty);
if (string.IsNullOrEmpty(extensionNamesValue))
{
return Array.Empty<string>();
}
var configuredExtensionNames = extensionNamesValue.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries);
return configuredExtensionNames;
}
// Internal for testing
internal static ProjectSystemRazorExtension[] GetExtensions(
string[] configuredExtensionNames,
IEnumerable<ProjectItemInstance> projectItems)
{
var extensions = new List<ProjectSystemRazorExtension>();
foreach (var item in projectItems)
{
if (item.ItemType != RazorExtensionItemType)
{
// Not a RazorExtension
continue;
}
var extensionName = item.EvaluatedInclude;
if (configuredExtensionNames.Contains(extensionName))
{
extensions.Add(new ProjectSystemRazorExtension(extensionName));
}
}
return extensions.ToArray();
}
/// <summary>
/// TargetPath is defined as using '\' but some Tasks used to set that parameter don't respect that, so we normalize.
/// </summary>
/// <param name="targetPath">The TargetPath to be normalized.</param>
/// <returns>A normalized TargetPath</returns>
internal static string NormalizeTargetPath(string targetPath)
{
if (targetPath is null)
{
throw new ArgumentNullException(nameof(targetPath));
}
var normalizedTargetPath = targetPath.Replace('/', '\\');
normalizedTargetPath = normalizedTargetPath.TrimStart('\\');
return normalizedTargetPath;
}
private class ProjectSystemRazorConfiguration : RazorConfiguration
{
public ProjectSystemRazorConfiguration(
RazorLanguageVersion languageVersion,
string configurationName,
RazorExtension[] extensions,
bool useConsolidatedMvcViews = false)
{
if (languageVersion is null)
{
throw new ArgumentNullException(nameof(languageVersion));
}
if (configurationName is null)
{
throw new ArgumentNullException(nameof(configurationName));
}
if (extensions is null)
{
throw new ArgumentNullException(nameof(extensions));
}
LanguageVersion = languageVersion;
ConfigurationName = configurationName;
Extensions = extensions;
UseConsolidatedMvcViews = useConsolidatedMvcViews;
}
public override string ConfigurationName { get; }
public override IReadOnlyList<RazorExtension> Extensions { get; }
public override RazorLanguageVersion LanguageVersion { get; }
public override bool UseConsolidatedMvcViews { get; }
}
internal class ProjectSystemRazorExtension : RazorExtension
{
public ProjectSystemRazorExtension(string extensionName)
{
if (extensionName is null)
{
throw new ArgumentNullException(nameof(extensionName));
}
ExtensionName = extensionName;
}
public override string ExtensionName { get; }
}
}

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

@ -1,162 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Composition;
using System.IO;
using System.Linq;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.Build.Execution;
using OmniSharp.MSBuild.Notification;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
[Shared]
[Export(typeof(IMSBuildEventSink))]
internal class MSBuildProjectDocumentChangeDetector : IMSBuildEventSink
{
private const string MSBuildProjectFullPathPropertyName = "MSBuildProjectFullPath";
private const string MSBuildProjectDirectoryPropertyName = "MSBuildProjectDirectory";
private static readonly IReadOnlyList<string> s_razorFileExtensions = new[] { ".razor", ".cshtml" };
private readonly Dictionary<string, IReadOnlyList<FileSystemWatcher>> _watcherMap;
private readonly IReadOnlyList<IRazorDocumentChangeListener> _documentChangeListeners;
private readonly List<IRazorDocumentOutputChangeListener> _documentOutputChangeListeners;
[ImportingConstructor]
public MSBuildProjectDocumentChangeDetector(
[ImportMany] IEnumerable<IRazorDocumentChangeListener> documentChangeListeners,
[ImportMany] IEnumerable<IRazorDocumentOutputChangeListener> documentOutputChangeListeners)
{
if (documentChangeListeners is null)
{
throw new ArgumentNullException(nameof(documentChangeListeners));
}
if (documentOutputChangeListeners is null)
{
throw new ArgumentNullException(nameof(documentOutputChangeListeners));
}
_watcherMap = new Dictionary<string, IReadOnlyList<FileSystemWatcher>>(FilePathComparer.Instance);
_documentChangeListeners = documentChangeListeners.ToList();
_documentOutputChangeListeners = documentOutputChangeListeners.ToList();
}
public void ProjectLoaded(ProjectLoadedEventArgs loadedArgs)
{
if (loadedArgs is null)
{
throw new ArgumentNullException(nameof(loadedArgs));
}
var projectInstance = loadedArgs.ProjectInstance;
var projectFilePath = projectInstance.GetPropertyValue(MSBuildProjectFullPathPropertyName);
if (string.IsNullOrEmpty(projectFilePath))
{
// This should never be true but we're being extra careful.
return;
}
var projectDirectory = projectInstance.GetPropertyValue(MSBuildProjectDirectoryPropertyName);
if (string.IsNullOrEmpty(projectDirectory))
{
// This should never be true but we're beign extra careful.
return;
}
if (_watcherMap.TryGetValue(projectDirectory, out var existingWatchers))
{
for (var i = 0; i < existingWatchers.Count; i++)
{
existingWatchers[i].Dispose();
}
}
var watchers = new List<FileSystemWatcher>(s_razorFileExtensions.Count);
for (var i = 0; i < s_razorFileExtensions.Count; i++)
{
var documentWatcher = new FileSystemWatcher(projectDirectory, "*" + s_razorFileExtensions[i])
{
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite | NotifyFilters.CreationTime,
IncludeSubdirectories = true,
};
documentWatcher.Created += (sender, args) => FileSystemWatcher_RazorDocumentEvent(args.FullPath, projectInstance, RazorFileChangeKind.Added);
documentWatcher.Deleted += (sender, args) => FileSystemWatcher_RazorDocumentEvent(args.FullPath, projectInstance, RazorFileChangeKind.Removed);
documentWatcher.Changed += (sender, args) => FileSystemWatcher_RazorDocumentEvent(args.FullPath, projectInstance, RazorFileChangeKind.Changed);
documentWatcher.Renamed += (sender, args) =>
{
// Translate file renames into remove / add
if (s_razorFileExtensions.Any(extension => args.OldFullPath.EndsWith(extension, StringComparison.Ordinal)))
{
// Renaming from Razor file to something else.
FileSystemWatcher_RazorDocumentEvent(args.OldFullPath, projectInstance, RazorFileChangeKind.Removed);
}
if (s_razorFileExtensions.Any(extension => args.FullPath.EndsWith(extension, StringComparison.Ordinal)))
{
// Renaming into a Razor file. This typically occurs when users go from .cshtml => .razor
FileSystemWatcher_RazorDocumentEvent(args.FullPath, projectInstance, RazorFileChangeKind.Added);
}
};
watchers.Add(documentWatcher);
var documentOutputWatcher = new FileSystemWatcher(projectDirectory, "*" + s_razorFileExtensions[i] + ".g.cs")
{
NotifyFilter = NotifyFilters.FileName | NotifyFilters.LastWrite,
IncludeSubdirectories = true,
};
documentOutputWatcher.Created += (sender, args) => FileSystemWatcher_RazorDocumentOutputEvent(args.FullPath, projectInstance, RazorFileChangeKind.Added);
documentOutputWatcher.Deleted += (sender, args) => FileSystemWatcher_RazorDocumentOutputEvent(args.FullPath, projectInstance, RazorFileChangeKind.Removed);
documentOutputWatcher.Changed += (sender, args) => FileSystemWatcher_RazorDocumentOutputEvent(args.FullPath, projectInstance, RazorFileChangeKind.Changed);
documentOutputWatcher.Renamed += (sender, args) =>
{
// Translate file renames into remove / add
if (s_razorFileExtensions.Any(extension => args.OldFullPath.EndsWith(extension + ".g.cs", StringComparison.Ordinal)))
{
// Renaming from Razor background file to something else.
FileSystemWatcher_RazorDocumentOutputEvent(args.OldFullPath, projectInstance, RazorFileChangeKind.Removed);
}
if (s_razorFileExtensions.Any(extension => args.FullPath.EndsWith(extension + ".g.cs", StringComparison.Ordinal)))
{
// Renaming into a Razor generated file.
FileSystemWatcher_RazorDocumentOutputEvent(args.FullPath, projectInstance, RazorFileChangeKind.Added);
}
};
watchers.Add(documentOutputWatcher);
documentWatcher.EnableRaisingEvents = true;
documentOutputWatcher.EnableRaisingEvents = true;
}
_watcherMap[projectDirectory] = watchers;
}
// Internal for testing
internal void FileSystemWatcher_RazorDocumentEvent(string filePath, ProjectInstance projectInstance, RazorFileChangeKind changeKind)
{
var args = new RazorFileChangeEventArgs(filePath, projectInstance, changeKind);
for (var i = 0; i < _documentChangeListeners.Count; i++)
{
_documentChangeListeners[i].RazorDocumentChanged(args);
}
}
// Internal for testing
internal void FileSystemWatcher_RazorDocumentOutputEvent(string filePath, ProjectInstance projectInstance, RazorFileChangeKind changeKind)
{
var args = new RazorFileChangeEventArgs(filePath, projectInstance, changeKind);
for (var i = 0; i < _documentOutputChangeListeners.Count; i++)
{
_documentOutputChangeListeners[i].RazorDocumentOutputChanged(args);
}
}
}

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

@ -1,327 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Composition;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.OmniSharpPlugin;
using Microsoft.Build.Execution;
using Microsoft.Extensions.Logging;
using OmniSharp.MSBuild.Notification;
namespace Microsoft.AspNetCore.Razor.OmnisharpPlugin;
[Shared]
[Export(typeof(IMSBuildEventSink))]
[Export(typeof(IRazorDocumentChangeListener))]
[Export(typeof(IOmniSharpProjectSnapshotManagerChangeTrigger))]
internal class MSBuildProjectManager : IOmniSharpProjectSnapshotManagerChangeTrigger, IMSBuildEventSink, IRazorDocumentChangeListener
{
// Internal for testing
internal const string IntermediateOutputPathPropertyName = "IntermediateOutputPath";
internal const string MSBuildProjectDirectoryPropertyName = "MSBuildProjectDirectory";
internal const string ProjectCapabilityItemType = "ProjectCapability";
private const string MSBuildProjectFullPathPropertyName = "MSBuildProjectFullPath";
private const string DebugRazorOmnisharpPluginPropertyName = "_DebugRazorOmnisharpPlugin_";
private readonly ILogger _logger;
private readonly IEnumerable<ProjectConfigurationProvider> _projectConfigurationProviders;
private readonly ProjectInstanceEvaluator _projectInstanceEvaluator;
private readonly ProjectChangePublisher _projectConfigurationPublisher;
private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private OmniSharpProjectSnapshotManager? _projectManager;
[ImportingConstructor]
public MSBuildProjectManager(
[ImportMany] IEnumerable<ProjectConfigurationProvider> projectConfigurationProviders,
ProjectInstanceEvaluator projectInstanceEvaluator,
ProjectChangePublisher projectConfigurationPublisher,
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
ILoggerFactory loggerFactory)
{
if (projectConfigurationProviders is null)
{
throw new ArgumentNullException(nameof(projectConfigurationProviders));
}
if (projectInstanceEvaluator is null)
{
throw new ArgumentNullException(nameof(projectInstanceEvaluator));
}
if (projectConfigurationPublisher is null)
{
throw new ArgumentNullException(nameof(projectConfigurationPublisher));
}
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
if (loggerFactory is null)
{
throw new ArgumentNullException(nameof(loggerFactory));
}
_logger = loggerFactory.CreateLogger<MSBuildProjectManager>();
_projectConfigurationProviders = projectConfigurationProviders;
_projectInstanceEvaluator = projectInstanceEvaluator;
_projectConfigurationPublisher = projectConfigurationPublisher;
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
}
public OmniSharpProjectSnapshotManager ProjectManager => _projectManager ?? throw new InvalidOperationException($"{nameof(ProjectManager)} was unexpectedly 'null'. Has {nameof(Initialize)} been called?");
public void Initialize(OmniSharpProjectSnapshotManager projectManager)
{
if (projectManager is null)
{
throw new ArgumentNullException(nameof(projectManager));
}
_projectManager = projectManager;
}
public void ProjectLoaded(ProjectLoadedEventArgs args)
{
_ = ProjectLoadedAsync(args, CancellationToken.None);
}
public void RazorDocumentChanged(RazorFileChangeEventArgs args)
{
if (args.Kind == RazorFileChangeKind.Added ||
args.Kind == RazorFileChangeKind.Removed)
{
// When documents get added or removed we need to refresh project state to properly reflect the host documents in the project.
var evaluatedProjectInstance = _projectInstanceEvaluator.Evaluate(args.UnevaluatedProjectInstance);
_ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
() => UpdateProjectState(evaluatedProjectInstance), CancellationToken.None).ConfigureAwait(false);
}
}
// Internal for testing
internal async Task ProjectLoadedAsync(ProjectLoadedEventArgs args, CancellationToken cancellationToken)
{
try
{
var projectInstance = args.ProjectInstance;
HandleDebug(projectInstance);
if (!TryResolveConfigurationOutputPath(projectInstance, out var configPath))
{
return;
}
var projectFilePath = projectInstance.GetPropertyValue(MSBuildProjectFullPathPropertyName);
if (string.IsNullOrEmpty(projectFilePath))
{
// This should never be true but we're being extra careful.
return;
}
_projectConfigurationPublisher.SetPublishFilePath(projectFilePath, configPath);
// Force project instance evaluation to ensure that all Razor specific targets have run.
projectInstance = _projectInstanceEvaluator.Evaluate(projectInstance);
await _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
() => UpdateProjectState(projectInstance), cancellationToken).ConfigureAwait(false);
}
catch (Exception ex)
{
_logger.LogError("Unexpected exception got thrown from the Razor plugin: {exception}", ex);
}
}
private void UpdateProjectState(ProjectInstance projectInstance)
{
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
var projectFilePath = projectInstance.GetPropertyValue(MSBuildProjectFullPathPropertyName);
if (string.IsNullOrEmpty(projectFilePath))
{
// This should never be true but we're being extra careful.
return;
}
var projectConfiguration = GetProjectConfiguration(projectInstance, _projectConfigurationProviders);
if (projectConfiguration is null)
{
// Not a Razor project
return;
}
if (!TryResolveConfigurationOutputPath(projectInstance, out var configPath) || configPath is null)
{
return;
}
var hostProject = new OmniSharpHostProject(projectFilePath, configPath, projectConfiguration.Configuration, projectConfiguration.RootNamespace);
var projectSnapshot = ProjectManager.GetLoadedProject(hostProject.Key);
if (projectSnapshot is null)
{
// Project doesn't exist yet, create it and set it up with all of its host documents.
ProjectManager.ProjectAdded(hostProject);
foreach (var hostDocument in projectConfiguration.Documents)
{
ProjectManager.DocumentAdded(hostProject, hostDocument);
}
}
else
{
// Project already exists (project change). Reconfigure the project and add or remove host documents to synchronize it with the configured host documents.
ProjectManager.ProjectConfigurationChanged(hostProject);
SynchronizeDocuments(projectConfiguration.Documents, projectSnapshot, hostProject);
}
}
// Internal for testing
internal void SynchronizeDocuments(
IReadOnlyList<OmniSharpHostDocument> configuredHostDocuments,
OmniSharpProjectSnapshot projectSnapshot,
OmniSharpHostProject hostProject)
{
// Remove any documents that need to be removed
foreach (var documentFilePath in projectSnapshot.DocumentFilePaths)
{
OmniSharpHostDocument? associatedHostDocument = null;
var documentSnapshot = projectSnapshot.GetDocument(documentFilePath);
if (documentSnapshot is null)
{
_logger.LogWarning("Missing DocumentSnapshot for {documentFilePath}.", documentFilePath);
continue;
}
var currentHostDocument = documentSnapshot.HostDocument;
for (var i = 0; i < configuredHostDocuments.Count; i++)
{
var configuredHostDocument = configuredHostDocuments[i];
if (OmniSharpHostDocumentComparer.Instance.Equals(configuredHostDocument, currentHostDocument))
{
associatedHostDocument = configuredHostDocument;
break;
}
}
if (associatedHostDocument is null)
{
// Document was removed
ProjectManager.DocumentRemoved(hostProject, currentHostDocument);
}
}
// Refresh the project snapshot to reflect any removed documents.
projectSnapshot = ProjectManager.GetLoadedProject(projectSnapshot.Key);
// Add any documents that need to be added
for (var i = 0; i < configuredHostDocuments.Count; i++)
{
var hostDocument = configuredHostDocuments[i];
if (!projectSnapshot.DocumentFilePaths.Contains(hostDocument.FilePath, FilePathComparer.Instance))
{
// Document was added.
ProjectManager.DocumentAdded(hostProject, hostDocument);
}
}
}
// Internal for testing
internal static ProjectConfiguration? GetProjectConfiguration(
ProjectInstance projectInstance,
IEnumerable<ProjectConfigurationProvider> projectConfigurationProviders)
{
if (projectInstance is null)
{
throw new ArgumentNullException(nameof(projectInstance));
}
if (projectConfigurationProviders is null)
{
throw new ArgumentNullException(nameof(projectConfigurationProviders));
}
var projectCapabilities = projectInstance
.GetItems(ProjectCapabilityItemType)
.Select(capability => capability.EvaluatedInclude)
.ToList();
var context = new ProjectConfigurationProviderContext(projectCapabilities, projectInstance);
foreach (var projectConfigurationProvider in projectConfigurationProviders)
{
if (projectConfigurationProvider.TryResolveConfiguration(context, out var configuration))
{
return configuration;
}
}
if (FallbackConfigurationProvider.Instance.TryResolveConfiguration(context, out var fallbackConfiguration))
{
return fallbackConfiguration;
}
return null;
}
private static void HandleDebug(ProjectInstance projectInstance)
{
var debugPlugin = projectInstance.GetPropertyValue(DebugRazorOmnisharpPluginPropertyName);
if (!string.IsNullOrEmpty(debugPlugin) && string.Equals(debugPlugin, "true", StringComparison.OrdinalIgnoreCase))
{
Console.WriteLine($"Waiting for a debugger to attach to the Razor Plugin. Process id: {Process.GetCurrentProcess().Id}");
while (!Debugger.IsAttached)
{
Thread.Sleep(1000);
}
Debugger.Break();
}
}
// Internal for testing
internal static bool TryResolveConfigurationOutputPath(ProjectInstance projectInstance, out string? path)
{
var intermediateOutputPath = projectInstance.GetPropertyValue(IntermediateOutputPathPropertyName);
if (string.IsNullOrEmpty(intermediateOutputPath))
{
path = null;
return false;
}
if (!Path.IsPathRooted(intermediateOutputPath))
{
// Relative path, need to convert to absolute.
var projectDirectory = projectInstance.GetPropertyValue(MSBuildProjectDirectoryPropertyName);
if (string.IsNullOrEmpty(projectDirectory))
{
// This should never be true but we're being extra careful.
path = null;
return false;
}
intermediateOutputPath = Path.Combine(projectDirectory, intermediateOutputPath);
}
intermediateOutputPath = intermediateOutputPath
.Replace('\\', Path.DirectorySeparatorChar)
.Replace('/', Path.DirectorySeparatorChar);
path = Path.Combine(intermediateOutputPath, LanguageServerConstants.DefaultProjectConfigurationFile);
return true;
}
}

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

@ -1,22 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>$(DefaultNetFxTargetFramework)</TargetFramework>
<Description>Razor is a markup syntax for adding logic to pages. This package contains the Omnisharp Razor plugin that extracts Razor configuration information from projects.</Description>
<EnableApiCheck>false</EnableApiCheck>
<IsShippingPackage>false</IsShippingPackage>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp\Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="OmniSharp.MSBuild" Version="$(OmniSharpMSBuildPackageVersion)" />
<PackageReference Include="Microsoft.Build" Version="$(MicrosoftBuildPackageVersion)" ExcludeAssets="Runtime" PrivateAssets="All" />
<PackageReference Include="Microsoft.CodeAnalysis.CSharp.Features" Version="$(MicrosoftCodeAnalysisCSharpFeaturesPackageVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.ExternalAccess.OmniSharp.CSharp" Version="$(MicrosoftCodeAnalysisExternalAccessOmniSharpCSharpPackageVersion)" />
</ItemGroup>
</Project>

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

@ -1,33 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System.Collections.Immutable;
using System.Composition;
using System.Reflection;
using OmniSharp.Services;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
// This service provider is here to enable the OmniSharp process to indirectly utilize internal types that are exposed via the strong named
// Razor assemblies by re-exporting them via the Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp assembly. For example, we re-export the
// DefaultTagHelperResolver's factory in the strong named assembly because it's internal to Razor and can only be accessed in a strong named
// assembly.
//
// We're also unable to directly load and discover Roslyn exports in the Microsoft.CodeAnalysis.Razor.Workspaces.dll due to mismatches in
// MSBuild metadata dependencies. The expectations of the MSBuild that is loaded with OmniSharp doesn't understand the version that Razor
// is compiled against. If we could there'd be no need for this class.
[Shared]
[Export(typeof(IHostServicesProvider))]
public class OmniSharpPluginStrongNamedRoslynServiceProvider : IHostServicesProvider
{
public OmniSharpPluginStrongNamedRoslynServiceProvider()
{
var strongNamedAssembly = Assembly.Load("Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp");
Assemblies = ImmutableArray.Create(strongNamedAssembly);
}
public ImmutableArray<Assembly> Assemblies { get; }
}

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

@ -1,93 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System.Collections.Generic;
using System.Composition;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp;
using OmniSharp;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
// We need to re-export MEF based services from the OmniSharp plugin strong named assembly in order
// to make those services available via MEF. This isn't an issue for Roslyn based services because
// we're able to hook into OmniSharp's Roslyn service aggregator to allow it to inspect the strong
// named plugin assembly.
[Shared]
[Export(typeof(OmniSharpProjectSnapshotManagerDispatcher))]
internal class ExportOmniSharpProjectSnapshotManagerDispatcher : OmniSharpProjectSnapshotManagerDispatcher
{
}
[Shared]
[Export(typeof(RemoteTextLoaderFactory))]
internal class ExportRemoteTextLoaderFactory : DefaultRemoteTextLoaderFactory
{
}
[Shared]
[Export(typeof(OmniSharpProjectSnapshotManagerAccessor))]
internal class ExportDefaultOmniSharpProjectSnapshotManagerAccessor : OmniSharpProjectSnapshotManagerAccessor
{
[ImportingConstructor]
public ExportDefaultOmniSharpProjectSnapshotManagerAccessor(
RemoteTextLoaderFactory remoteTextLoaderFactory,
[ImportMany] IEnumerable<IOmniSharpProjectSnapshotManagerChangeTrigger> projectChangeTriggers,
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
OmniSharpWorkspace workspace) : base(remoteTextLoaderFactory, projectChangeTriggers, projectSnapshotManagerDispatcher, workspace)
{
}
}
[Shared]
[Export(typeof(IOmniSharpProjectSnapshotManagerChangeTrigger))]
internal class ExportOmniSharpWorkspaceProjectStateChangeDetector : OmniSharpWorkspaceProjectStateChangeDetector
{
[ImportingConstructor]
public ExportOmniSharpWorkspaceProjectStateChangeDetector(
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator,
OmniSharpLanguageServerFeatureOptions languageServerFeatureOptions)
: base(projectSnapshotManagerDispatcher, workspaceStateGenerator, languageServerFeatureOptions)
{
}
}
[Shared]
[Export(typeof(IOmniSharpProjectSnapshotManagerChangeTrigger))]
[Export(typeof(OmniSharpProjectWorkspaceStateGenerator))]
internal class ExportOmniSharpProjectWorkspaceStateGenerator : OmniSharpProjectWorkspaceStateGenerator
{
[ImportingConstructor]
public ExportOmniSharpProjectWorkspaceStateGenerator(OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher) : base(projectSnapshotManagerDispatcher)
{
}
}
[Shared]
[Export(typeof(IOmniSharpProjectSnapshotManagerChangeTrigger))]
internal class ExportOmniSharpBackgroundDocumentGenerator : OmniSharpBackgroundDocumentGenerator
{
[ImportingConstructor]
public ExportOmniSharpBackgroundDocumentGenerator(
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
RemoteTextLoaderFactory remoteTextLoaderFactory,
[ImportMany] IEnumerable<OmniSharpDocumentProcessedListener> documentProcessedListeners) : base(projectSnapshotManagerDispatcher, remoteTextLoaderFactory, documentProcessedListeners)
{
}
}
[Shared]
[Export(typeof(OmniSharpLanguageServerFeatureOptions))]
internal class ExportOmniSharpLanguageServerFeatureOptions : OmniSharpLanguageServerFeatureOptions
{
[ImportingConstructor]
public ExportOmniSharpLanguageServerFeatureOptions() : base()
{
}
}

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

@ -1,82 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Composition;
using Microsoft.CodeAnalysis;
using OmniSharp;
using OmniSharp.MSBuild.Notification;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
// This entire class is a temporary work around for https://github.com/OmniSharp/omnisharp-roslyn/issues/1443.
// We hack together a heuristic to detect when Razor documents that shouldn't be added to the workspace are and to then
// remove them from the workspace. In the primary case we're watching for pre-compiled Razor files that are generated
// from calling dotnet build and removing them from the workspace once they're added.
[Shared]
[Export(typeof(IMSBuildEventSink))]
public class PrecompiledRazorPageSuppressor : IMSBuildEventSink
{
private readonly OmniSharpWorkspace _workspace;
[ImportingConstructor]
public PrecompiledRazorPageSuppressor(OmniSharpWorkspace workspace)
{
if (workspace is null)
{
throw new ArgumentNullException(nameof(workspace));
}
_workspace = workspace;
_workspace.WorkspaceChanged += Workspace_WorkspaceChanged;
}
// Internal for testing
internal void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs args)
{
switch (args.Kind)
{
case WorkspaceChangeKind.DocumentAdded:
case WorkspaceChangeKind.DocumentChanged:
var project = args.NewSolution.GetProject(args.ProjectId);
var document = project.GetDocument(args.DocumentId);
if (document.FilePath is null)
{
break;
}
if (document.FilePath.EndsWith(".RazorTargetAssemblyInfo.cs", StringComparison.Ordinal) ||
document.FilePath.EndsWith(".RazorAssemblyInfo.cs", StringComparison.Ordinal))
{
// Razor assembly info. This doesn't catch cases when users have customized their assembly info but captures all of the
// default cases for now. Once the omnisharp-roslyn bug has been fixed this entire class can go awy so we're hacking for now.
_workspace.RemoveDocument(document.Id);
break;
}
if (!document.FilePath.EndsWith(".cshtml.g.cs", StringComparison.Ordinal) &&
!document.FilePath.EndsWith(".razor.g.cs", StringComparison.Ordinal) &&
// 2.2 only extension for generated Razor files
!document.FilePath.EndsWith(".g.cshtml.cs", StringComparison.Ordinal))
{
break;
}
// Razor output file
_workspace.RemoveDocument(document.Id);
break;
}
}
public void ProjectLoaded(ProjectLoadedEventArgs e)
{
// We don't do anything on project load we're just using the IMSBuildEventSink to ensure we're instantiated.
}
}

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

@ -1,11 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
internal abstract class ProjectChangePublisher
{
public abstract void SetPublishFilePath(string projectFilePath, string publishFilePath);
}

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

@ -1,37 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
public sealed class ProjectConfiguration
{
internal ProjectConfiguration(RazorConfiguration configuration, IReadOnlyList<OmniSharpHostDocument> documents, string rootNamespace)
{
if (configuration is null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (documents is null)
{
throw new ArgumentNullException(nameof(documents));
}
Configuration = configuration;
Documents = documents;
RootNamespace = rootNamespace;
}
public RazorConfiguration Configuration { get; }
internal IReadOnlyList<OmniSharpHostDocument> Documents { get; }
public string RootNamespace { get; }
}

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

@ -1,11 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
public abstract class ProjectConfigurationProvider
{
public abstract bool TryResolveConfiguration(ProjectConfigurationProviderContext context, out ProjectConfiguration configuration);
}

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

@ -1,35 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using Microsoft.Build.Execution;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
public sealed class ProjectConfigurationProviderContext
{
public ProjectConfigurationProviderContext(
IReadOnlyList<string> projectCapabilities,
ProjectInstance projectInstance)
{
if (projectCapabilities is null)
{
throw new ArgumentNullException(nameof(projectCapabilities));
}
if (projectInstance is null)
{
throw new ArgumentNullException(nameof(projectInstance));
}
ProjectCapabilities = projectCapabilities;
ProjectInstance = projectInstance;
}
public IReadOnlyList<string> ProjectCapabilities { get; }
public ProjectInstance ProjectInstance { get; }
}

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

@ -1,13 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using Microsoft.Build.Execution;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
public abstract class ProjectInstanceEvaluator
{
public abstract ProjectInstance Evaluate(ProjectInstance projectInstance);
}

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

@ -1,33 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System.Composition;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using OmniSharp.MSBuild.Notification;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
[Shared]
[Export(typeof(IMSBuildEventSink))]
internal class ProjectSnapshotManagerInstantiator : IMSBuildEventSink
{
// The entire purpose of this class is to ensure the project manager is instantiated.
// Without this class all exporters of AbstractOmniSharpProjectSnapshotManagerChangeTrigger
// would never be called (the class wouldn't have been created). So instead we rely
// on OmniSharp to instantiate the snapshot manager and therefore configure the
// dependent change triggers.
private readonly OmniSharpProjectSnapshotManager _projectManager;
[ImportingConstructor]
public ProjectSnapshotManagerInstantiator(OmniSharpProjectSnapshotManagerAccessor accessor)
{
_projectManager = accessor.Instance;
}
public void ProjectLoaded(ProjectLoadedEventArgs _)
{
}
}

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

@ -1,9 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.OmniSharpPlugin.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]

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

@ -1,39 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using Microsoft.AspNetCore.Razor.LanguageServer.Common;
using Microsoft.Build.Execution;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
internal class RazorFileChangeEventArgs : EventArgs
{
public RazorFileChangeEventArgs(
string filePath,
ProjectInstance projectInstance,
RazorFileChangeKind kind)
{
if (filePath is null)
{
throw new ArgumentNullException(nameof(filePath));
}
if (projectInstance is null)
{
throw new ArgumentNullException(nameof(projectInstance));
}
FilePath = filePath;
UnevaluatedProjectInstance = projectInstance;
Kind = kind;
}
public string FilePath { get; }
public ProjectInstance UnevaluatedProjectInstance { get; }
public RazorFileChangeKind Kind { get; }
}

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

@ -1,47 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Composition;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Document;
using Microsoft.AspNetCore.Razor.ProjectEngineHost;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
[Shared]
[Export(typeof(ProjectConfigurationProvider))]
internal class SystemWebConfigurationProvider : CoreProjectConfigurationProvider
{
// Internal for testing
internal const string ReferencePathWithRefAssembliesItemType = "ReferencePathWithRefAssemblies";
internal const string SystemWebRazorAssemblyFileName = "System.Web.Razor.dll";
public override bool TryResolveConfiguration(ProjectConfigurationProviderContext context, out ProjectConfiguration configuration)
{
if (HasRazorCoreCapability(context))
{
configuration = null;
return false;
}
var compilationReferences = context.ProjectInstance.GetItems(ReferencePathWithRefAssembliesItemType);
foreach (var compilationReference in compilationReferences)
{
var assemblyFullPath = compilationReference.EvaluatedInclude;
if (assemblyFullPath.EndsWith(SystemWebRazorAssemblyFileName, FilePathComparison.Instance))
{
var potentialPathSeparator = assemblyFullPath[assemblyFullPath.Length - SystemWebRazorAssemblyFileName.Length - 1];
if (potentialPathSeparator == '/' || potentialPathSeparator == '\\')
{
configuration = new ProjectConfiguration(UnsupportedRazorConfiguration.Instance, Array.Empty<OmniSharpHostDocument>(), rootNamespace: null);
return true;
}
}
}
configuration = null;
return false;
}
}

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

@ -1,202 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the MIT license. See License.txt in the project root for license information.
#nullable disable
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.ExternalAccess.OmniSharp.Project;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using OmniSharp;
using OmniSharp.MSBuild.Notification;
namespace Microsoft.AspNetCore.Razor.OmniSharpPlugin;
[Shared]
[Export(typeof(IMSBuildEventSink))]
[Export(typeof(IRazorDocumentChangeListener))]
[Export(typeof(IRazorDocumentOutputChangeListener))]
[Export(typeof(IOmniSharpProjectSnapshotManagerChangeTrigger))]
internal class TagHelperRefreshTrigger : IOmniSharpProjectSnapshotManagerChangeTrigger, IMSBuildEventSink, IRazorDocumentOutputChangeListener, IRazorDocumentChangeListener
{
private readonly OmniSharpProjectSnapshotManagerDispatcher _projectSnapshotManagerDispatcher;
private readonly Workspace _omniSharpWorkspace;
private readonly OmniSharpProjectWorkspaceStateGenerator _workspaceStateGenerator;
private readonly Dictionary<string, Task> _deferredUpdates;
private OmniSharpProjectSnapshotManager _projectManager;
[ImportingConstructor]
public TagHelperRefreshTrigger(
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
OmniSharpWorkspace omniSharpWorkspace,
OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator)
: this(projectSnapshotManagerDispatcher, (Workspace)omniSharpWorkspace, workspaceStateGenerator)
{
}
// Internal for testing
internal TagHelperRefreshTrigger(
OmniSharpProjectSnapshotManagerDispatcher projectSnapshotManagerDispatcher,
Workspace omniSharpWorkspace,
OmniSharpProjectWorkspaceStateGenerator workspaceStateGenerator)
{
if (projectSnapshotManagerDispatcher is null)
{
throw new ArgumentNullException(nameof(projectSnapshotManagerDispatcher));
}
if (omniSharpWorkspace is null)
{
throw new ArgumentNullException(nameof(omniSharpWorkspace));
}
if (workspaceStateGenerator is null)
{
throw new ArgumentNullException(nameof(workspaceStateGenerator));
}
_projectSnapshotManagerDispatcher = projectSnapshotManagerDispatcher;
_omniSharpWorkspace = omniSharpWorkspace;
_workspaceStateGenerator = workspaceStateGenerator;
_deferredUpdates = new Dictionary<string, Task>();
}
public int EnqueueDelay { get; set; } = 3 * 1000;
public void Initialize(OmniSharpProjectSnapshotManager projectManager)
{
if (projectManager is null)
{
throw new ArgumentNullException(nameof(projectManager));
}
_projectManager = projectManager;
}
public void ProjectLoaded(ProjectLoadedEventArgs args)
{
if (args is null)
{
throw new ArgumentNullException(nameof(args));
}
// Project file was modified or impacted in a significant way.
_ = _projectSnapshotManagerDispatcher.RunOnDispatcherThreadAsync(
() => EnqueueUpdate(args.ProjectInstance.ProjectFileLocation.File),
CancellationToken.None).ConfigureAwait(false);
}
public void RazorDocumentChanged(RazorFileChangeEventArgs args)
{
if (args is null)
{
throw new ArgumentNullException(nameof(args));
}
// Razor document changed
_ = Task.Factory.StartNew(
() =>
{
if (IsComponentFile(args.FilePath, args.UnevaluatedProjectInstance.ProjectFileLocation.File))
{
// Razor component file changed.
EnqueueUpdate(args.UnevaluatedProjectInstance.ProjectFileLocation.File);
}
},
CancellationToken.None,
TaskCreationOptions.None,
_projectSnapshotManagerDispatcher.DispatcherScheduler).ConfigureAwait(false);
}
public void RazorDocumentOutputChanged(RazorFileChangeEventArgs args)
{
if (args is null)
{
throw new ArgumentNullException(nameof(args));
}
// Razor build occurred
_ = Task.Factory.StartNew(
() => EnqueueUpdate(args.UnevaluatedProjectInstance.ProjectFileLocation.File),
CancellationToken.None,
TaskCreationOptions.None,
_projectSnapshotManagerDispatcher.DispatcherScheduler).ConfigureAwait(false);
}
// Internal for testing
internal async Task UpdateAfterDelayAsync(string projectFilePath)
{
if (string.IsNullOrEmpty(projectFilePath))
{
return;
}
await Task.Delay(EnqueueDelay);
var solution = _omniSharpWorkspace.CurrentSolution;
var workspaceProject = solution.Projects.FirstOrDefault(project => FilePathComparer.Instance.Equals(project.FilePath, projectFilePath));
if (workspaceProject != null && TryGetProjectSnapshot(OmniSharpProjectKey.From(workspaceProject), out var projectSnapshot))
{
_workspaceStateGenerator.Update(workspaceProject, projectSnapshot);
}
}
private void EnqueueUpdate(string projectFilePath)
{
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
// A race is not possible here because we use the main thread to synchronize the updates
// by capturing the sync context.
if (!_deferredUpdates.TryGetValue(projectFilePath, out var update) || update.IsCompleted)
{
_deferredUpdates[projectFilePath] = UpdateAfterDelayAsync(projectFilePath);
}
}
private bool TryGetProjectSnapshot(OmniSharpProjectKey projectKey, out OmniSharpProjectSnapshot projectSnapshot)
{
if (projectKey is null)
{
projectSnapshot = null;
return false;
}
projectSnapshot = _projectManager.GetLoadedProject(projectKey);
return projectSnapshot != null;
}
// Internal for testing
internal bool IsComponentFile(string relativeDocumentFilePath, string projectFilePath)
{
_projectSnapshotManagerDispatcher.AssertDispatcherThread();
foreach (var key in _projectManager.GetAllProjectKeys(projectFilePath))
{
var projectSnapshot = _projectManager.GetLoadedProject(key);
if (projectSnapshot is null)
{
continue;
}
var documentSnapshot = projectSnapshot.GetDocument(relativeDocumentFilePath);
if (documentSnapshot is null)
{
continue;
}
var isComponentKind = FileKinds.IsComponent(documentSnapshot.FileKind);
return isComponentKind;
}
return false;
}
}

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

@ -7,19 +7,6 @@
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ProjectReference
Include="..\Microsoft.AspNetCore.Razor.VSCode\Microsoft.AspNetCore.Razor.VSCode.npmproj"
ReferenceOutputAssemblies="false"
SkipGetTargetFrameworkProperties="true"
UndefineProperties="TargetFramework"
Private="false" />
</ItemGroup>
<ItemGroup>
<BuildOutputFiles Include="dist\extension.js" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Directory.Build.targets))\Directory.Build.targets" />
</Project>

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

@ -1,19 +0,0 @@
# Info
In practice the Razor VSCode extension operates as a library that [OmniSharp](https://github.com/omnisharp/omnisharp-vscode) (O#) bootstraps and includes in its operation flow. Therefore, in order to provide a dev experience for testing out Razor VSCode extension changes this project attempts to replicate what O# does to bootstrap Razor's VSCode extension library.
## Debugging
1. npm install -g typescript
1. npm install -g yarn
1. .\build.cmd
### Debugging with Omnisharp-vscode
If you need to make changes to both the Razor-vscode extension and the Omnisharp-vscode extension you might find it useful to debug through both of them at the same time.
1. Do all the steps for debugging this repo
1. Clone <https://github.com/OmniSharp/omnisharp-vscode>
1. In that repo do all the steps to debug except pressing F5.
1. Edit <https://github.com/OmniSharp/omnisharp-vscode/blob/master/.vscode/launch.json#L10> to include a second `--extensionDevelopmentPath` which points to our workspace.
1. F5 on their repo.

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

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

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

@ -1,525 +1,10 @@
{
"name": "razor-vscode",
"private": true,
"displayName": "Razor",
"description": "Razor VS Code extension bootstrapper. This extension attempts to replicate what O# does to bootstrap Razor's VSCode extension library. ",
"version": "0.0.1",
"defaults": {
"razor": "0.0.1"
},
"publisher": "ms-dotnettools",
"engines": {
"vscode": "^1.69.0"
},
"categories": [
"Other"
],
"activationEvents": [
"onWebviewPanel:razorReportIssue",
"onDebugInitialConfigurations",
"onDebugResolve:blazorwasm",
"onDebugResolve:coreclr",
"onDebugResolve:clr",
"onLanguage:csharp",
"onLanguage:aspnetcorerazor",
"onCommand:o.restart",
"onCommand:o.pickProjectAndStart",
"onCommand:o.showOutput",
"onCommand:dotnet.restore.project",
"onCommand:dotnet.restore.all",
"onCommand:dotnet.generateAssets",
"onCommand:csharp.downloadDebugger",
"onCommand:csharp.listProcess",
"onCommand:csharp.listRemoteProcess",
"onCommand:extension.configureRazorDevMode",
"onCommand:extension.resetRazorDevModeConfiguration",
"onCommand:extension.razorActivated",
"workspaceContains:project.json",
"workspaceContains:*.csproj",
"workspaceContains:*.sln",
"workspaceContains:*.csx",
"workspaceContains:*.cake",
"workspaceContains:**/*.csproj",
"workspaceContains:**/*.sln",
"workspaceContains:**/*.csx",
"workspaceContains:**/*.cake"
],
"main": "../Microsoft.AspNetCore.Razor.VSCode.Extension/dist/extension.js",
"contributes": {
"breakpoints": [
{
"language": "aspnetcorerazor"
},
{
"language": "csharp"
}
],
"debuggers": [
{
"type": "blazorwasm",
"label": "Blazor WebAssembly Debug",
"initialConfigurations": [
{
"type": "blazorwasm",
"name": "Launch and Debug Blazor WebAssembly Application",
"request": "launch"
}
],
"configurationAttributes": {
"launch": {
"properties": {
"cwd": {
"type": "string",
"description": "The directory of the Blazor WebAssembly app, defaults to the workspace folder.",
"default": "${workspaceFolder}"
},
"url": {
"type": "string",
"description": "The URL of the application",
"default": "https://localhost:5001"
},
"browser": {
"type": "string",
"description": "The debugging browser to launch (Edge or Chrome)",
"default": "edge",
"enum": [
"chrome",
"edge"
]
},
"trace": {
"type": [
"boolean",
"string"
],
"default": "true",
"enum": [
"verbose",
true
],
"description": "If true, verbose logs from JS debugger are sent to log file. If 'verbose', send logs to console."
},
"hosted": {
"type": "boolean",
"default": "false",
"description": "True if the app is a hosted Blazor WebAssembly app, false otherwise."
},
"webRoot": {
"type": "string",
"default": "${workspaceFolder}",
"description": "Specifies the absolute path to the webserver root."
},
"timeout": {
"type": "number",
"default": 30000,
"description": "Retry for this number of milliseconds to connect to browser."
},
"program": {
"type": "string",
"default": "${workspaceFolder}/Server/bin/Debug/<target-framework>/<target-dll>",
"description": "The path of the DLL to execute when launching a hosted server app"
},
"env": {
"type": "object",
"description": "Environment variables passed to dotnet. Only valid for hosted apps."
},
"dotNetConfig": {
"description": "Options passed to the underlying .NET debugger. For more info, see https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger.md.",
"type": "object",
"required": [],
"default": {},
"properties": {
"justMyCode": {
"type": "boolean",
"description": "Optional flag to only show user code.",
"default": true
},
"sourceFileMap": {
"type": "object",
"description": "Optional source file mappings passed to the debug engine. Example: '{ \"C:\\foo\":\"/home/user/foo\" }'",
"additionalProperties": {
"type": "string"
},
"default": {
"<insert-source-path-here>": "<insert-target-path-here>"
}
},
"logging": {
"description": "Optional flags to determine what types of messages should be logged to the output window.",
"type": "object",
"required": [],
"default": {},
"properties": {
"exceptions": {
"type": "boolean",
"description": "Optional flag to determine whether exception messages should be logged to the output window.",
"default": true
},
"moduleLoad": {
"type": "boolean",
"description": "Optional flag to determine whether module load events should be logged to the output window.",
"default": true
},
"programOutput": {
"type": "boolean",
"description": "Optional flag to determine whether program output should be logged to the output window when not using an external console.",
"default": true
},
"engineLogging": {
"type": "boolean",
"description": "Optional flag to determine whether diagnostic engine logs should be logged to the output window.",
"default": false
},
"browserStdOut": {
"type": "boolean",
"description": "Optional flag to determine if stdout text from the launching the web browser should be logged to the output window.",
"default": true
},
"elapsedTiming": {
"type": "boolean",
"description": "If true, engine logging will include `adapterElapsedTime` and `engineElapsedTime` properties to indicate the amount of time, in microseconds, that a request took.",
"default": false
},
"threadExit": {
"type": "boolean",
"description": "Controls if a message is logged when a thread in the target process exits. Default: `false`.",
"default": false
},
"processExit": {
"type": "boolean",
"description": "Controls if a message is logged when the target process exits, or debugging is stopped. Default: `true`.",
"default": true
}
}
}
}
},
"browserConfig": {
"description": "Options based to the underlying JavaScript debugger. For more info, see https://github.com/microsoft/vscode-js-debug/blob/main/OPTIONS.md.",
"type": "object",
"required": [],
"default": {},
"properties": {
"outputCapture": {
"enum": [
"console",
"std"
],
"description": "From where to capture output messages: the default debug API if set to `console`, or stdout/stderr streams if set to `std`.",
"default": "console"
}
}
}
}
},
"attach": {
"properties": {
"url": {
"type": "string",
"description": "The URL of the application",
"default": "https://localhost:5001"
},
"cwd": {
"type": "string",
"description": "The directory of the Blazor WebAssembly app, defaults to the workspace folder.",
"default": "${workspaceFolder}"
},
"browser": {
"type": "string",
"description": "The debugging browser to launch (Edge or Chrome)",
"default": "chrome",
"enum": [
"chrome",
"edge"
]
},
"trace": {
"type": [
"boolean",
"string"
],
"default": "true",
"enum": [
"verbose",
true
],
"description": "If true, verbose logs from JS debugger are sent to log file. If 'verbose', send logs to console."
},
"webRoot": {
"type": "string",
"default": "${workspaceFolder}",
"description": "Specifies the absolute path to the webserver root."
},
"timeout": {
"type": "number",
"default": 30000,
"description": "Retry for this number of milliseconds to connect to browser."
}
}
}
}
}
],
"semanticTokenTypes": [
{
"id": "razorComponentElement",
"description": "A Razor component element"
},
{
"id": "razorComponentAttribute",
"description": "A Razor component attribute"
},
{
"id": "razorTagHelperElement",
"description": "A Razor TagHelper Element"
},
{
"id": "razorTagHelperAttribute",
"description": "A Razor TagHelper Attribute"
},
{
"id": "razorTransition",
"description": "A Razor transition"
},
{
"id": "razorDirectiveAttribute",
"description": "A Razor Directive Attribute"
},
{
"id": "razorDirectiveColon",
"description": "A colon between directive attribute parameters"
},
{
"id": "razorDirective",
"description": "A Razor directive such as 'code' or 'function'"
},
{
"id": "razorComment",
"description": "A Razor comment"
},
{
"id": "markupCommentPunctuation",
"description": "The '@' or '*' of a Razor comment."
},
{
"id": "markupTagDelimiter",
"description": "Markup delimiters like '<', '>', and '/'."
},
{
"id": "markupOperator",
"description": "Delimiter for Markup Attribute Key-Value pairs."
},
{
"id": "markupElement",
"description": "The name of a Markup element."
},
{
"id": "markupAttribute",
"description": "The name of a Markup attribute."
},
{
"id": "markupComment",
"description": "The contents of a Markup comment."
},
{
"id": "markupCommentPunctuation",
"description": "The begining or ending punctuation of a Markup comment."
}
],
"semanticTokenScopes": [
{
"scopes": {
"razorComponentElement": [
"entity.name.class.element.component"
],
"razorComponentAttribute": [
"entity.name.class.attribute.component"
],
"razorTagHelperElement": [
"entity.name.class.element.taghelper"
],
"razorTagHelperAttribute": [
"entity.name.class.attribute.taghelper"
],
"razorTransition": [
"keyword.control.razor.transition"
],
"razorDirectiveAttribute": [
"keyword.control.razor.directive.attribute",
"keyword.control.cshtml.directive.attribute"
],
"razorDirectiveColon": [
"keyword.control.razor.directive.colon",
"keyword.control.cshtml.directive.colon"
],
"razorDirective": [
"keyword.control.razor.directive",
"keyword.control.cshtml.directive"
],
"razorComment": [
"comment.block.razor"
],
"razorCommentTransition": [
"meta.comment.razor",
"keyword.control.cshtml.transition"
],
"razorCommentStar": [
"keyword.control.razor.comment.star",
"meta.comment.razor"
],
"angleBracket": [
"punctuation.definition.tag"
],
"forwardSlash": [
"punctuation.definition.tag"
],
"equals": [
"punctuation.separator.key-value.html"
],
"markupElement": [
"entity.name.tag.html"
],
"markupAttribute": [
"entity.other.attribute-name.html"
],
"markupComment": [
"comment.block.html"
],
"markupCommentPunctuation": [
"punctuation.definition.comment.html",
"comment.block.html"
]
}
}
],
"languages": [
{
"id": "aspnetcorerazor",
"extensions": [
".cshtml",
".razor"
],
"mimetypes": [
"text/x-cshtml"
],
"configuration": "./language-configuration.json"
}
],
"grammars": [
{
"language": "aspnetcorerazor",
"scopeName": "text.aspnetcorerazor",
"path": "./syntaxes/aspnetcorerazor.tmLanguage.json",
"embeddedLanguages": {
"source.cs": "csharp",
"text.html.basic": "html",
"source.js": "javascript",
"source.css": "css"
}
}
],
"commands": [
{
"command": "extension.showRazorCSharpWindow",
"title": "Show Razor CSharp",
"category": "Razor"
},
{
"command": "extension.showRazorHtmlWindow",
"title": "Show Razor Html",
"category": "Razor"
},
{
"command": "razor.reportIssue",
"title": "Report a Razor issue",
"category": "Razor"
},
{
"command": "extension.configureRazorDevMode",
"title": "Configure workspace for Razor extension development",
"category": "Razor"
},
{
"command": "extension.resetRazorDevModeConfiguration",
"title": "Reset workspace Razor dev mode configuration",
"category": "Razor"
},
{
"command": "extension.razorActivated",
"title": "Force activation of Razor extension",
"category": "Razor"
}
],
"menus": {
"editor/title": [
{
"command": "extension.showRazorCSharpWindow",
"when": "resourceLangId == aspnetcorerazor"
},
{
"command": "extension.showRazorHtmlWindow",
"when": "resourceLangId == aspnetcorerazor"
},
{
"command": "razor.reportIssue",
"when": "resourceLangId == aspnetcorerazor"
},
{
"command": "extension.configureRazorDevMode"
},
{
"command": "extension.resetRazorDevModeConfiguration"
},
{
"command": "extension.razorActivated"
}
]
},
"configuration": {
"title": "Razor Configuration",
"properties": {
"razor.plugin.path": {
"type": [
"string",
"null"
],
"default": null,
"description": "Overrides the path to the Razor plugin dll."
},
"razor.languageServer.debug": {
"type": "boolean",
"default": false,
"description": "Specifies whether to wait for debug attach when launching the language server."
},
"razor.format.enable": {
"type": "boolean",
"scope": "window",
"default": true,
"description": "Enable/disable default Razor formatter."
}
}
}
},
"scripts": {
"vscode:prepublish": "yarn run compile",
"clean": "rimraf dist",
"build": "yarn run clean && yarn run lint && tsc -p ./ && yarn run compile:TextMate",
"lint": "tslint --project ./",
"watch": "yarn run clean && yarn run lint && tsc -watch -p ./",
"build": "yarn run compile:TextMate",
"compile:TextMate": "npx js-yaml syntaxes/aspnetcorerazor.tmLanguage.yml > syntaxes/aspnetcorerazor.tmLanguage.json"
},
"devDependencies": {
"@types/node": "^17.0.2",
"@types/vscode": "1.69.0",
"cross-env": "^5.2.0",
"js-yaml": ">=3.13.1",
"minimatch": "3.0.5",
"rimraf": "2.6.3",
"tslint": "^5.11.0",
"typescript": "^4.5.4"
},
"dependencies": {
"diff": ">=3.5.0",
"microsoft.aspnetcore.razor.vscode": "file:../Microsoft.AspNetCore.Razor.VSCode"
"js-yaml": ">=3.13.1"
}
}
}

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

@ -1,62 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as fs from 'fs';
import * as path from 'path';
import * as vscode from 'vscode';
export async function registerRazorDevModeHelpers(context: vscode.ExtensionContext) {
const razorConfiguration = vscode.workspace.getConfiguration('razor');
const unconfigureSubscription = vscode.commands.registerCommand('extension.resetRazorDevModeConfiguration', async () => {
await razorConfiguration.update('devmode', undefined);
const pluginConfiguration = vscode.workspace.getConfiguration('razor.plugin');
await pluginConfiguration.update('path', undefined);
// Settings have been updated, lets reload the window.
await vscode.commands.executeCommand('workbench.action.reloadWindow');
});
context.subscriptions.push(unconfigureSubscription);
const configureSubscription = vscode.commands.registerCommand('extension.configureRazorDevMode', async () => {
await razorConfiguration.update('devmode', true);
await razorConfiguration.update('trace', 'Verbose');
const config = process.env.config ? process.env.config : 'Debug';
const pluginPath = path.join(
__dirname, '..', '..', '..', '..', '..', 'artifacts', 'bin', 'Microsoft.AspNetCore.Razor.OmniSharpPlugin', config, 'net472', 'Microsoft.AspNetCore.Razor.OmniSharpPlugin.dll');
if (!fs.existsSync(pluginPath)) {
vscode.window.showErrorMessage(`The Razor Language Server O# plugin has not yet been built - could not find ${pluginPath}`);
return;
}
const pluginConfiguration = vscode.workspace.getConfiguration('razor.plugin');
await pluginConfiguration.update('path', pluginPath);
// Settings have been updated, lets reload the window.
await vscode.commands.executeCommand('workbench.action.reloadWindow');
});
context.subscriptions.push(configureSubscription);
}
export function ensureWorkspaceIsConfigured() {
const razorConfiguration = vscode.workspace.getConfiguration('razor');
if (!razorConfiguration.get('devmode')) {
// Running in a workspace without devmode enabled. We should prompt the user to configure the workspace.
vscode.window.showErrorMessage(
'This workspace is not configured to use the local Razor extension.',
'Configure and Reload').then(async (reloadResponse) => {
if (reloadResponse === 'Configure and Reload') {
await vscode.commands.executeCommand('extension.configureRazorDevMode');
}
});
return false;
}
return true;
}

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

@ -1,63 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as fs from 'fs';
import * as razorExtensionPackage from 'microsoft.aspnetcore.razor.vscode';
import * as path from 'path';
import * as vscode from 'vscode';
import { ensureWorkspaceIsConfigured, registerRazorDevModeHelpers } from './RazorDevModeHelpers';
let activationResolver: (value?: any) => void;
export const extensionActivated = new Promise(resolve => {
activationResolver = resolve;
});
export async function activate(context: vscode.ExtensionContext) {
// Because this extension is only used for local development and tests in CI,
// we know the Razor Language Server is at a specific path within this repo
const config = process.env.config ? process.env.config : 'Debug';
const languageServerDir = path.join(
__dirname, '..', '..', '..', '..', '..', 'artifacts', 'bin', 'rzls', config, 'net7.0');
if (!fs.existsSync(languageServerDir)) {
vscode.window.showErrorMessage(`The Razor Language Server project has not yet been built - could not find ${languageServerDir}`);
return;
}
const hostEventStream = {
post: (event: any) => {
// 1 corresponds to the telemetry event type from OmniSharp
if (event.type === 1) {
console.log(`Telemetry Event: ${event.eventName}.`);
if (event.properties) {
const propertiesString = JSON.stringify(event.properties, null, 2);
console.log(propertiesString);
}
} else {
console.log(`Unknown event: ${event.eventName}`);
}
},
};
vscode.commands.registerCommand('extension.razorActivated', () => extensionActivated);
await registerRazorDevModeHelpers(context);
const workspaceConfigured = ensureWorkspaceIsConfigured();
if (workspaceConfigured) {
await razorExtensionPackage.activate(
vscode,
context,
languageServerDir,
hostEventStream,
/* enabledProposedApis */true);
} else {
console.warn('Razor workspace was not configured, extension activation skipped.');
console.warn('To configure your workspace run the following command (ctrl+shift+p) in the experimental instance "Razor: Configure workspace for Razor extension development"');
}
activationResolver();
}

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

@ -1,9 +0,0 @@
{
"extends": "../../tsconfig.json",
"compilerOptions": {
"outDir": "dist"
},
"include": [
"./src/**/*"
]
}

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

@ -1,3 +0,0 @@
{
"extends": "../../tslint.json"
}

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

@ -1,2 +0,0 @@
# Auto generated file from Gardener Plugin CentralFeedServiceAdoptionPlugin
registry=https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet-public-npm/npm/registry/

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

@ -1,20 +0,0 @@
<Project DefaultTargets="Build">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Directory.Build.props))\Directory.Build.props" />
<PropertyGroup>
<PackageId>microsoft.aspnetcore.razor.vscode</PackageId>
<TargetFramework>netstandard2.0</TargetFramework>
<IsPackable Condition="'$(OS)' == 'Windows_NT'">true</IsPackable>
<!-- We technically ship this to a blob feed and then manually integrate with O#. Don't want this package making its way anywhere else. -->
<IsShippingPackage>false</IsShippingPackage>
</PropertyGroup>
<ItemGroup>
<BuildOutputFiles Include="dist\extension.js" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), Directory.Build.targets))\Directory.Build.targets" />
</Project>

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

@ -1,35 +0,0 @@
{
"name": "microsoft.aspnetcore.razor.vscode",
"private": true,
"version": "0.0.1",
"defaults": {
"razor": "0.0.1"
},
"description": "VS Code library for Razor language support.",
"devDependencies": {
"@types/node": "^10.9.4",
"@types/vscode": "1.69.0",
"js-yaml": ">=3.13.1",
"minimatch": "3.0.5",
"rimraf": "2.6.3",
"tslint": "^5.11.0",
"typescript": "~4.5.4"
},
"dependencies": {
"ps-list": "7.2.0",
"vscode-html-languageservice": "^5.0.1",
"vscode-languageclient": "8.0.2",
"vscode-languageserver-textdocument": "^1.0.5"
},
"main": "./dist/extension.js",
"types": "./dist/extension.d.ts",
"engines": {
"vscode": "1.69.0"
},
"scripts": {
"clean": "rimraf out && rimraf dist",
"build": "yarn run clean && yarn run lint && tsc -p ./",
"lint": "tslint ./src/**/*.ts --project ./",
"watch": "tsc -watch -p ./"
}
}

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

@ -1,142 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { readFileSync } from 'fs';
import { join } from 'path';
import { fileURLToPath } from 'url';
import * as vscode from 'vscode';
import { RazorLogger } from '../RazorLogger';
import { JS_DEBUG_NAME, SERVER_APP_NAME } from './Constants';
import { onDidTerminateDebugSession } from './TerminateDebugHandler';
export class BlazorDebugConfigurationProvider implements vscode.DebugConfigurationProvider {
constructor(private readonly logger: RazorLogger, private readonly vscodeType: typeof vscode) { }
public async resolveDebugConfiguration(folder: vscode.WorkspaceFolder | undefined, configuration: vscode.DebugConfiguration): Promise<vscode.DebugConfiguration | undefined> {
/**
* The Blazor WebAssembly app should only be launched if the
* launch configuration is a launch request. Attach requests will
* only launch the browser.
*/
if (configuration.request === 'launch') {
await this.launchApp(folder, configuration);
}
let inspectUri = '{wsProtocol}://{url.hostname}:{url.port}/_framework/debug/ws-proxy?browser={browserInspectUri}';
let url = 'https://localhost:5001';
try {
if (folder !== undefined) {
let folderPath = configuration.cwd ? configuration.cwd : fileURLToPath(folder.uri.toString());
folderPath = folderPath.replace('${workspaceFolder}', fileURLToPath(folder.uri.toString()));
const launchSettings = JSON.parse(readFileSync(join(folderPath, 'Properties', 'launchSettings.json'), 'utf8'));
if (launchSettings?.profiles && launchSettings?.profiles[Object.keys(launchSettings.profiles)[0]]?.inspectUri) {
inspectUri = launchSettings.profiles[Object.keys(launchSettings.profiles)[0]].inspectUri;
url = launchSettings.profiles[Object.keys(launchSettings.profiles)[0]].applicationUrl.split(';', 1)[0];
}
}
} catch (error: any) {
this.logger.logError('[DEBUGGER] Error while getting information from launchSettings.json: ', error as Error);
}
await this.launchBrowser(
folder,
configuration,
inspectUri,
url);
/**
* If `resolveDebugConfiguration` returns undefined, then the debugger
* launch is canceled. Here, we opt to manually launch the browser
* configuration using `startDebugging` above instead of returning
* the configuration to avoid a bug where VS Code is unable to resolve
* the debug adapter for the browser debugger.
*/
return undefined;
}
private async launchApp(folder: vscode.WorkspaceFolder | undefined, configuration: vscode.DebugConfiguration) {
const program = configuration.hosted ? configuration.program : 'dotnet';
const cwd = configuration.cwd || '${workspaceFolder}';
const args = configuration.hosted ? [] : ['run'];
const app = {
name: SERVER_APP_NAME,
type: 'coreclr',
request: 'launch',
prelaunchTask: 'build',
program,
args,
cwd,
env: {
ASPNETCORE_ENVIRONMENT: 'Development',
...configuration.env,
},
launchBrowser: {
enabled: false,
},
...configuration.dotNetConfig,
};
try {
await this.vscodeType.debug.startDebugging(folder, app);
if (process.platform !== 'win32') {
const terminate = this.vscodeType.debug.onDidTerminateDebugSession(async event => {
const blazorDevServer = 'blazor-devserver\\.dll';
const dir = folder && folder.uri && folder.uri.fsPath;
const regexEscapedDir = dir!.toLowerCase()!.replace(/\//g, '\\/');
const launchedApp = configuration.hosted ? app.program : `${regexEscapedDir}.*${blazorDevServer}|${blazorDevServer}.*${regexEscapedDir}`;
await onDidTerminateDebugSession(event, this.logger, launchedApp);
terminate.dispose();
});
}
} catch (error) {
this.logger.logError('[DEBUGGER] Error when launching application: ', error as Error);
}
}
private async launchBrowser(folder: vscode.WorkspaceFolder | undefined, configuration: vscode.DebugConfiguration, inspectUri: string, url: string) {
const browser = {
name: JS_DEBUG_NAME,
type: configuration.browser === 'edge' ? 'pwa-msedge' : 'pwa-chrome',
request: 'launch',
timeout: configuration.timeout || 30000,
url: configuration.url || url,
webRoot: configuration.webRoot || '${workspaceFolder}',
inspectUri,
trace: configuration.trace || false,
noDebug: configuration.noDebug || false,
...configuration.browserConfig,
// When the browser debugging session is stopped, propogate
// this and terminate the debugging session of the Blazor dev server.
cascadeTerminateToConfigurations: [SERVER_APP_NAME],
};
try {
/**
* The browser debugger will immediately launch after the
* application process is started. It waits a `timeout`
* interval before crashing after being unable to find the launched
* process.
*
* We do this to provide immediate visual feedback to the user
* that their debugger session has started.
*/
await this.vscodeType.debug.startDebugging(folder, browser);
} catch (error) {
this.logger.logError(
'[DEBUGGER] Error when launching browser debugger: ',
error as Error,
);
const message = `There was an unexpected error while launching your debugging session. Check the console for helpful logs and visit the debugging docs for more info.`;
this.vscodeType.window.showErrorMessage(message, `View Debug Docs`, `Ignore`).then(async result => {
if (result === 'View Debug Docs') {
const debugDocsUri = 'https://aka.ms/blazorwasmcodedebug';
await this.vscodeType.commands.executeCommand(`vcode.open`, debugDocsUri);
}
});
}
}
}

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

@ -1,7 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
export const SERVER_APP_NAME = '.NET Application Server';
export const JS_DEBUG_NAME = 'Debug Blazor Web Assembly in Browser';

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

@ -1,86 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as psList from 'ps-list';
import { DebugSession } from 'vscode';
import { RazorLogger } from '../RazorLogger';
import { JS_DEBUG_NAME, SERVER_APP_NAME } from './Constants';
export const isValidEvent = (name: string) => {
// The name can be of the form: `Debug Blazor Web Assembly in Browser: https://localhost:7291`
// hence we have to examine what the name **startsWith**
// we cannot use startsWith otherwise when we close a login window we will receive a name like this
// `Debug Blazor Web Assembly in Browser: https://localhost:5001/authentication/login-callback#state=eyJpZCI6ImEwYjQ5MDMzL` and will kill the app
return name === JS_DEBUG_NAME || name === SERVER_APP_NAME;
};
const killProcess = (targetPid: number | undefined, logger: RazorLogger) => {
// If no PID was provided, then exit early.
if (!targetPid) {
return;
}
try {
logger.logVerbose(`[DEBUGGER] Terminating debugging session with PID ${targetPid}...`);
process.kill(targetPid);
} catch (error) {
logger.logError(`[DEBUGGER] Error terminating debug processes with PID ${targetPid}: `, error as Error);
}
};
export async function onDidTerminateDebugSession(
event: DebugSession,
logger: RazorLogger,
target: string | number | undefined,
) {
if (!target) {
return;
}
if (typeof target === 'number') {
terminateByPid(event, logger, target);
} else {
await terminateByProcessName(event, logger, target);
}
}
function terminateByPid(
event: DebugSession,
logger: RazorLogger,
targetPid: number | undefined,
) {
// Ignore debug sessions that are not applicable to us
if (!isValidEvent(event.name)) {
return;
}
killProcess(targetPid, logger);
}
async function terminateByProcessName(
event: DebugSession,
logger: RazorLogger,
targetProcess: string,
) {
// Ignore debug sessions that are not applicable to us
if (!isValidEvent(event.name)) {
return;
}
let processes: psList.ProcessDescriptor[] = [];
try {
processes = await psList();
} catch (error) {
logger.logError(`Error retrieving processes to clean-up: `, error as Error);
}
const devserver = processes.find(
(process: psList.ProcessDescriptor) => !!(process && process.cmd && process.cmd.toLowerCase().match(targetProcess)));
if (devserver) {
killProcess(devserver.pid, logger);
}
}

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

@ -1,141 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { IRazorDocumentChangeEvent } from '../Document/IRazorDocumentChangeEvent';
import { RazorDocumentChangeKind } from '../Document/RazorDocumentChangeKind';
import { RazorDocumentManager } from '../Document/RazorDocumentManager';
import { getUriPath } from '../UriPaths';
export class CSharpPreviewPanel {
public static readonly viewType = 'razorCSharpPreview';
private panel: vscode.WebviewPanel | undefined;
private csharpContent: string | undefined;
constructor(
private readonly documentManager: RazorDocumentManager) {
documentManager.onChange((event) => this.documentChanged(event));
}
public async show() {
if (this.panel) {
this.panel.reveal(vscode.ViewColumn.Two);
} else {
this.panel = vscode.window.createWebviewPanel(
CSharpPreviewPanel.viewType,
'Razor C# Preview',
vscode.ViewColumn.Two, {
enableScripts: true,
// Disallow any remote sources
localResourceRoots: [],
});
this.attachToCurrentPanel();
}
await this.update();
}
public async revive(panel: vscode.WebviewPanel) {
this.panel = panel;
this.attachToCurrentPanel();
await this.update();
}
private async documentChanged(event: IRazorDocumentChangeEvent) {
if (!this.panel) {
return;
}
if (event.kind === RazorDocumentChangeKind.csharpChanged ||
event.kind === RazorDocumentChangeKind.opened ||
event.kind === RazorDocumentChangeKind.closed) {
await this.update();
}
}
private attachToCurrentPanel() {
if (!this.panel) {
vscode.window.showErrorMessage('Unexpected error when attaching to C# preview window.');
return;
}
this.panel.webview.onDidReceiveMessage(async message => {
switch (message.command) {
case 'copy':
if (!this.csharpContent) {
return;
}
await vscode.env.clipboard.writeText(this.csharpContent);
vscode.window.showInformationMessage('Razor C# copied to clipboard');
return;
}
});
this.panel.onDidDispose(() => this.panel = undefined);
}
private async update() {
if (!this.panel) {
return;
}
const document = await this.documentManager.getActiveDocument();
let hostDocumentFilePath = '';
let virtualDocumentFilePath = '';
if (document) {
// The document is guaranteed to be a Razor document
this.csharpContent = document.csharpDocument.getContent();
hostDocumentFilePath = getUriPath(document.uri);
virtualDocumentFilePath = getUriPath(document.csharpDocument.uri);
} else {
this.csharpContent = undefined;
}
let content = this.csharpContent ? this.csharpContent : '';
content = content.replace(/</g, '&lt;').replace(/</g, '&gt;');
this.panel.webview.html = `<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Report a Razor issue</title>
<style>
button {
background-color: #eff3f6;
background-image: linear-gradient(-180deg,#fafbfc,#eff3f6 90%);
color: #24292e;
border: 1px solid rgba(27,31,35,.2);
border-radius: .25em;
font-size: 1.1em;
font-weight: 600;
line-height: 18px;
padding: 6px 12px;
vertical-align: middle;
cursor: pointer;
}
</style>
<script type="text/javascript">
const vscode = acquireVsCodeApi();
function copy() {
vscode.postMessage({
command: 'copy'
});
}
</script>
</head>
<body>
<p>Host document file path: <strong>${hostDocumentFilePath}</strong></p>
<p>Virtual document file path: <strong>${virtualDocumentFilePath}</strong></p
<p><button onclick="copy()">Copy C#</button></p>
<hr />
<pre>${content}</pre>
</body>
</html>`;
}
}

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

@ -1,102 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { IProjectedDocument } from '../Projection/IProjectedDocument';
import { ServerTextChange } from '../RPC/ServerTextChange';
import { getUriPath } from '../UriPaths';
import * as vscode from '../vscodeAdapter';
export class CSharpProjectedDocument implements IProjectedDocument {
public readonly path: string;
private content = '';
private preProvisionalContent: string | undefined;
private provisionalEditAt: number | undefined;
private hostDocumentVersion: number | null = null;
private projectedDocumentVersion = 0;
public constructor(public readonly uri: vscode.Uri) {
this.path = getUriPath(uri);
}
public get hostDocumentSyncVersion(): number | null {
return this.hostDocumentVersion;
}
public get projectedDocumentSyncVersion(): number {
return this.projectedDocumentVersion;
}
public update(edits: ServerTextChange[], hostDocumentVersion: number) {
this.removeProvisionalDot();
this.hostDocumentVersion = hostDocumentVersion;
if (edits.length === 0) {
return;
}
let content = this.content;
for (const edit of edits.reverse()) {
// TODO: Use a better data structure to represent the content, string concatenation is slow.
content = this.getEditedContent(edit.newText, edit.span.start, edit.span.start + edit.span.length, content);
}
this.setContent(content);
}
public reset() {
this.provisionalEditAt = undefined;
this.preProvisionalContent = undefined;
this.hostDocumentVersion = null;
this.setContent('');
}
public getContent() {
return this.content;
}
// A provisional dot represents a '.' that's inserted into the projected document but will be
// removed prior to any edits that get applied. In Razor's case a provisional dot is used to
// show completions after an expression for a dot that's usually interpreted as Html.
public addProvisionalDotAt(index: number) {
if (this.provisionalEditAt === index) {
// Edits already applied.
return;
}
this.removeProvisionalDot();
const newContent = this.getEditedContent('.', index, index, this.content);
this.preProvisionalContent = this.content;
this.provisionalEditAt = index;
this.setContent(newContent);
}
public removeProvisionalDot() {
if (this.provisionalEditAt && this.preProvisionalContent) {
// Undo provisional edit if one was applied.
this.setContent(this.preProvisionalContent);
this.provisionalEditAt = undefined;
this.preProvisionalContent = undefined;
return true;
}
return false;
}
private getEditedContent(newText: string, start: number, end: number, content: string) {
const before = content.substr(0, start);
const after = content.substr(end);
content = `${before}${newText}${after}`;
return content;
}
private setContent(content: string) {
this.projectedDocumentVersion++;
this.content = content;
}
}

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

@ -1,70 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { IRazorDocumentChangeEvent } from '../Document/IRazorDocumentChangeEvent';
import { IRazorDocumentManager } from '../Document/IRazorDocumentManager';
import { RazorDocumentChangeKind } from '../Document/RazorDocumentChangeKind';
import { IEventEmitterFactory } from '../IEventEmitterFactory';
import { RazorLogger } from '../RazorLogger';
import { getUriPath } from '../UriPaths';
import * as vscode from '../vscodeAdapter';
export class CSharpProjectedDocumentContentProvider implements vscode.TextDocumentContentProvider {
public static readonly scheme = 'virtualCSharp-razor';
private readonly onDidChangeEmitter: vscode.EventEmitter<vscode.Uri>;
constructor(
private readonly documentManager: IRazorDocumentManager,
eventEmitterFactory: IEventEmitterFactory,
private readonly logger: RazorLogger) {
documentManager.onChange((event: IRazorDocumentChangeEvent) => this.documentChanged(event));
this.onDidChangeEmitter = eventEmitterFactory.create<vscode.Uri>();
}
public get onDidChange() { return this.onDidChangeEmitter.event; }
public async provideTextDocumentContent(uri: vscode.Uri) {
const razorDocument = this.findRazorDocument(uri);
if (!razorDocument) {
// Document was removed from the document manager, meaning there's no more content for this
// file. Report an empty document.
if (this.logger.verboseEnabled) {
this.logger.logVerbose(
`Could not find document '${getUriPath(uri)}' when updating the C# buffer. This typically happens when a document is removed.`);
}
return '';
}
const content = `${razorDocument.csharpDocument.getContent()}
// ${razorDocument.csharpDocument.projectedDocumentSyncVersion}`;
return content;
}
public ensureDocumentContent(uri: vscode.Uri) {
this.onDidChangeEmitter.fire(uri);
}
private documentChanged(event: IRazorDocumentChangeEvent) {
if (event.kind === RazorDocumentChangeKind.csharpChanged ||
event.kind === RazorDocumentChangeKind.opened ||
event.kind === RazorDocumentChangeKind.removed) {
// We also notify changes on document removal in order to tell VSCode that there's no more
// C# content for the file.
this.onDidChangeEmitter.fire(event.document.csharpDocument.uri);
}
}
private findRazorDocument(uri: vscode.Uri) {
const projectedPath = getUriPath(uri);
return this.documentManager.documents.find(razorDocument =>
razorDocument.csharpDocument.path.localeCompare(
projectedPath, undefined, { sensitivity: 'base' }) === 0);
}
}

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

@ -1,43 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { RazorDocumentManager } from '../Document/RazorDocumentManager';
import { IEventEmitterFactory } from '../IEventEmitterFactory';
import { RazorLogger } from '../RazorLogger';
import { CSharpPreviewPanel } from './CSharpPreviewPanel';
import { CSharpProjectedDocumentContentProvider } from './CSharpProjectedDocumentContentProvider';
export class RazorCSharpFeature {
public readonly projectionProvider: CSharpProjectedDocumentContentProvider;
private readonly csharpPreviewPanel: CSharpPreviewPanel;
constructor(
documentManager: RazorDocumentManager,
eventEmitterFactory: IEventEmitterFactory,
logger: RazorLogger) {
this.projectionProvider = new CSharpProjectedDocumentContentProvider(documentManager, eventEmitterFactory, logger);
this.csharpPreviewPanel = new CSharpPreviewPanel(documentManager);
}
public register() {
const registrations = [
vscode.workspace.registerTextDocumentContentProvider(
CSharpProjectedDocumentContentProvider.scheme, this.projectionProvider),
vscode.commands.registerCommand(
'extension.showRazorCSharpWindow', () => this.csharpPreviewPanel.show()),
];
if (vscode.window.registerWebviewPanelSerializer) {
registrations.push(vscode.window.registerWebviewPanelSerializer(CSharpPreviewPanel.viewType, {
deserializeWebviewPanel: async (panel: vscode.WebviewPanel) => {
await this.csharpPreviewPanel.revive(panel);
},
}));
}
return vscode.Disposable.from(...registrations);
}
}

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

@ -1,66 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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 { RequestType } from 'vscode-languageclient';
import { RazorDocumentManager } from '../Document/RazorDocumentManager';
import { RazorLanguageServerClient } from '../RazorLanguageServerClient';
import { RazorLogger } from '../RazorLogger';
import { convertRangeFromSerializable } from '../RPC/SerializableRange';
import { RazorCodeAction } from './RazorCodeAction';
import { SerializableDelegatedCodeActionParams } from './SerializableDelegatedCodeActionParams';
export class CodeActionsHandler {
private static readonly provideCodeActionsEndpoint = 'razor/provideCodeActions';
private codeActionRequestType: RequestType<SerializableDelegatedCodeActionParams, RazorCodeAction[], any> = new RequestType(CodeActionsHandler.provideCodeActionsEndpoint);
private emptyCodeActionResponse: RazorCodeAction[] = [];
constructor(
private readonly documentManager: RazorDocumentManager,
private readonly serverClient: RazorLanguageServerClient,
private readonly logger: RazorLogger) { }
public register() {
return this.serverClient.onRequestWithParams<SerializableDelegatedCodeActionParams, RazorCodeAction[], any>(
this.codeActionRequestType,
async (request, token) => this.provideCodeActions(request, token));
}
private async provideCodeActions(
delegatedCodeActionParams: SerializableDelegatedCodeActionParams,
cancellationToken: vscode.CancellationToken) {
try {
const codeActionParams = delegatedCodeActionParams.codeActionParams;
const razorDocumentUri = vscode.Uri.parse(codeActionParams.textDocument.uri, true);
const razorDocument = await this.documentManager.getDocument(razorDocumentUri);
if (razorDocument === undefined) {
return this.emptyCodeActionResponse;
}
const virtualCSharpUri = razorDocument.csharpDocument.uri;
const range = convertRangeFromSerializable(codeActionParams.range);
const commands = await vscode.commands.executeCommand<vscode.Command[]>(
'vscode.executeCodeActionProvider',
virtualCSharpUri,
range) as vscode.Command[];
if (commands.length === 0) {
return this.emptyCodeActionResponse;
}
return commands.map(c => this.commandAsCodeAction(c));
} catch (error) {
this.logger.logWarning(`${CodeActionsHandler.provideCodeActionsEndpoint} failed with ${error}`);
}
return this.emptyCodeActionResponse;
}
private commandAsCodeAction(command: vscode.Command): RazorCodeAction {
return { title: command.title, data: { CustomTags: ['CodeActionFromVSCode'] } } as RazorCodeAction;
}
}

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

@ -1,14 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { SerializableWorkspaceEdit } from '../RPC/SerializableWorkspaceEdit';
import { RazorCodeActionDataParams } from './RazorCodeActionDataParams';
import { RazorCodeActionResolutionParams } from './RazorCodeActionResolutionParams';
export interface RazorCodeAction {
title: string;
edit: SerializableWorkspaceEdit;
data: RazorCodeActionResolutionParams | RazorCodeActionDataParams;
}

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

@ -1,8 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
export interface RazorCodeActionDataParams {
CustomTags: string[];
}

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

@ -1,9 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
export interface RazorCodeActionResolutionParams {
action: string;
data: object;
}

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

@ -1,47 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { RazorLanguageServerClient } from '../RazorLanguageServerClient';
import { RazorLogger } from '../RazorLogger';
import { convertWorkspaceEditFromSerializable } from '../RPC/SerializableWorkspaceEdit';
import { RazorCodeAction } from './RazorCodeAction';
import { RazorCodeActionResolutionParams } from './RazorCodeActionResolutionParams';
export class RazorCodeActionRunner {
private static readonly codeActionResolveEndpoint = 'textDocument/codeActionResolve';
private static readonly razorCodeActionRunnerCommand = 'razor/runCodeAction';
constructor(
private readonly serverClient: RazorLanguageServerClient,
private readonly logger: RazorLogger,
) {}
public register(): vscode.Disposable {
return vscode.commands.registerCommand(
RazorCodeActionRunner.razorCodeActionRunnerCommand,
(request: RazorCodeActionResolutionParams) => this.runCodeAction(request),
this);
}
private async runCodeAction(request: RazorCodeActionResolutionParams): Promise<boolean> {
const response: RazorCodeAction = await this.serverClient.sendRequest(
RazorCodeActionRunner.codeActionResolveEndpoint,
{ data: request, title: request.action });
let changesWorkspaceEdit: vscode.WorkspaceEdit;
let documentChangesWorkspaceEdit: vscode.WorkspaceEdit;
try {
changesWorkspaceEdit = convertWorkspaceEditFromSerializable({changes: response.edit.changes});
documentChangesWorkspaceEdit = convertWorkspaceEditFromSerializable({documentChanges: response.edit.documentChanges});
} catch (error) {
this.logger.logError(`Unexpected error deserializing code action for ${request.action}`, error as Error);
return Promise.resolve(false);
}
return vscode.workspace.applyEdit(documentChangesWorkspaceEdit).then(() => vscode.workspace.applyEdit(changesWorkspaceEdit));
}
}

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

@ -1,12 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { SerializableRange } from '../RPC/SerializableRange';
import { SerializableTextDocumentIdentifier } from '../RPC/SerializableTextDocumentIdentifier';
export interface SerializableCodeActionParams {
textDocument: SerializableTextDocumentIdentifier;
range: SerializableRange;
}

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

@ -1,10 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { SerializableCodeActionParams } from './SerializableCodeActionParams';
export interface SerializableDelegatedCodeActionParams {
codeActionParams: SerializableCodeActionParams;
}

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

@ -1,17 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 RazorCodeLens extends vscode.CodeLens {
constructor(
range: vscode.Range,
public uri: vscode.Uri,
public document: vscode.TextDocument,
command?: vscode.Command) {
super(range, command);
}
}

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

@ -1,134 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { RazorDocumentChangeKind } from '../Document/RazorDocumentChangeKind';
import { RazorDocumentManager } from '../Document/RazorDocumentManager';
import { RazorDocumentSynchronizer } from '../Document/RazorDocumentSynchronizer';
import { RazorLanguageFeatureBase } from '../RazorLanguageFeatureBase';
import { RazorLanguageServiceClient } from '../RazorLanguageServiceClient';
import { RazorLogger } from '../RazorLogger';
import { LanguageKind } from '../RPC/LanguageKind';
import { RazorCodeLens } from './RazorCodeLens';
export class RazorCodeLensProvider
extends RazorLanguageFeatureBase
implements vscode.CodeLensProvider {
public onDidChangeCodeLenses: vscode.Event<void>;
constructor(
documentSynchronizer: RazorDocumentSynchronizer,
documentManager: RazorDocumentManager,
serviceClient: RazorLanguageServiceClient,
logger: RazorLogger) {
super(documentSynchronizer, documentManager, serviceClient, logger);
const onCodeLensChangedEmitter = new vscode.EventEmitter<void>();
this.onDidChangeCodeLenses = onCodeLensChangedEmitter.event;
documentManager.onChange(async (event) => {
if (event.kind !== RazorDocumentChangeKind.added) {
return;
}
// Sometimes when a file already open in the editor is renamed, provideCodeLens would return empty
// because the background C# document is not ready yet. So, when that happens we should manually invoke
// a code lens refresh after waiting for a little while.
const openDocumentUris = vscode.workspace.textDocuments.filter(doc => !doc.isClosed).map(doc => doc.uri);
if (openDocumentUris.includes(event.document.uri)) {
await new Promise(r => setTimeout(r, 5000));
onCodeLensChangedEmitter.fire();
}
});
}
public async provideCodeLenses(document: vscode.TextDocument, token: vscode.CancellationToken) {
try {
const razorDocument = await this.documentManager.getDocument(document.uri);
if (!razorDocument) {
return;
}
const csharpDocument = razorDocument.csharpDocument;
// Get all the code lenses that applies to our projected C# document.
const codeLenses = await vscode.commands.executeCommand<vscode.CodeLens[]>(
'vscode.executeCodeLensProvider',
csharpDocument.uri) as vscode.CodeLens[];
if (!codeLenses) {
return;
}
// Re-map the CodeLens locations to the original Razor document.
const remappedCodeLenses = new Array<vscode.CodeLens>();
for (const codeLens of codeLenses) {
const result = await this.serviceClient.mapToDocumentRanges(
LanguageKind.CSharp,
[codeLens.range],
razorDocument.uri);
if (result && result.ranges.length > 0) {
const newCodeLens = new RazorCodeLens(result.ranges[0], razorDocument.uri, document, codeLens.command);
remappedCodeLenses.push(newCodeLens);
} else {
// This means this CodeLens was for non-user code. We can safely ignore those.
}
}
return remappedCodeLenses;
} catch (error) {
this.logger.logWarning(`provideCodeLens failed with ${error}`);
return [];
}
}
public async resolveCodeLens(codeLens: vscode.CodeLens, token: vscode.CancellationToken) {
if (codeLens instanceof RazorCodeLens) {
return this.resolveRazorCodeLens(codeLens, token);
}
}
private async resolveRazorCodeLens(codeLens: RazorCodeLens, token: vscode.CancellationToken): Promise<vscode.CodeLens> {
// Initialize with default values.
codeLens.command = {
title: '',
command: '',
arguments: [],
};
try {
const razorDocument = await this.documentManager.getDocument(codeLens.uri);
if (!razorDocument) {
return codeLens;
}
// Make sure this CodeLens is for a valid location in the projected C# document.
const projection = await this.getProjection(codeLens.document, codeLens.range.start, token);
if (!projection || projection.languageKind !== LanguageKind.CSharp) {
return codeLens;
}
const references = await vscode.commands.executeCommand<vscode.Location[]>(
'vscode.executeReferenceProvider',
projection.uri,
projection.position) as vscode.Location[];
// We now have a list of references to show in the CodeLens.
const count = references.length;
codeLens.command = {
title: count === 1 ? '1 reference' : `${count} references`,
command: 'editor.action.showReferences',
arguments: [razorDocument.uri, codeLens.range.start, references],
};
return codeLens;
} catch (error) {
this.logger.logWarning(`resolveCodeLens failed with ${error}`);
return codeLens;
}
}
}

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

@ -1,14 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { Range } from 'vscode-languageserver-types';
export class ColorPresentationContext {
constructor(
public readonly uri: vscode.Uri,
public readonly range: Range) {
}
}

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

@ -1,92 +0,0 @@
/*---------------------------------------------------------------------------------------------
* 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 { RequestType } from 'vscode-languageclient';
import { RazorDocumentManager } from '../Document/RazorDocumentManager';
import { RazorLanguageServerClient } from '../RazorLanguageServerClient';
import { RazorLogger } from '../RazorLogger';
import { convertTextEditToSerializable, SerializableTextEdit } from '../RPC/SerializableTextEdit';
import { ColorPresentationContext } from './ColorPresentationContext';
import { SerializableColorPresentation } from './SerializableColorPresentation';
import { SerializableColorPresentationParams } from './SerializableColorPresentationParams';
export class ColorPresentationHandler {
private static readonly provideHtmlColorPresentation = 'razor/provideHtmlColorPresentation';
private colorPresentationRequestType: RequestType<SerializableColorPresentationParams, SerializableColorPresentation[], any> =
new RequestType(ColorPresentationHandler.provideHtmlColorPresentation);
private emptyColorInformationResponse: SerializableColorPresentation[] = [];
constructor(
private readonly documentManager: RazorDocumentManager,
private readonly serverClient: RazorLanguageServerClient,
private readonly logger: RazorLogger) {
}
public register() {
return this.serverClient.onRequestWithParams<SerializableColorPresentationParams, SerializableColorPresentation[], any>(
this.colorPresentationRequestType,
async (request: SerializableColorPresentationParams, token: vscode.CancellationToken) => this.provideHtmlColorPresentation(request, token));
}
private async provideHtmlColorPresentation(
colorPresentationParams: SerializableColorPresentationParams,
cancellationToken: vscode.CancellationToken) {
try {
const razorDocumentUri = vscode.Uri.parse(`${colorPresentationParams.textDocument.uri}`, true);
const razorDocument = await this.documentManager.getDocument(razorDocumentUri);
if (razorDocument === undefined) {
this.logger.logWarning(`Could not find Razor document ${razorDocumentUri}; returning empty color information.`);
return this.emptyColorInformationResponse;
}
const color = new vscode.Color(
colorPresentationParams.color.red,
colorPresentationParams.color.green,
colorPresentationParams.color.blue,
colorPresentationParams.color.alpha);
const virtualHtmlUri = razorDocument.htmlDocument.uri;
const colorPresentations = await vscode.commands.executeCommand<vscode.ColorPresentation[]>(
'vscode.executeColorPresentationProvider',
color,
new ColorPresentationContext(virtualHtmlUri, colorPresentationParams.range));
const serializableColorPresentations = this.SerializeColorPresentations(colorPresentations);
return serializableColorPresentations;
} catch (error) {
this.logger.logWarning(`${ColorPresentationHandler.provideHtmlColorPresentation} failed with ${error}`);
}
return this.emptyColorInformationResponse;
}
private SerializeColorPresentations(colorPresentations: vscode.ColorPresentation[]) {
const serializableColorPresentations = new Array<SerializableColorPresentation>();
for (const colorPresentation of colorPresentations) {
let serializedTextEdit: any = null;
const serializableAdditionalTextEdits = new Array<SerializableTextEdit>();
if (colorPresentation.textEdit) {
serializedTextEdit = convertTextEditToSerializable(colorPresentation.textEdit);
}
if (colorPresentation.additionalTextEdits) {
for (const additionalTextEdit of colorPresentation.additionalTextEdits) {
const serializableAdditionalTextEdit = convertTextEditToSerializable(additionalTextEdit);
serializableAdditionalTextEdits.push(serializableAdditionalTextEdit);
}
}
const serializableColorPresentation = new SerializableColorPresentation(
colorPresentation.label,
serializedTextEdit,
serializableAdditionalTextEdits);
serializableColorPresentations.push(serializableColorPresentation);
}
return serializableColorPresentations;
}
}

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

@ -1,14 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import { SerializableTextEdit } from '../RPC/SerializableTextEdit';
export class SerializableColorPresentation {
constructor(
public readonly label: string,
public readonly textEdit?: SerializableTextEdit,
public readonly additionalTextEdits?: SerializableTextEdit[]) {
}
}

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

@ -1,14 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { SerializableRange } from '../RPC/SerializableRange';
import { SerializableTextDocumentIdentifier } from '../RPC/SerializableTextDocumentIdentifier';
export interface SerializableColorPresentationParams {
textDocument: SerializableTextDocumentIdentifier;
color: vscode.Color;
range: SerializableRange;
}

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

@ -1,169 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 '../CSharp/CSharpProjectedDocument';
import { CSharpProjectedDocumentContentProvider } from '../CSharp/CSharpProjectedDocumentContentProvider';
import { RazorDocumentManager } from '../Document/RazorDocumentManager';
import { ProjectionResult } from '../Projection/ProjectionResult';
import { RazorLanguage } from '../RazorLanguage';
import { RazorLanguageServiceClient } from '../RazorLanguageServiceClient';
import { RazorLogger } from '../RazorLogger';
import { LanguageKind } from '../RPC/LanguageKind';
import { RazorCompletionItemProvider } from './RazorCompletionItemProvider';
export class ProvisionalCompletionOrchestrator {
private provisionalDotsMayBeActive = false;
private currentActiveDocument: vscode.TextDocument | undefined;
constructor(
private readonly documentManager: RazorDocumentManager,
private readonly projectedCSharpProvider: CSharpProjectedDocumentContentProvider,
private readonly serviceClient: RazorLanguageServiceClient,
private readonly logger: RazorLogger) {
}
public register() {
if (vscode.window.activeTextEditor) {
this.currentActiveDocument = vscode.window.activeTextEditor.document;
}
// There's no event in VSCode to let us know when the completion window has been dismissed.
// Because of this restriction we do a best effort to understand when the user has gone onto
// different actions (other than viewing completion).
const onDidChangeSelectionRegistration = vscode.window.onDidChangeTextEditorSelection(
args => this.tryRemoveProvisionalDot(args.textEditor.document));
const onDidChangeRegistration = vscode.workspace.onDidChangeTextDocument(async args => {
if (args.contentChanges.length === 1 && args.contentChanges[0].text === '.') {
// Don't want to remove a provisional dot that we just added.
return;
}
await this.tryRemoveProvisionalDot(args.document);
});
const onDidChangeActiveEditorRegistration = vscode.window.onDidChangeActiveTextEditor(async args => {
if (this.currentActiveDocument) {
await this.tryRemoveProvisionalDot(this.currentActiveDocument);
}
if (args) {
this.currentActiveDocument = args.document;
} else {
this.currentActiveDocument = undefined;
}
});
return vscode.Disposable.from(
onDidChangeRegistration,
onDidChangeSelectionRegistration,
onDidChangeActiveEditorRegistration);
}
public async tryGetProvisionalCompletions(
hostDocumentUri: vscode.Uri,
projection: ProjectionResult,
completionContext: vscode.CompletionContext) {
// We expect to be called in scenarios where the user has just typed a dot after
// some identifier.
// Such as (cursor is pipe): "DateTime.| "
// In this case Razor interprets after the dot as Html and before it as C#. We
// use this criteria to provide a better completion experience for what we call
// provisional changes.
if (projection.languageKind !== LanguageKind.Html) {
return null;
}
if (completionContext.triggerCharacter !== '.') {
return null;
}
const htmlPosition = projection.position;
if (htmlPosition.character === 0) {
return null;
}
const previousCharacterPosition = new vscode.Position(
htmlPosition.line,
htmlPosition.character - 1,
);
const previousCharacterQuery = await this.serviceClient.languageQuery(
previousCharacterPosition,
hostDocumentUri);
if (previousCharacterQuery.kind !== LanguageKind.CSharp) {
return null;
}
const document = await this.documentManager.getDocument(hostDocumentUri);
const projectedDocument = document.csharpDocument as CSharpProjectedDocument;
const absoluteIndex = previousCharacterQuery.positionIndex;
if (this.logger.verboseEnabled) {
this.logger.logVerbose(`Applying provisional completion on ${projectedDocument.uri} ` +
`at (${previousCharacterQuery.position.line}, ${previousCharacterQuery.position.character})`);
}
// Edit the projected document to contain a '.'. This allows C# completion to provide valid completion items
// for moments when a user has typed a '.' that's typically interpreted as Html.
// This provisional dot is removed when one of the following is true:
// 1. The user starts typing
// 2. The user swaps active documents
// 3. The user selects different content
// 4. The projected document gets an update request
projectedDocument.addProvisionalDotAt(absoluteIndex);
this.projectedCSharpProvider.ensureDocumentContent(projectedDocument.uri);
// We open and then re-save because we're adding content to the text document within an event.
// We need to allow the system to propogate this text document change.
const newDocument = await vscode.workspace.openTextDocument(projectedDocument.uri);
await newDocument.save();
const provisionalPosition = new vscode.Position(
previousCharacterQuery.position.line,
previousCharacterQuery.position.character + 1);
const completionList = await RazorCompletionItemProvider.getCompletions(
projectedDocument.uri,
htmlPosition,
provisionalPosition,
completionContext.triggerCharacter);
// We track when we add provisional dots to avoid doing unnecessary work on commonly invoked events.
this.provisionalDotsMayBeActive = true;
return completionList;
}
private async tryRemoveProvisionalDot(document: vscode.TextDocument) {
if (!this.provisionalDotsMayBeActive) {
return;
}
if (document.languageId !== RazorLanguage.id) {
return;
}
const razorDocument = await this.documentManager.getActiveDocument();
if (!razorDocument) {
return;
}
const projectedDocument = razorDocument.csharpDocument as CSharpProjectedDocument;
if (projectedDocument.removeProvisionalDot()) {
this.projectedCSharpProvider.ensureDocumentContent(projectedDocument.uri);
if (this.logger.verboseEnabled) {
this.logger.logVerbose(`Ensured removal of provisional completion on ${projectedDocument.uri}.`);
}
}
// Don't need to force the document to refresh here by saving because the user has already
// moved onto a different action. We only want to re-save the projected document when we
// expect instant interactions with the projected document.
this.provisionalDotsMayBeActive = false;
}
}

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

@ -1,144 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { RazorDocumentManager } from '../Document/RazorDocumentManager';
import { RazorDocumentSynchronizer } from '../Document/RazorDocumentSynchronizer';
import { RazorLanguageFeatureBase } from '../RazorLanguageFeatureBase';
import { RazorLanguageServiceClient } from '../RazorLanguageServiceClient';
import { RazorLogger } from '../RazorLogger';
import { getUriPath } from '../UriPaths';
import { ProvisionalCompletionOrchestrator } from './ProvisionalCompletionOrchestrator';
export class RazorCompletionItemProvider
extends RazorLanguageFeatureBase
implements vscode.CompletionItemProvider {
public static async getCompletions(
projectedUri: vscode.Uri, hostDocumentPosition: vscode.Position,
projectedPosition: vscode.Position, triggerCharacter: string | undefined) {
if (projectedUri) {
// "@" is not a valid trigger character for C# / HTML and therefore we need to translate
// it into a non-trigger invocation.
const modifiedTriggerCharacter = triggerCharacter === '@' ? undefined : triggerCharacter;
const completions = await vscode
.commands
.executeCommand<vscode.CompletionList | vscode.CompletionItem[]>(
'vscode.executeCompletionItemProvider',
projectedUri,
projectedPosition,
modifiedTriggerCharacter);
const completionItems =
completions instanceof Array ? completions // was vscode.CompletionItem[]
: completions ? completions.items // was vscode.CompletionList
: [];
// There are times when the generated code will not line up with the content of the .razor/.cshtml file.
// Therefore, we need to offset all completion items' characters by a certain amount in order
// to have proper completion. An example of this is typing @DateTime at the beginning of a line.
// In the code behind it's represented as __o = DateTime.
const completionCharacterOffset = projectedPosition.character - hostDocumentPosition.character;
for (const completionItem of completionItems) {
const doc = completionItem.documentation as vscode.MarkdownString;
if (doc) {
// Without this, the documentation doesn't get rendered in the editor.
const newDoc = new vscode.MarkdownString(doc.value);
newDoc.isTrusted = false;
completionItem.documentation = newDoc;
}
if (completionItem.range) {
const range = completionItem.range;
const insertingRange = (range as any).inserting;
if (insertingRange) {
const insertingRangeStart = this.offsetColumn(completionCharacterOffset, hostDocumentPosition.line, insertingRange.start);
const insertingRangeEnd = this.offsetColumn(completionCharacterOffset, hostDocumentPosition.line, insertingRange.end);
(range as any).inserting = new vscode.Range(insertingRangeStart, insertingRangeEnd);
}
const replacingRange = (range as any).replacing;
if (replacingRange) {
const replacingRangeStart = this.offsetColumn(completionCharacterOffset, hostDocumentPosition.line, replacingRange.start);
const replacingRangeEnd = this.offsetColumn(completionCharacterOffset, hostDocumentPosition.line, replacingRange.end);
(range as any).replacing = new vscode.Range(replacingRangeStart, replacingRangeEnd);
}
if (range instanceof vscode.Range && range.start && range.end) {
const rangeStart = this.offsetColumn(completionCharacterOffset, hostDocumentPosition.line, range.start);
const rangeEnd = this.offsetColumn(completionCharacterOffset, hostDocumentPosition.line, range.end);
completionItem.range = new vscode.Range(rangeStart, rangeEnd);
}
}
// textEdit is deprecated in favor of .range. Clear out its value to avoid any unexpected behavior.
completionItem.textEdit = undefined;
if (triggerCharacter === '@' &&
completionItem.commitCharacters) {
// We remove `{`, '(', and '*' from the commit characters to prevent auto-completing the first
// completion item with a curly brace when a user intended to type `@{}` or `@()`.
completionItem.commitCharacters = completionItem.commitCharacters.filter(
commitChar => commitChar !== '{' && commitChar !== '(' && commitChar !== '*');
}
}
const isIncomplete = completions instanceof Array ? false
: completions ? completions.isIncomplete
: false;
return new vscode.CompletionList(completionItems, isIncomplete);
}
}
private static offsetColumn(offset: number, hostDocumentLine: number, projectedPosition: vscode.Position) {
const offsetPosition = new vscode.Position(
hostDocumentLine,
projectedPosition.character - offset);
return offsetPosition;
}
constructor(
documentSynchronizer: RazorDocumentSynchronizer,
documentManager: RazorDocumentManager,
serviceClient: RazorLanguageServiceClient,
private readonly provisionalCompletionOrchestrator: ProvisionalCompletionOrchestrator,
logger: RazorLogger) {
super(documentSynchronizer, documentManager, serviceClient, logger);
}
public async provideCompletionItems(
document: vscode.TextDocument, position: vscode.Position,
token: vscode.CancellationToken, context: vscode.CompletionContext) {
const projection = await this.getProjection(document, position, token);
if (this.logger.verboseEnabled) {
this.logger.logVerbose(`Providing completions for document ${getUriPath(document.uri)} ` +
`at location (${position.line}, ${position.character})`);
}
if (!projection) {
return { isIncomplete: true, items: [] } as vscode.CompletionList;
}
const provisionalCompletions = await this.provisionalCompletionOrchestrator.tryGetProvisionalCompletions(
document.uri,
projection,
context);
if (provisionalCompletions) {
return provisionalCompletions;
}
// Not a provisional completion
const completionList = await RazorCompletionItemProvider.getCompletions(
projection.uri,
position,
projection.position,
context.triggerCharacter);
return completionList;
}
}

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

@ -1,31 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { RazorLanguageServerClient } from './RazorLanguageServerClient';
export function listenToConfigurationChanges(
languageServerClient: RazorLanguageServerClient): vscode.Disposable {
return vscode.workspace.onDidChangeConfiguration(event => {
if (event.affectsConfiguration('razor.trace')) {
razorTraceConfigurationChangeHandler(languageServerClient);
}
});
}
function razorTraceConfigurationChangeHandler(languageServerClient: RazorLanguageServerClient) {
const promptText = 'Would you like to restart the Razor Language Server to enable the Razor trace configuration change?';
const restartButtonText = 'Restart';
vscode.window.showInformationMessage(promptText, restartButtonText).then(async result => {
if (result !== restartButtonText) {
return;
}
await languageServerClient.stop();
languageServerClient.updateTraceLevel();
await languageServerClient.start();
});
}

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

@ -1,50 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { getRazorDocumentUri, isRazorHtmlFile } from '../RazorConventions';
import { RazorLanguageFeatureBase } from '../RazorLanguageFeatureBase';
import { LanguageKind } from '../RPC/LanguageKind';
export class RazorDefinitionProvider
extends RazorLanguageFeatureBase
implements vscode.DefinitionProvider {
public async provideDefinition(
document: vscode.TextDocument, position: vscode.Position,
token: vscode.CancellationToken) {
const projection = await this.getProjection(document, position, token);
if (!projection || projection.languageKind === LanguageKind.Razor) {
return;
}
const definitions = await vscode.commands.executeCommand<vscode.Definition>(
'vscode.executeDefinitionProvider',
projection.uri,
projection.position) as vscode.Location[];
const result = new Array<vscode.Location>();
for (const definition of definitions) {
if (projection.languageKind === LanguageKind.Html && isRazorHtmlFile(definition.uri)) {
// Because the line pragmas for html are generated referencing the projected document
// we need to remap their file locations to reference the top level Razor document.
const razorFile = getRazorDocumentUri(definition.uri);
result.push(new vscode.Location(razorFile, definition.range));
} else {
// This means it is one of the following,
// 1. A .razor/.cshtml file (because OmniSharp already remapped the background C# to the original document)
// 2. A .cs file
// 3. A .html/.js file
// In all of these cases, we don't need to remap. So accept it as is and move on.
result.push(definition);
}
}
return result;
}
}

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

@ -1,11 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 interface IReportIssueDataCollectionResult {
readonly document: vscode.TextDocument | undefined;
readonly logOutput: string;
}

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

@ -1,48 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as os from 'os';
import * as vscode from 'vscode';
import { RazorLogger } from '../RazorLogger';
import { IReportIssueDataCollectionResult } from './IReportIssueDataCollectionResult';
export class ReportIssueDataCollector {
private readonly logMessages: string[] = [];
private logOutput = '';
private focusRegistration: vscode.Disposable | undefined;
private logRegistration: vscode.Disposable | undefined;
private lastFocusedRazorDocument: vscode.TextDocument | undefined;
constructor(
private readonly razorFileFocusChange: vscode.Event<vscode.TextDocument>,
private readonly logger: RazorLogger) {
}
public start() {
this.focusRegistration = this.razorFileFocusChange((razorDocument) => this.lastFocusedRazorDocument = razorDocument);
this.logRegistration = this.logger.onLog(message => this.logMessages.push(message));
this.logger.outputChannel.show(/* preserveFocus: */ true);
this.logger.logAlways('-- Starting Issue Data Collection-- ');
}
public stop() {
this.logger.logAlways('-- Stopping Issue Data Collection-- ');
this.logOutput = this.logMessages.join(os.EOL);
this.logMessages.length = 0;
if (this.focusRegistration) {
this.focusRegistration.dispose();
}
if (this.logRegistration) {
this.logRegistration.dispose();
}
}
public collect(): IReportIssueDataCollectionResult {
return {
document: this.lastFocusedRazorDocument,
logOutput: this.logOutput,
};
}
}

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

@ -1,43 +0,0 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { RazorDocumentManager } from '../Document/RazorDocumentManager';
import { RazorLogger } from '../RazorLogger';
import { api } from '../vscodeAdapter';
import * as vscode from '../vscodeAdapter';
import { ReportIssueCreator } from './ReportIssueCreator';
import { ReportIssueDataCollectorFactory } from './ReportIssueDataCollectorFactory';
import { ReportIssuePanel } from './ReportIssuePanel';
export class ReportIssueCommand {
private readonly issuePanel: ReportIssuePanel;
private readonly issueCreator: ReportIssueCreator;
private readonly dataCollectorFactory: ReportIssueDataCollectorFactory;
constructor(
private readonly vscodeApi: api,
documentManager: RazorDocumentManager,
logger: RazorLogger) {
this.dataCollectorFactory = new ReportIssueDataCollectorFactory(logger);
this.issueCreator = new ReportIssueCreator(this.vscodeApi, documentManager);
this.issuePanel = new ReportIssuePanel(this.dataCollectorFactory, this.issueCreator, logger);
}
public register() {
const registrations: vscode.Disposable[] = [];
registrations.push(
this.dataCollectorFactory.register(),
this.vscodeApi.commands.registerCommand('razor.reportIssue', () => this.issuePanel.show()));
if (this.vscodeApi.window.registerWebviewPanelSerializer) {
registrations.push(this.vscodeApi.window.registerWebviewPanelSerializer(ReportIssuePanel.viewType, {
deserializeWebviewPanel: async (panel: vscode.WebviewPanel) => {
await this.issuePanel.revive(panel);
},
}));
}
return this.vscodeApi.Disposable.from(...registrations);
}
}

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

@ -1,267 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as cp from 'child_process';
import * as os from 'os';
import { IRazorDocument } from '../Document/IRazorDocument';
import { IRazorDocumentManager } from '../Document/IRazorDocumentManager';
import { razorExtensionId } from '../RazorExtensionId';
import * as vscode from '../vscodeAdapter';
import { IReportIssueDataCollectionResult } from './IReportIssueDataCollectionResult';
export class ReportIssueCreator {
constructor(
private readonly vscodeApi: vscode.api,
private readonly documentManager: IRazorDocumentManager) {
}
public async create(collectionResult: IReportIssueDataCollectionResult) {
let razorContent: string;
let csharpContent: string;
let htmlContent: string;
if (collectionResult.document) {
razorContent = await this.getRazor(collectionResult.document);
const razorDocument = await this.documentManager.getDocument(collectionResult.document.uri);
csharpContent = await this.getProjectedCSharp(razorDocument);
htmlContent = await this.getProjectedHtml(razorDocument);
} else {
razorContent = 'Non Razor file as active document';
csharpContent = 'Could not determine CSharp content';
htmlContent = 'Could not determine Html content';
}
const razorExtensionVersion = this.getExtensionVersion();
let dotnetInfo = '';
try {
dotnetInfo = await this.getDotnetInfo();
} catch (error) {
dotnetInfo = `A valid dotnet installation could not be found: ${error}`;
}
const extensionTable = this.generateExtensionTable();
const sanitizedLogOutput = this.sanitize(collectionResult.logOutput);
const sanitizedRazorContent = this.sanitize(razorContent);
const sanitizedCSharpContent = this.sanitize(csharpContent);
const sanitizedHtmlContent = this.sanitize(htmlContent);
const sanitizedDotnetInfo = this.sanitize(dotnetInfo);
return `## Is this a Bug or Feature request?:
Bug
## Steps to reproduce
------------------- Please fill in this section -------------------------
## Description of the problem:
------------------- Please fill in this section -------------------------
Expected behavior:
Actual behavior:
## Logs
#### OmniSharp
------------------- Please fill in this section -------------------------
To find the OmniSharp log, open VS Code's "Output" pane, then in the dropdown choose "OmniSharp Log".
#### Razor
<details><summary>Expand</summary>
<p>
\`\`\`
${sanitizedLogOutput}
\`\`\`
</p>
</details>
## Workspace information
#### Razor document:
<details><summary>Expand</summary>
<p>
\`\`\`Razor
${sanitizedRazorContent}
\`\`\`
</p>
</details>
#### Projected CSharp document:
<details><summary>Expand</summary>
<p>
\`\`\`C#
${sanitizedCSharpContent}
\`\`\`
</p>
</details>
#### Projected Html document:
<details><summary>Expand</summary>
<p>
\`\`\`Html
${sanitizedHtmlContent}
\`\`\`
</p>
</details>
## Machine information
**VSCode version**: ${this.vscodeApi.version}
**Razor.VSCode version**: ${razorExtensionVersion}
#### \`dotnet --info\`
<details><summary>Expand</summary>
<p>
\`\`\`
${sanitizedDotnetInfo}
\`\`\`
</p>
</details>
#### Extensions
<details><summary>Expand</summary>
<p>
${extensionTable}
</p>
</details>`;
}
// Protected for testing
protected sanitize(content: string) {
const user = process.env.USERNAME === undefined ? process.env.USER : process.env.USERNAME;
if (user === undefined) {
// Couldn't determine user, therefore can't truly sanitize the content.
return content;
}
const replacer = new RegExp(user, 'g');
const sanitizedContent = content.replace(replacer, 'anonymous');
return sanitizedContent;
}
// Protected for testing
protected async getRazor(document: vscode.TextDocument) {
const content = document.getText();
return content;
}
// Protected for testing
protected async getProjectedCSharp(razorDocument: IRazorDocument) {
let csharpContent = `////////////////////// Projected CSharp as seen by extension ///////////////////////
${razorDocument.csharpDocument.getContent()}
////////////////////// Projected CSharp as seen by VSCode ///////////////////////`;
try {
const csharpTextDocument = await this.vscodeApi.workspace.openTextDocument(razorDocument.csharpDocument.uri);
if (csharpTextDocument) {
csharpContent = `${csharpContent}
${csharpTextDocument.getText()}`;
} else {
csharpContent = `${csharpContent}
Unable to resolve VSCode's version of CSharp`;
}
} catch (e) {
csharpContent = `${csharpContent}
Unable to resolve VSCode's version of CSharp`;
}
return csharpContent;
}
// Protected for testing
protected async getProjectedHtml(razorDocument: IRazorDocument) {
let htmlContent = `////////////////////// Projected Html as seen by extension ///////////////////////
${razorDocument.htmlDocument.getContent()}
////////////////////// Projected Html as seen by VSCode ///////////////////////`;
try {
const htmlTextDocument = await this.vscodeApi.workspace.openTextDocument(razorDocument.htmlDocument.uri);
if (htmlTextDocument) {
htmlContent = `${htmlContent}
${htmlTextDocument.getText()}`;
} else {
htmlContent = `${htmlContent}
Unable to resolve VSCode's version of Html`;
}
} catch (e) {
htmlContent = `${htmlContent}
Unable to resolve VSCode's version of Html`;
}
return htmlContent;
}
// Protected for testing
protected getExtensionVersion(): string {
const extension = this.vscodeApi.extensions.getExtension(razorExtensionId);
if (!extension) {
return 'Unable to find Razor extension version.';
}
return extension.packageJSON.version;
}
// Protected for testing
protected getInstalledExtensions() {
const extensions: Array<vscode.Extension<any>> = this.vscodeApi.extensions.all
.filter(extension => extension.packageJSON.isBuiltin === false);
return extensions.sort((a, b) =>
a.packageJSON.name.toLowerCase().localeCompare(b.packageJSON.name.toLowerCase()));
}
// Protected for testing
protected generateExtensionTable() {
const extensions = this.getInstalledExtensions();
if (extensions.length <= 0) {
return 'none';
}
const tableHeader = `|Extension|Author|Version|${os.EOL}|---|---|---|`;
const table = extensions.map(
(e) => `|${e.packageJSON.name}|${e.packageJSON.publisher}|${e.packageJSON.version}|`).join(os.EOL);
const extensionTable = `
${tableHeader}${os.EOL}${table};
`;
return extensionTable;
}
private getDotnetInfo(): Promise<string> {
return new Promise<string>((resolve, reject) => {
try {
cp.exec('dotnet --info', { cwd: process.cwd(), maxBuffer: 500 * 1024 }, (error, stdout, stderr) => {
if (error) {
reject(error);
} else if (stderr && stderr.length > 0) {
reject(error);
} else {
resolve(stdout);
}
});
} catch (error) {
reject(error);
}
});
}
}

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

@ -1,46 +0,0 @@
/* --------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
* ------------------------------------------------------------------------------------------ */
import * as os from 'os';
import * as vscode from 'vscode';
import { RazorLogger } from '../RazorLogger';
import { IReportIssueDataCollectionResult } from './IReportIssueDataCollectionResult';
export class ReportIssueDataCollector {
private readonly logMessages: string[] = [];
private logOutput = '';
private focusRegistration: vscode.Disposable | undefined;
private logRegistration: vscode.Disposable | undefined;
private lastFocusedRazorDocument: vscode.TextDocument | undefined;
constructor(
private readonly razorFileFocusChange: vscode.Event<vscode.TextDocument>,
private readonly logger: RazorLogger) {
this.focusRegistration = this.razorFileFocusChange((razorDocument) => this.lastFocusedRazorDocument = razorDocument);
this.logRegistration = this.logger.onLog(message => this.logMessages.push(message));
this.logger.outputChannel.show(/* preserveFocus: */ true);
this.logger.logAlways('-- Starting Issue Data Collection-- ');
}
public stop() {
this.logger.logAlways('-- Stopping Issue Data Collection-- ');
this.logOutput = this.logMessages.join(os.EOL);
this.logMessages.length = 0;
if (this.focusRegistration) {
this.focusRegistration.dispose();
}
if (this.logRegistration) {
this.logRegistration.dispose();
}
}
public collect(): IReportIssueDataCollectionResult {
return {
document: this.lastFocusedRazorDocument,
logOutput: this.logOutput,
};
}
}

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

@ -1,30 +0,0 @@
/* --------------------------------------------------------------------------------------------
* 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 { RazorLanguage } from '../RazorLanguage';
import { RazorLogger } from '../RazorLogger';
import { ReportIssueDataCollector } from './ReportIssueDataCollector';
export class ReportIssueDataCollectorFactory {
private onRazorDocumentFocusedEmitter = new vscode.EventEmitter<vscode.TextDocument>();
constructor(private readonly logger: RazorLogger) {
this.onRazorDocumentFocusedEmitter = new vscode.EventEmitter<vscode.TextDocument>();
}
public register() {
return vscode.window.onDidChangeActiveTextEditor((newEditor) => {
if (newEditor && RazorLanguage.fileExtensions.some(ext => newEditor.document.fileName.endsWith(ext))) {
this.onRazorDocumentFocusedEmitter.fire(newEditor.document);
}
});
}
public create() {
const collector = new ReportIssueDataCollector(this.onRazorDocumentFocusedEmitter.event, this.logger);
return collector;
}
}

Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше