Merge in 'release/2.2' changes

This commit is contained in:
dotnet-bot 2018-12-12 21:00:13 +00:00
commit 6de24d6d2c
357 changed files with 12 additions and 38902 deletions

View File

@ -151,9 +151,7 @@
<PackageArtifact Include="Microsoft.AspNetCore.WebSockets" Category="ship" />
<PackageArtifact Include="Microsoft.AspNetCore.WebUtilities" Category="ship" />
<PackageArtifact Include="Microsoft.AspNetCore" Category="ship" />
<PackageArtifact Include="Microsoft.CodeAnalysis.Razor.Workspaces" Category="shipoob" />
<PackageArtifact Include="Microsoft.CodeAnalysis.Razor" Category="ship" />
<PackageArtifact Include="Microsoft.CodeAnalysis.Remote.Razor" Category="shipoob" />
<PackageArtifact Include="Microsoft.Data.Sqlite.Core" Category="ship" />
<PackageArtifact Include="Microsoft.Data.Sqlite" Category="ship" />
<PackageArtifact Include="Microsoft.DotNet.Web.Client.ItemTemplates" Category="ship" />
@ -184,9 +182,6 @@
<PackageArtifact Include="Microsoft.Net.Http.Headers" Category="ship" />
<PackageArtifact Include="Microsoft.NET.Sdk.Razor" Category="ship" />
<PackageArtifact Include="Microsoft.Owin.Security.Interop" Category="noship" />
<PackageArtifact Include="Microsoft.VisualStudio.Editor.Razor" Category="shipoob" />
<PackageArtifact Include="Microsoft.VisualStudio.LanguageServices.Razor" Category="shipoob" />
<PackageArtifact Include="Microsoft.VisualStudio.Mac.LanguageServices.Razor" Category="shipoob" />
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.Contracts" Category="ship" />
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.Core" Category="ship" />
<PackageArtifact Include="Microsoft.VisualStudio.Web.CodeGeneration.Design" Category="ship" />

View File

@ -5,12 +5,7 @@
],
"packages": {
"Microsoft.AspNetCore.Razor.TagHelpers.Testing.Sources": {},
"RazorPageGenerator": {},
"Microsoft.CodeAnalysis.Razor.Workspaces": {},
"Microsoft.CodeAnalysis.Remote.Razor": {},
"Microsoft.VisualStudio.Editor.Razor": {},
"Microsoft.VisualStudio.LanguageServices.Razor": {},
"Microsoft.VisualStudio.Mac.LanguageServices.Razor": {}
"RazorPageGenerator": {}
}
},
"Default": { // Rules to run for packages not listed in any other set.

View File

@ -31,24 +31,12 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Runtime.Test", "test\Microsoft.AspNetCore.Razor.Runtime.Test\Microsoft.AspNetCore.Razor.Runtime.Test.csproj", "{277AB67E-9C8D-4799-A18C-C628E70A8664}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Workspaces", "src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj", "{0F265874-C592-448B-BC4F-3430AB03E0DC}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Remote.Razor", "src\Microsoft.CodeAnalysis.Remote.Razor\Microsoft.CodeAnalysis.Remote.Razor.csproj", "{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tooling", "tooling", "{C0CC1E1F-1559-44DE-93A8-63259CEA2AAB}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.VisualStudio.RazorExtension", "tooling\Microsoft.VisualStudio.RazorExtension\Microsoft.VisualStudio.RazorExtension.csproj", "{D66B45B5-CBFD-4947-81F1-F30AB80EA992}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor", "src\Microsoft.CodeAnalysis.Razor\Microsoft.CodeAnalysis.Razor.csproj", "{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Test", "test\Microsoft.CodeAnalysis.Razor.Test\Microsoft.CodeAnalysis.Razor.Test.csproj", "{7A8A1664-37CE-4376-81CA-1862CF5F91D9}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServices.Razor", "src\Microsoft.VisualStudio.LanguageServices.Razor\Microsoft.VisualStudio.LanguageServices.Razor.csproj", "{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "RazorPageGenerator.Test", "test\RazorPageGenerator.Test\RazorPageGenerator.Test.csproj", "{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.LanguageServices.Razor.Test", "test\Microsoft.VisualStudio.LanguageServices.Razor.Test\Microsoft.VisualStudio.LanguageServices.Razor.Test.csproj", "{37E61BDB-658E-4F44-A499-D64CC6D35485}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions", "src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj", "{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions.Test", "test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Test.csproj", "{7CFD5646-A757-4498-9E01-9C8528ED60AE}"
@ -57,38 +45,18 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test.MvcShim", "test\Microsoft.AspNetCore.Razor.Test.MvcShim\Microsoft.AspNetCore.Razor.Test.MvcShim.csproj", "{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Workspaces.Test", "test\Microsoft.CodeAnalysis.Razor.Workspaces.Test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.csproj", "{C61AAE12-5007-4205-A220-68F354A7F235}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X", "src\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.csproj", "{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test", "test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test\Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test.csproj", "{296D4516-0323-4D28-955D-B0324E4F10BE}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test.MvcShim.Version1_X", "test\Microsoft.AspNetCore.Razor.Test.MvcShim.Version1_X\Microsoft.AspNetCore.Razor.Test.MvcShim.Version1_X.csproj", "{AC5CA24B-B81E-4B20-B193-2E3983B1896C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Editor.Razor", "src\Microsoft.VisualStudio.Editor.Razor\Microsoft.VisualStudio.Editor.Razor.csproj", "{0BCDE75A-A438-46C7-95E9-391F029D07C5}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Editor.Razor.Test", "test\Microsoft.VisualStudio.Editor.Razor.Test\Microsoft.VisualStudio.Editor.Razor.Test.csproj", "{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Editor.Razor.Test.Common", "test\Microsoft.VisualStudio.Editor.Razor.Test.Common\Microsoft.VisualStudio.Editor.Razor.Test.Common.csproj", "{FC684D4F-D23C-407C-9C68-E10EF3B38560}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Mac.RazorAddin", "tooling\Microsoft.VisualStudio.Mac.RazorAddin\Microsoft.VisualStudio.Mac.RazorAddin.csproj", "{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Mac.LanguageServices.Razor", "src\Microsoft.VisualStudio.Mac.LanguageServices.Razor\Microsoft.VisualStudio.Mac.LanguageServices.Razor.csproj", "{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test", "test\Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test\Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test.csproj", "{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Design", "src\Microsoft.AspNetCore.Razor.Design\Microsoft.AspNetCore.Razor.Design.csproj", "{5257B25D-330A-4DCF-ACED-B4709CFBF916}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Design.Test", "test\Microsoft.AspNetCore.Razor.Design.Test\Microsoft.AspNetCore.Razor.Design.Test.csproj", "{1D90F276-E1CA-4FDF-A173-EB889E7D3150}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Test", "test\Microsoft.AspNetCore.Razor.Test\Microsoft.AspNetCore.Razor.Test.csproj", "{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Performance", "benchmarks\Microsoft.AspNetCore.Razor.Performance\Microsoft.AspNetCore.Razor.Performance.csproj", "{6205467F-E381-4C42-AEEC-763BD62B3D5E}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "benchmarks", "benchmarks", "{C2C98051-0F39-47F2-80B6-E72B29159F2C}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common", "test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common.csproj", "{933101DA-C4CC-401A-AA01-2784E1025B7F}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.AspNetCore.Razor.Tools", "src\Microsoft.AspNetCore.Razor.Tools\Microsoft.AspNetCore.Razor.Tools.csproj", "{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.NET.Sdk.Razor", "src\Microsoft.NET.Sdk.Razor\Microsoft.NET.Sdk.Razor.csproj", "{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9}"
@ -153,28 +121,6 @@ Global
{277AB67E-9C8D-4799-A18C-C628E70A8664}.Release|Any CPU.Build.0 = Release|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{277AB67E-9C8D-4799-A18C-C628E70A8664}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.Release|Any CPU.Build.0 = Release|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{0F265874-C592-448B-BC4F-3430AB03E0DC}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.Release|Any CPU.Build.0 = Release|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.Release|Any CPU.Build.0 = Release|Any CPU
{D66B45B5-CBFD-4947-81F1-F30AB80EA992}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.Debug|Any CPU.Build.0 = Debug|Any CPU
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
@ -191,14 +137,6 @@ Global
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.Release|Any CPU.Build.0 = Release|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{7A8A1664-37CE-4376-81CA-1862CF5F91D9}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.Release|Any CPU.Build.0 = Release|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.Debug|Any CPU.Build.0 = Debug|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
@ -207,14 +145,6 @@ Global
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.Release|Any CPU.Build.0 = Release|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.Debug|Any CPU.Build.0 = Debug|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.Release|Any CPU.ActiveCfg = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.Release|Any CPU.Build.0 = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{37E61BDB-658E-4F44-A499-D64CC6D35485}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.Debug|Any CPU.Build.0 = Debug|Any CPU
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
@ -247,14 +177,6 @@ Global
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.Release|Any CPU.Build.0 = Release|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.Release|Any CPU.Build.0 = Release|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{C61AAE12-5007-4205-A220-68F354A7F235}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
@ -279,54 +201,6 @@ Global
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.Release|Any CPU.Build.0 = Release|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{AC5CA24B-B81E-4B20-B193-2E3983B1896C}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.Release|Any CPU.Build.0 = Release|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{0BCDE75A-A438-46C7-95E9-391F029D07C5}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.Release|Any CPU.Build.0 = Release|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.Release|Any CPU.Build.0 = Release|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{FC684D4F-D23C-407C-9C68-E10EF3B38560}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.Debug|Any CPU.Build.0 = Debug|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.Release|Any CPU.ActiveCfg = Release|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.Release|Any CPU.Build.0 = Release|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.Release|Any CPU.Build.0 = Release|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.Release|Any CPU.Build.0 = Release|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.Debug|Any CPU.Build.0 = Debug|Any CPU
{5257B25D-330A-4DCF-ACED-B4709CFBF916}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
@ -351,22 +225,6 @@ Global
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.Release|Any CPU.Build.0 = Release|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.Release|Any CPU.Build.0 = Release|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{6205467F-E381-4C42-AEEC-763BD62B3D5E}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.DebugNoVSIX|Any CPU.Build.0 = Debug|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.Release|Any CPU.Build.0 = Release|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.ReleaseNoVSIX|Any CPU.ActiveCfg = Release|Any CPU
{933101DA-C4CC-401A-AA01-2784E1025B7F}.ReleaseNoVSIX|Any CPU.Build.0 = Release|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB}.DebugNoVSIX|Any CPU.ActiveCfg = Debug|Any CPU
@ -410,33 +268,19 @@ Global
{932F3C9C-A6C0-40D3-BA50-9309886242FC} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{969357A4-CCF1-46D9-B002-9AA072AFC75C} = {92463391-81BE-462B-AC3C-78C6C760741F}
{277AB67E-9C8D-4799-A18C-C628E70A8664} = {92463391-81BE-462B-AC3C-78C6C760741F}
{0F265874-C592-448B-BC4F-3430AB03E0DC} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{4EAD959D-73B2-4FB2-B46F-16CEB1EF49D4} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{D66B45B5-CBFD-4947-81F1-F30AB80EA992} = {C0CC1E1F-1559-44DE-93A8-63259CEA2AAB}
{42403DAF-F0BC-4F3A-B7F2-46D7013345D8} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{7A8A1664-37CE-4376-81CA-1862CF5F91D9} = {92463391-81BE-462B-AC3C-78C6C760741F}
{E5D92DB7-5CBF-410A-9685-FF76F71EC96F} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{96EB1BD4-B8E0-4F52-A068-BBCACA7E3F63} = {92463391-81BE-462B-AC3C-78C6C760741F}
{37E61BDB-658E-4F44-A499-D64CC6D35485} = {92463391-81BE-462B-AC3C-78C6C760741F}
{995F2FEB-65FA-4399-B1C0-16E0B3FBDB15} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{7CFD5646-A757-4498-9E01-9C8528ED60AE} = {92463391-81BE-462B-AC3C-78C6C760741F}
{078AEF36-F319-4CE2-BAA2-5B58A6536B46} = {92463391-81BE-462B-AC3C-78C6C760741F}
{8F165A3F-A18C-4649-AA08-C0E1BA5F5C90} = {92463391-81BE-462B-AC3C-78C6C760741F}
{C61AAE12-5007-4205-A220-68F354A7F235} = {92463391-81BE-462B-AC3C-78C6C760741F}
{F1538809-7347-45D2-A7AC-C1D89CF0BBD4} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{296D4516-0323-4D28-955D-B0324E4F10BE} = {92463391-81BE-462B-AC3C-78C6C760741F}
{AC5CA24B-B81E-4B20-B193-2E3983B1896C} = {92463391-81BE-462B-AC3C-78C6C760741F}
{0BCDE75A-A438-46C7-95E9-391F029D07C5} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{AA888DB9-340E-4E06-A2A4-25BFEE1AC2B7} = {92463391-81BE-462B-AC3C-78C6C760741F}
{FC684D4F-D23C-407C-9C68-E10EF3B38560} = {92463391-81BE-462B-AC3C-78C6C760741F}
{FAF9986F-E086-4513-9D52-F7BF5FFCF31D} = {C0CC1E1F-1559-44DE-93A8-63259CEA2AAB}
{95B18DEE-8B45-4CF0-B9F8-CCBAF3B5251A} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{B8A3E4CA-D54A-441F-A3BF-E00F060CA042} = {92463391-81BE-462B-AC3C-78C6C760741F}
{5257B25D-330A-4DCF-ACED-B4709CFBF916} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{1D90F276-E1CA-4FDF-A173-EB889E7D3150} = {92463391-81BE-462B-AC3C-78C6C760741F}
{323553F0-14AB-4FBD-9CF0-1CC0BE8056F8} = {92463391-81BE-462B-AC3C-78C6C760741F}
{6205467F-E381-4C42-AEEC-763BD62B3D5E} = {C2C98051-0F39-47F2-80B6-E72B29159F2C}
{933101DA-C4CC-401A-AA01-2784E1025B7F} = {92463391-81BE-462B-AC3C-78C6C760741F}
{3E7F2D49-3B45-45A8-9893-F73EC1EEBAAB} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{7D9ECCEE-71D1-4A42-ABEE-876AFA1B4FC9} = {3C0D6505-79B3-49D0-B4C3-176F0F1836ED}
{6EA56B2B-89EC-4C38-A384-97D203375B06} = {92463391-81BE-462B-AC3C-78C6C760741F}

View File

@ -1 +0,0 @@
[assembly: BenchmarkDotNet.Attributes.AspNetCoreBenchmark]

View File

@ -1,58 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class CodeGenerationBenchmark
{
public CodeGenerationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "MSN.cshtml")))
{
current = current.Parent;
}
var root = current;
var fileSystem = RazorProjectFileSystem.Create(root.FullName);
ProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, b => RazorExtensions.Register(b)); ;
MSN = fileSystem.GetItem(Path.Combine(root.FullName, "MSN.cshtml"));
}
public RazorProjectEngine ProjectEngine { get; }
public RazorProjectItem MSN { get; }
[Benchmark(Description = "Razor Design Time Code Generation of MSN.com")]
public void CodeGeneration_DesignTime_LargeStaticFile()
{
var codeDocument = ProjectEngine.ProcessDesignTime(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
}
}
[Benchmark(Description = "Razor Runtime Code Generation of MSN.com")]
public void CodeGeneration_Runtime_LargeStaticFile()
{
var codeDocument = ProjectEngine.Process(MSN);
var generated = codeDocument.GetCSharpDocument();
if (generated.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, generated.Diagnostics));
}
}
}
}

File diff suppressed because one or more lines are too long

View File

@ -1,40 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netcoreapp2.1</TargetFramework>
<OutputType>Exe</OutputType>
<ServerGarbageCollection>true</ServerGarbageCollection>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPackable>false</IsPackable>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.Mvc.Razor.Extensions\Microsoft.AspNetCore.Mvc.Razor.Extensions.csproj" />
<ProjectReference Include="..\..\src\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Include="..\..\src\Microsoft.VisualStudio.LanguageServices.Razor\Serialization\*.cs">
<Link>Serialization\%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestServices.cs">
<Link>TestServices\%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestWorkspace.cs">
<Link>TestServices\%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestLanguageServices.cs">
<Link>TestServices\%(FileName)%(Extension)</Link>
</Compile>
<Compile Include="..\..\test\Microsoft.CodeAnalysis.Razor.Workspaces.Test.Common\TestWorkspaceServices.cs">
<Link>TestServices\%(FileName)%(Extension)</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="$(BenchmarkDotNetPackageVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />
<PackageReference Include="Microsoft.AspNetCore.BenchmarkRunner.Sources" Version="$(MicrosoftAspNetCoreBenchmarkRunnerSourcesPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -1,53 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Threading.Tasks;
using BenchmarkDotNet.Attributes;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class BackgroundCodeGenerationBenchmark : ProjectSnapshotManagerBenchmarkBase
{
[IterationSetup]
public void Setup()
{
SnapshotManager = CreateProjectSnapshotManager();
SnapshotManager.HostProjectAdded(HostProject);
SnapshotManager.Changed += SnapshotManager_Changed;
}
[IterationCleanup]
public void Cleanup()
{
SnapshotManager.Changed -= SnapshotManager_Changed;
Tasks.Clear();
}
private List<Task> Tasks { get; } = new List<Task>();
private DefaultProjectSnapshotManager SnapshotManager { get; set; }
[Benchmark(Description = "Generates the code for 100 files", OperationsPerInvoke = 100)]
public async Task BackgroundCodeGeneration_Generate100Files()
{
for (var i = 0; i < Documents.Length; i++)
{
SnapshotManager.DocumentAdded(HostProject, Documents[i], TextLoaders[i % 4]);
}
await Task.WhenAll(Tasks);
}
private void SnapshotManager_Changed(object sender, ProjectChangeEventArgs e)
{
// The real work happens here.
var project = SnapshotManager.GetLoadedProject(e.ProjectFilePath);
var document = project.GetDocument(e.DocumentFilePath);
Tasks.Add(document.GetGeneratedOutputAsync());
}
}
}

View File

@ -1,30 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using BenchmarkDotNet.Attributes;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class ProjectLoadBenchmark : ProjectSnapshotManagerBenchmarkBase
{
[IterationSetup]
public void Setup()
{
SnapshotManager = CreateProjectSnapshotManager();
}
private DefaultProjectSnapshotManager SnapshotManager { get; set; }
[Benchmark(Description = "Initializes a project and 100 files", OperationsPerInvoke = 100)]
public void ProjectLoad_AddProjectAnd100Files()
{
SnapshotManager.HostProjectAdded(HostProject);
for (var i= 0; i < Documents.Length; i++)
{
SnapshotManager.DocumentAdded(HostProject, Documents[i], TextLoaders[i % 4]);
}
}
}
}

View File

@ -1,154 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.CodeAnalysis.Text;
using Microsoft.VisualStudio.LanguageServices.Razor.Serialization;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class ProjectSnapshotManagerBenchmarkBase
{
public ProjectSnapshotManagerBenchmarkBase()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "Razor.sln")))
{
current = current.Parent;
}
var root = current;
var projectRoot = Path.Combine(root.FullName, "test", "testapps", "LargeProject");
HostProject = new HostProject(Path.Combine(projectRoot, "LargeProject.csproj"), FallbackRazorConfiguration.MVC_2_1);
TextLoaders = new TextLoader[4];
for (var i = 0; i < 4; i++)
{
var filePath = Path.Combine(projectRoot, "Views", "Home", $"View00{i % 4}.cshtml");
var text = SourceText.From(filePath, encoding: null);
TextLoaders[i] = TextLoader.From(TextAndVersion.Create(text, VersionStamp.Create()));
}
Documents = new HostDocument[100];
for (var i = 0; i < Documents.Length; i++)
{
var filePath = Path.Combine(projectRoot, "Views", "Home", $"View00{i % 4}.cshtml");
Documents[i] = new HostDocument(filePath, $"/Views/Home/View00{i}.cshtml");
}
var tagHelpers = Path.Combine(root.FullName, "benchmarks", "Microsoft.AspNetCore.Razor.Performance", "taghelpers.json");
TagHelperResolver = new StaticTagHelperResolver(ReadTagHelpers(tagHelpers));
}
internal HostProject HostProject { get; }
internal HostDocument[] Documents { get; }
internal TextLoader[] TextLoaders { get; }
internal TagHelperResolver TagHelperResolver { get; }
internal DefaultProjectSnapshotManager CreateProjectSnapshotManager()
{
var services = TestServices.Create(
new IWorkspaceService[]
{
new StaticProjectSnapshotProjectEngineFactory(),
},
new ILanguageService[]
{
TagHelperResolver,
});
return new DefaultProjectSnapshotManager(
new TestForegroundDispatcher(),
new TestErrorReporter(),
Array.Empty<ProjectSnapshotChangeTrigger>(),
new AdhocWorkspace(services));
}
private static IReadOnlyList<TagHelperDescriptor> ReadTagHelpers(string filePath)
{
var serializer = new JsonSerializer();
serializer.Converters.Add(new RazorDiagnosticJsonConverter());
serializer.Converters.Add(new TagHelperDescriptorJsonConverter());
using (var reader = new JsonTextReader(File.OpenText(filePath)))
{
return serializer.Deserialize<IReadOnlyList<TagHelperDescriptor>>(reader);
}
}
private class TestForegroundDispatcher : ForegroundDispatcher
{
public override bool IsForegroundThread => true;
public override TaskScheduler ForegroundScheduler => TaskScheduler.Default;
public override TaskScheduler BackgroundScheduler => TaskScheduler.Default;
}
private class TestErrorReporter : ErrorReporter
{
public override void ReportError(Exception exception)
{
}
public override void ReportError(Exception exception, ProjectSnapshot project)
{
}
public override void ReportError(Exception exception, Project workspaceProject)
{
}
}
private class StaticTagHelperResolver : TagHelperResolver
{
private readonly IReadOnlyList<TagHelperDescriptor> _tagHelpers;
public StaticTagHelperResolver(IReadOnlyList<TagHelperDescriptor> tagHelpers)
{
this._tagHelpers = tagHelpers;
}
public override Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, CancellationToken cancellationToken = default)
{
return Task.FromResult(new TagHelperResolutionResult(_tagHelpers, Array.Empty<RazorDiagnostic>()));
}
}
private class StaticProjectSnapshotProjectEngineFactory : ProjectSnapshotProjectEngineFactory
{
public override RazorProjectEngine Create(ProjectSnapshot project, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
{
return RazorProjectEngine.Create(project.Configuration, fileSystem, b =>
{
RazorExtensions.Register(b);
});
}
public override IProjectEngineFactory FindFactory(ProjectSnapshot project)
{
throw new NotImplementedException();
}
public override IProjectEngineFactory FindSerializableFactory(ProjectSnapshot project)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -1,77 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Linq;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Mvc.Razor.Extensions;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class SyntaxTreeGenerationBenchmark
{
public SyntaxTreeGenerationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "MSN.cshtml")))
{
current = current.Parent;
}
var root = current;
var fileSystem = RazorProjectFileSystem.Create(root.FullName);
ProjectEngine = RazorProjectEngine.Create(RazorConfiguration.Default, fileSystem, b => RazorExtensions.Register(b)); ;
var projectItem = fileSystem.GetItem(Path.Combine(root.FullName, "MSN.cshtml"));
MSN = RazorSourceDocument.ReadFrom(projectItem);
var directiveFeature = ProjectEngine.EngineFeatures.OfType<IRazorDirectiveFeature>().FirstOrDefault();
Directives = directiveFeature?.Directives.ToArray() ?? Array.Empty<DirectiveDescriptor>();
}
public RazorProjectEngine ProjectEngine { get; }
public RazorSourceDocument MSN { get; }
public DirectiveDescriptor[] Directives { get; }
[Benchmark(Description = "Razor Design Time Syntax Tree Generation of MSN.com")]
public void SyntaxTreeGeneration_DesignTime_LargeStaticFile()
{
var options = RazorParserOptions.CreateDesignTime(o =>
{
foreach (var directive in Directives)
{
o.Directives.Add(directive);
}
});
var syntaxTree = RazorSyntaxTree.Parse(MSN, options);
if (syntaxTree.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, syntaxTree.Diagnostics));
}
}
[Benchmark(Description = "Razor Runtime Syntax Tree Generation of MSN.com")]
public void SyntaxTreeGeneration_Runtime_LargeStaticFile()
{
var options = RazorParserOptions.Create(o =>
{
foreach (var directive in Directives)
{
o.Directives.Add(directive);
}
});
var syntaxTree = RazorSyntaxTree.Parse(MSN, options);
if (syntaxTree.Diagnostics.Count != 0)
{
throw new Exception("Error!" + Environment.NewLine + string.Join(Environment.NewLine, syntaxTree.Diagnostics));
}
}
}
}

View File

@ -1,54 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using BenchmarkDotNet.Attributes;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.VisualStudio.LanguageServices.Razor.Serialization;
using Newtonsoft.Json;
namespace Microsoft.AspNetCore.Razor.Performance
{
public class TagHelperSerializationBenchmark
{
private readonly byte[] _tagHelperBuffer;
public TagHelperSerializationBenchmark()
{
var current = new DirectoryInfo(AppContext.BaseDirectory);
while (current != null && !File.Exists(Path.Combine(current.FullName, "taghelpers.json")))
{
current = current.Parent;
}
var tagHelperFilePath = Path.Combine(current.FullName, "taghelpers.json");
_tagHelperBuffer = File.ReadAllBytes(tagHelperFilePath);
}
[Benchmark(Description = "Razor TagHelper Serialization")]
public void TagHelper_Serialization_RoundTrip()
{
var serializer = new JsonSerializer();
serializer.Converters.Add(new RazorDiagnosticJsonConverter());
serializer.Converters.Add(new TagHelperDescriptorJsonConverter());
// Deserialize from json file.
IReadOnlyList<TagHelperDescriptor> tagHelpers;
using (var stream = new MemoryStream(_tagHelperBuffer))
using (var reader = new JsonTextReader(new StreamReader(stream)))
{
tagHelpers = serializer.Deserialize<IReadOnlyList<TagHelperDescriptor>>(reader);
}
// Serialize back to json.
using (var stream = new MemoryStream())
using (var writer = new StreamWriter(stream, Encoding.UTF8, bufferSize: 4096))
{
serializer.Serialize(writer, tagHelpers);
}
}
}
}

View File

@ -1,11 +0,0 @@
Compile the solution in Release mode (so binaries are available in release)
To run a specific benchmark add it as parameter.
```
dotnet run -c Release <benchmark_name>
```
If you run without any parameters, you'll be offered the list of all benchmarks and get to choose.
```
dotnet run -c Release
```

File diff suppressed because one or more lines are too long

3
src/Razor/build.cmd Normal file
View File

@ -0,0 +1,3 @@
@ECHO OFF
SET RepoRoot="%~dp0..\.."
%RepoRoot%\build.cmd -LockFile %RepoRoot%\korebuild-lock.txt -Path %~dp0 %*

7
src/Razor/build.sh Normal file
View File

@ -0,0 +1,7 @@
#!/usr/bin/env bash
set -euo pipefail
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
repo_root="$DIR/../.."
"$repo_root/build.sh" --path "$DIR" --lockfile "$repo_root/korebuild-lock.txt" "$@"

View File

@ -1,7 +1,4 @@
<Project>
<Import Project="VSIX.targets" />
<Import Project="MPack.targets" />
<ItemGroup>
<Solutions Update="$(RepositoryRoot)Razor.sln">
<!-- the 'DebugNoVSIX' and 'ReleaseNoVSIX' configurations exclude the VSIX project, which doesn't build with Microsoft.NET.Sdk yet. -->

View File

@ -2,24 +2,12 @@
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Version1_X.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.GenerateTool, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Language.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.TagHelperTool, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Test.Common, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Tools.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("rzc, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Remote.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor.Test.Common, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.LanguageServices.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.LanguageServices.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.RazorExtension, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Razor is a markup syntax for adding server-side logic to web pages. This assembly contains infrastructure supporting Razor MSBuild integration.</Description>
@ -12,15 +12,6 @@
<EnableApiCheck>false</EnableApiCheck>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Microsoft.VisualStudio.LanguageServices.Razor\Serialization\TagHelperDescriptorJsonConverter.cs">
<Link>Shared\TagHelperDescriptorJsonConverter.cs</Link>
</Compile>
<Compile Include="..\Microsoft.VisualStudio.LanguageServices.Razor\Serialization\RazorDiagnosticJsonConverter.cs">
<Link>Shared\RazorDiagnosticJsonConverter.cs</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.Extensions.CommandLineUtils.Sources" Version="$(MicrosoftExtensionsCommandLineUtilsSourcesPackageVersion)" />
<PackageReference Include="Newtonsoft.Json" Version="$(NewtonsoftJsonPackageVersion)" />

View File

@ -1,41 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Razor
{
internal class DefaultErrorReporter : ErrorReporter
{
public override void ReportError(Exception exception)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
// Do nothing.
}
public override void ReportError(Exception exception, ProjectSnapshot project)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
// Do nothing.
}
public override void ReportError(Exception exception, Project workspaceProject)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
// Do nothing.
}
}
}

View File

@ -1,19 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Razor
{
[Shared]
[ExportWorkspaceServiceFactory(typeof(ErrorReporter), ServiceLayer.Default)]
internal class DefaultErrorReporterFactory : IWorkspaceServiceFactory
{
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
return new DefaultErrorReporter();
}
}
}

View File

@ -1,102 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Razor
{
internal class DefaultProjectSnapshotProjectEngineFactory : ProjectSnapshotProjectEngineFactory
{
private readonly static RazorConfiguration DefaultConfiguration = FallbackRazorConfiguration.MVC_2_1;
private readonly IFallbackProjectEngineFactory _fallback;
private readonly Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[] _factories;
public DefaultProjectSnapshotProjectEngineFactory(
IFallbackProjectEngineFactory fallback,
Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[] factories)
{
if (fallback == null)
{
throw new ArgumentNullException(nameof(fallback));
}
if (factories == null)
{
throw new ArgumentNullException(nameof(factories));
}
_fallback = fallback;
_factories = factories;
}
public override RazorProjectEngine Create(ProjectSnapshot project, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
if (fileSystem == null)
{
throw new ArgumentNullException(nameof(fileSystem));
}
// When we're running in the editor, the editor provides a configure delegate that will include
// the editor settings and tag helpers.
//
// This service is only used in process in Visual Studio, and any other callers should provide these
// things also.
configure = configure ?? ((b) => { });
// The default configuration currently matches the newest MVC configuration.
//
// We typically want this because the language adds features over time - we don't want to a bunch of errors
// to show up when a document is first opened, and then go away when the configuration loads, we'd prefer the opposite.
var configuration = project.Configuration ?? DefaultConfiguration;
// If there's no factory to handle the configuration then fall back to a very basic configuration.
//
// This will stop a crash from happening in this case (misconfigured project), but will still make
// it obvious to the user that something is wrong.
var factory = SelectFactory(configuration) ?? _fallback;
return factory.Create(configuration, fileSystem, configure);
}
public override IProjectEngineFactory FindFactory(ProjectSnapshot project)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
return SelectFactory(project.Configuration ?? DefaultConfiguration, requireSerializable: false);
}
public override IProjectEngineFactory FindSerializableFactory(ProjectSnapshot project)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
return SelectFactory(project.Configuration ?? DefaultConfiguration, requireSerializable: true);
}
private IProjectEngineFactory SelectFactory(RazorConfiguration configuration, bool requireSerializable = false)
{
for (var i = 0; i < _factories.Length; i++)
{
var factory = _factories[i];
if (string.Equals(configuration.ConfigurationName, factory.Metadata.ConfigurationName))
{
return requireSerializable && !factory.Metadata.SupportsSerialization ? null : factory.Value;
}
}
return null;
}
}
}

View File

@ -1,46 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Razor.Workspaces
{
[ExportWorkspaceServiceFactory(typeof(ProjectSnapshotProjectEngineFactory))]
internal class DefaultProjectSnapshotProjectEngineFactoryFactory : IWorkspaceServiceFactory
{
private readonly IFallbackProjectEngineFactory _fallback;
private readonly Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[] _factories;
[ImportingConstructor]
public DefaultProjectSnapshotProjectEngineFactoryFactory(
IFallbackProjectEngineFactory fallback,
[ImportMany] Lazy<IProjectEngineFactory, ICustomProjectEngineFactoryMetadata>[] factories)
{
if (fallback == null)
{
throw new ArgumentNullException(nameof(fallback));
}
if (factories == null)
{
throw new ArgumentNullException(nameof(factories));
}
_fallback = fallback;
_factories = factories;
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
if (workspaceServices == null)
{
throw new ArgumentNullException(nameof(workspaceServices));
}
return new DefaultProjectSnapshotProjectEngineFactory(_fallback, _factories);
}
}
}

View File

@ -1,275 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Composition;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
using Microsoft.Extensions.Internal;
namespace Microsoft.CodeAnalysis.Razor
{
// Deliberately not exported for now, until this feature is working end to end.
// [Export(typeof(ProjectSnapshotChangeTrigger))]
internal class BackgroundDocumentGenerator : ProjectSnapshotChangeTrigger
{
private ForegroundDispatcher _foregroundDispatcher;
private ProjectSnapshotManagerBase _projectManager;
private readonly Dictionary<DocumentKey, DocumentSnapshot> _files;
private Timer _timer;
[ImportingConstructor]
public BackgroundDocumentGenerator(ForegroundDispatcher foregroundDispatcher)
{
if (foregroundDispatcher == null)
{
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
_foregroundDispatcher = foregroundDispatcher;
_files = new Dictionary<DocumentKey, DocumentSnapshot>();
}
public bool HasPendingNotifications
{
get
{
lock (_files)
{
return _files.Count > 0;
}
}
}
// Used in unit tests to control the timer delay.
public TimeSpan Delay { get; set; } = TimeSpan.FromSeconds(2);
public bool IsScheduledOrRunning => _timer != null;
// Used in unit tests to ensure we can control when background work starts.
public ManualResetEventSlim BlockBackgroundWorkStart { get; set; }
// Used in unit tests to ensure we can know when background work finishes.
public ManualResetEventSlim NotifyBackgroundWorkStarting { get; set; }
// Used in unit tests to ensure we can know when background has captured its current workload.
public ManualResetEventSlim NotifyBackgroundCapturedWorkload { get; set; }
// Used in unit tests to ensure we can control when background work completes.
public ManualResetEventSlim BlockBackgroundWorkCompleting { get; set; }
// Used in unit tests to ensure we can know when background work finishes.
public ManualResetEventSlim NotifyBackgroundWorkCompleted { get; set; }
private void OnStartingBackgroundWork()
{
if (BlockBackgroundWorkStart != null)
{
BlockBackgroundWorkStart.Wait();
BlockBackgroundWorkStart.Reset();
}
if (NotifyBackgroundWorkStarting != null)
{
NotifyBackgroundWorkStarting.Set();
}
}
private void OnCompletingBackgroundWork()
{
if (BlockBackgroundWorkCompleting != null)
{
BlockBackgroundWorkCompleting.Wait();
BlockBackgroundWorkCompleting.Reset();
}
}
private void OnCompletedBackgroundWork()
{
if (NotifyBackgroundWorkCompleted != null)
{
NotifyBackgroundWorkCompleted.Set();
}
}
private void OnBackgroundCapturedWorkload()
{
if (NotifyBackgroundCapturedWorkload != null)
{
NotifyBackgroundCapturedWorkload.Set();
}
}
public override void Initialize(ProjectSnapshotManagerBase projectManager)
{
if (projectManager == null)
{
throw new ArgumentNullException(nameof(projectManager));
}
_projectManager = projectManager;
_projectManager.Changed += ProjectManager_Changed;
}
protected virtual Task ProcessDocument(DocumentSnapshot document)
{
return document.GetGeneratedOutputAsync();
}
public void Enqueue(ProjectSnapshot project, DocumentSnapshot document)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
_foregroundDispatcher.AssertForegroundThread();
lock (_files)
{
// We only want to store the last 'seen' version of any given document. That way when we pick one to process
// it's always the best version to use.
_files[new DocumentKey(project.FilePath, document.FilePath)] = document;
StartWorker();
}
}
protected virtual void StartWorker()
{
// Access to the timer is protected by the lock in Enqueue and in Timer_Tick
if (_timer == null)
{
// Timer will fire after a fixed delay, but only once.
_timer = NonCapturingTimer.Create(state => ((BackgroundDocumentGenerator)state).Timer_Tick(), this, Delay, Timeout.InfiniteTimeSpan);
}
}
private void Timer_Tick()
{
_ = TimerTick();
}
private async Task TimerTick()
{
try
{
_foregroundDispatcher.AssertBackgroundThread();
// Timer is stopped.
_timer.Change(Timeout.Infinite, Timeout.Infinite);
OnStartingBackgroundWork();
DocumentSnapshot[] work;
lock (_files)
{
work = _files.Values.ToArray();
_files.Clear();
}
OnBackgroundCapturedWorkload();
for (var i = 0; i < work.Length; i++)
{
var document = work[i];
try
{
await ProcessDocument(document);
}
catch (Exception ex)
{
ReportError(document, ex);
}
}
OnCompletingBackgroundWork();
lock (_files)
{
// Resetting the timer allows another batch of work to start.
_timer.Dispose();
_timer = null;
// If more work came in while we were running start the worker again.
if (_files.Count > 0)
{
StartWorker();
}
}
OnCompletedBackgroundWork();
}
catch (Exception ex)
{
// This is something totally unexpected, let's just send it over to the workspace.
await Task.Factory.StartNew(
(p) => ((ProjectSnapshotManagerBase)p).ReportError(ex),
_projectManager,
CancellationToken.None,
TaskCreationOptions.None,
_foregroundDispatcher.ForegroundScheduler);
}
}
private void ReportError(DocumentSnapshot document, Exception ex)
{
GC.KeepAlive(Task.Factory.StartNew(
(p) => ((ProjectSnapshotManagerBase)p).ReportError(ex),
_projectManager,
CancellationToken.None,
TaskCreationOptions.None,
_foregroundDispatcher.ForegroundScheduler));
}
private void ProjectManager_Changed(object sender, ProjectChangeEventArgs e)
{
switch (e.Kind)
{
case ProjectChangeKind.ProjectAdded:
case ProjectChangeKind.ProjectChanged:
{
var project = _projectManager.GetLoadedProject(e.ProjectFilePath);
foreach (var documentFilePath in project.DocumentFilePaths)
{
Enqueue(project, project.GetDocument(documentFilePath));
}
break;
}
case ProjectChangeKind.ProjectRemoved:
// ignore
break;
case ProjectChangeKind.DocumentAdded:
case ProjectChangeKind.DocumentChanged:
{
var project = _projectManager.GetLoadedProject(e.ProjectFilePath);
Enqueue(project, project.GetDocument(e.DocumentFilePath));
break;
}
case ProjectChangeKind.DocumentRemoved:
// ignore
break;
default:
throw new InvalidOperationException($"Unknown ProjectChangeKind {e.Kind}");
}
}
}
}

View File

@ -1,41 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Extensions.Internal;
namespace Microsoft.CodeAnalysis.Razor
{
public struct DocumentKey : IEquatable<DocumentKey>
{
public DocumentKey(string projectFilePath, string documentFilePath)
{
ProjectFilePath = projectFilePath;
DocumentFilePath = documentFilePath;
}
public string ProjectFilePath { get; }
public string DocumentFilePath { get; }
public bool Equals(DocumentKey other)
{
return
FilePathComparer.Instance.Equals(ProjectFilePath, other.ProjectFilePath) &&
FilePathComparer.Instance.Equals(DocumentFilePath, other.DocumentFilePath);
}
public override bool Equals(object obj)
{
return obj is DocumentKey key ? Equals(key) : false;
}
public override int GetHashCode()
{
var hash = new HashCodeCombiner();
hash.Add(ProjectFilePath, FilePathComparer.Instance);
hash.Add(DocumentFilePath, FilePathComparer.Instance);
return hash;
}
}
}

View File

@ -1,53 +0,0 @@
// Copyright(c) .NET Foundation.All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.Extensions.Internal;
namespace Microsoft.CodeAnalysis.Razor.Editor
{
public sealed class EditorSettings : IEquatable<EditorSettings>
{
public static readonly EditorSettings Default = new EditorSettings(indentWithTabs: false, indentSize: 4);
public EditorSettings(bool indentWithTabs, int indentSize)
{
if (indentSize < 0)
{
throw new ArgumentOutOfRangeException(nameof(indentSize));
}
IndentWithTabs = indentWithTabs;
IndentSize = indentSize;
}
public bool IndentWithTabs { get; }
public int IndentSize { get; }
public bool Equals(EditorSettings other)
{
if (other == null)
{
return false;
}
return IndentWithTabs == other.IndentWithTabs &&
IndentSize == other.IndentSize;
}
public override bool Equals(object other)
{
return Equals(other as EditorSettings);
}
public override int GetHashCode()
{
var combiner = HashCodeCombiner.Start();
combiner.Add(IndentWithTabs);
combiner.Add(IndentSize);
return combiner.CombinedHash;
}
}
}

View File

@ -1,17 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.CodeAnalysis.Razor.Editor
{
public sealed class EditorSettingsChangedEventArgs : EventArgs
{
public EditorSettingsChangedEventArgs(EditorSettings settings)
{
Settings = settings;
}
public EditorSettings Settings { get; }
}
}

View File

@ -1,15 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Razor.Editor
{
internal abstract class WorkspaceEditorSettings : ILanguageService
{
public abstract event EventHandler<EditorSettingsChangedEventArgs> Changed;
public abstract EditorSettings Current { get; }
}
}

View File

@ -1,18 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Razor
{
internal abstract class ErrorReporter : IWorkspaceService
{
public abstract void ReportError(Exception exception);
public abstract void ReportError(Exception exception, ProjectSnapshot project);
public abstract void ReportError(Exception exception, Project workspaceProject);
}
}

View File

@ -1,28 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
namespace Microsoft.CodeAnalysis.Razor
{
[MetadataAttribute]
[AttributeUsage(AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public class ExportCustomProjectEngineFactoryAttribute : ExportAttribute, ICustomProjectEngineFactoryMetadata
{
public ExportCustomProjectEngineFactoryAttribute(string configurationName)
: base(typeof(IProjectEngineFactory))
{
if (configurationName == null)
{
throw new ArgumentNullException(nameof(configurationName));
}
ConfigurationName = configurationName;
}
public string ConfigurationName { get; }
public bool SupportsSerialization { get; set; }
}
}

View File

@ -1,37 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.CodeAnalysis.Razor
{
[Export(typeof(IFallbackProjectEngineFactory))]
internal class FallbackProjectEngineFactory : IFallbackProjectEngineFactory
{
public RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure)
{
if (configuration == null)
{
throw new ArgumentNullException(nameof(configuration));
}
if (fileSystem == null)
{
throw new ArgumentNullException(nameof(fileSystem));
}
// This is a very basic implementation that will provide reasonable support without crashing.
// If the user falls into this situation, ideally they can realize that something is wrong and take
// action.
//
// This has no support for:
// - Tag Helpers
// - Imports
// - Default Imports
// - and will have a very limited set of directives
return RazorProjectEngine.Create(configuration, fileSystem, configure);
}
}
}

View File

@ -1,37 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Razor
{
internal abstract class ForegroundDispatcher
{
public abstract bool IsForegroundThread { get; }
public abstract TaskScheduler ForegroundScheduler { get; }
public abstract TaskScheduler BackgroundScheduler { get; }
public virtual void AssertForegroundThread([CallerMemberName] string caller = null)
{
if (!IsForegroundThread)
{
caller = caller == null ? Workspaces.Resources.ForegroundDispatcher_NoMethodNamePlaceholder : $"'{caller}'";
throw new InvalidOperationException(Workspaces.Resources.FormatForegroundDispatcher_AssertForegroundThread(caller));
}
}
public virtual void AssertBackgroundThread([CallerMemberName] string caller = null)
{
if (IsForegroundThread)
{
caller = caller == null ? Workspaces.Resources.ForegroundDispatcher_NoMethodNamePlaceholder : $"'{caller}'";
throw new InvalidOperationException(Workspaces.Resources.FormatForegroundDispatcher_AssertBackgroundThread(caller));
}
}
}
}

View File

@ -1,12 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Razor
{
public interface ICustomProjectEngineFactoryMetadata
{
string ConfigurationName { get; }
bool SupportsSerialization { get; }
}
}

View File

@ -1,10 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Razor
{
// Used to create the 'fallback' project engine when we don't have a custom implementation.
internal interface IFallbackProjectEngineFactory : IProjectEngineFactory
{
}
}

View File

@ -1,13 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.CodeAnalysis.Razor
{
public interface IProjectEngineFactory
{
RazorProjectEngine Create(RazorConfiguration configuration, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure);
}
}

View File

@ -1,19 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Razor is a markup syntax for adding server-side logic to web pages. This package contains the Razor design-time infrastructure.</Description>
<TargetFrameworks>net46;netstandard2.0</TargetFrameworks>
<EnableApiCheck>false</EnableApiCheck>
</PropertyGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.CodeAnalysis.Razor\Microsoft.CodeAnalysis.Razor.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(VSIX_MicrosoftCodeAnalysisCSharpPackageVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="$(VSIX_MicrosoftCodeAnalysisWorkspacesCommonPackageVersion)" />
<PackageReference Include="Microsoft.Extensions.NonCapturingTimer.Sources" Version="$(MicrosoftExtensionsNonCapturingTimerSourcesPackageVersion)" PrivateAssets="all" />
</ItemGroup>
</Project>

View File

@ -1,51 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Razor
{
internal abstract class ProjectSnapshotProjectEngineFactory : IWorkspaceService
{
public abstract IProjectEngineFactory FindFactory(ProjectSnapshot project);
public abstract IProjectEngineFactory FindSerializableFactory(ProjectSnapshot project);
public RazorProjectEngine Create(ProjectSnapshot project)
{
return Create(project, RazorProjectFileSystem.Create(Path.GetDirectoryName(project.FilePath)), null);
}
public RazorProjectEngine Create(ProjectSnapshot project, RazorProjectFileSystem fileSystem)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
if (fileSystem == null)
{
throw new ArgumentNullException(nameof(fileSystem));
}
return Create(project, fileSystem, null);
}
public RazorProjectEngine Create(ProjectSnapshot project, Action<RazorProjectEngineBuilder> configure)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
return Create(project, RazorProjectFileSystem.Create(Path.GetDirectoryName(project.FilePath)), configure);
}
public abstract RazorProjectEngine Create(ProjectSnapshot project, RazorProjectFileSystem fileSystem, Action<RazorProjectEngineBuilder> configure);
}
}

View File

@ -1,81 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class DefaultDocumentSnapshot : DocumentSnapshot
{
public DefaultDocumentSnapshot(DefaultProjectSnapshot project, DocumentState state)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
if (state == null)
{
throw new ArgumentNullException(nameof(state));
}
Project = project;
State = state;
}
public DefaultProjectSnapshot Project { get; }
public DocumentState State { get; }
public override string FilePath => State.HostDocument.FilePath;
public override string TargetPath => State.HostDocument.TargetPath;
public override IReadOnlyList<DocumentSnapshot> GetImports()
{
return State.Imports.GetImports(Project, this);
}
public override Task<SourceText> GetTextAsync()
{
return State.GetTextAsync();
}
public override Task<VersionStamp> GetTextVersionAsync()
{
return State.GetTextVersionAsync();
}
public override Task<RazorCodeDocument> GetGeneratedOutputAsync()
{
// IMPORTANT: Don't put more code here. We want this to return a cached task.
return State.GeneratedOutput.GetGeneratedOutputInitializationTask(Project, this);
}
public override bool TryGetText(out SourceText result)
{
return State.TryGetText(out result);
}
public override bool TryGetTextVersion(out VersionStamp result)
{
return State.TryGetTextVersion(out result);
}
public override bool TryGetGeneratedOutput(out RazorCodeDocument result)
{
if (State.GeneratedOutput.IsResultAvailable)
{
result = State.GeneratedOutput.GetGeneratedOutputInitializationTask(Project, this).Result;
return true;
}
result = null;
return false;
}
}
}

View File

@ -1,84 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class DefaultProjectSnapshot : ProjectSnapshot
{
private readonly object _lock;
private Dictionary<string, DefaultDocumentSnapshot> _documents;
public DefaultProjectSnapshot(ProjectState state)
{
if (state == null)
{
throw new ArgumentNullException(nameof(state));
}
State = state;
_lock = new object();
_documents = new Dictionary<string, DefaultDocumentSnapshot>(FilePathComparer.Instance);
}
public ProjectState State { get; }
public override RazorConfiguration Configuration => HostProject.Configuration;
public override IEnumerable<string> DocumentFilePaths => State.Documents.Keys;
public override string FilePath => State.HostProject.FilePath;
public HostProject HostProject => State.HostProject;
public override bool IsInitialized => WorkspaceProject != null;
public override VersionStamp Version => State.Version;
public override Project WorkspaceProject => State.WorkspaceProject;
public override DocumentSnapshot GetDocument(string filePath)
{
lock (_lock)
{
if (!_documents.TryGetValue(filePath, out var result) &&
State.Documents.TryGetValue(filePath, out var state))
{
result = new DefaultDocumentSnapshot(this, state);
_documents.Add(filePath, result);
}
return result;
}
}
public override RazorProjectEngine GetProjectEngine()
{
return State.ProjectEngine.GetProjectEngine(this);
}
public override Task<IReadOnlyList<TagHelperDescriptor>> GetTagHelpersAsync()
{
// IMPORTANT: Don't put more code here. We want this to return a cached task.
return State.TagHelpers.GetTagHelperInitializationTask(this);
}
public override bool TryGetTagHelpers(out IReadOnlyList<TagHelperDescriptor> result)
{
if (State.TagHelpers.IsResultAvailable)
{
result = State.TagHelpers.GetTagHelperInitializationTask(this).Result;
return true;
}
result = null;
return false;
}
}
}

View File

@ -1,656 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
// The implementation of project snapshot manager abstracts over the Roslyn Project (WorkspaceProject)
// and information from the host's underlying project system (HostProject), to provide a unified and
// immutable view of the underlying project systems.
//
// The HostProject support all of the configuration that the Razor SDK exposes via the project system
// (language version, extensions, named configuration).
//
// The WorkspaceProject is needed to support our use of Roslyn Compilations for Tag Helpers and other
// C# based constructs.
//
// The implementation will create a ProjectSnapshot for each HostProject. Put another way, when we
// see a WorkspaceProject get created, we only care if we already have a HostProject for the same
// filepath.
//
// Our underlying HostProject infrastructure currently does not handle multiple TFMs (project with
// $(TargetFrameworks), so we just bind to the first WorkspaceProject we see for each HostProject.
internal class DefaultProjectSnapshotManager : ProjectSnapshotManagerBase
{
public override event EventHandler<ProjectChangeEventArgs> Changed;
private readonly ErrorReporter _errorReporter;
private readonly ForegroundDispatcher _foregroundDispatcher;
private readonly ProjectSnapshotChangeTrigger[] _triggers;
// Each entry holds a ProjectState and an optional ProjectSnapshot. ProjectSnapshots are
// created lazily.
private readonly Dictionary<string, Entry> _projects;
private readonly HashSet<string> _openDocuments;
public DefaultProjectSnapshotManager(
ForegroundDispatcher foregroundDispatcher,
ErrorReporter errorReporter,
IEnumerable<ProjectSnapshotChangeTrigger> triggers,
Workspace workspace)
{
if (foregroundDispatcher == null)
{
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
if (errorReporter == null)
{
throw new ArgumentNullException(nameof(errorReporter));
}
if (triggers == null)
{
throw new ArgumentNullException(nameof(triggers));
}
if (workspace == null)
{
throw new ArgumentNullException(nameof(workspace));
}
_foregroundDispatcher = foregroundDispatcher;
_errorReporter = errorReporter;
_triggers = triggers.ToArray();
Workspace = workspace;
_projects = new Dictionary<string, Entry>(FilePathComparer.Instance);
_openDocuments = new HashSet<string>(FilePathComparer.Instance);
for (var i = 0; i < _triggers.Length; i++)
{
_triggers[i].Initialize(this);
}
}
public override IReadOnlyList<ProjectSnapshot> Projects
{
get
{
_foregroundDispatcher.AssertForegroundThread();
var i = 0;
var projects = new ProjectSnapshot[_projects.Count];
foreach (var entry in _projects)
{
if (entry.Value.Snapshot == null)
{
entry.Value.Snapshot = new DefaultProjectSnapshot(entry.Value.State);
}
projects[i++] = entry.Value.Snapshot;
}
return projects;
}
}
public override Workspace Workspace { get; }
public override ProjectSnapshot GetLoadedProject(string filePath)
{
if (filePath == null)
{
throw new ArgumentNullException(nameof(filePath));
}
_foregroundDispatcher.AssertForegroundThread();
if (_projects.TryGetValue(filePath, out var entry))
{
if (entry.Snapshot == null)
{
entry.Snapshot = new DefaultProjectSnapshot(entry.State);
}
return entry.Snapshot;
}
return null;
}
public override ProjectSnapshot GetOrCreateProject(string filePath)
{
if (filePath == null)
{
throw new ArgumentNullException(nameof(filePath));
}
_foregroundDispatcher.AssertForegroundThread();
return GetLoadedProject(filePath) ?? new EphemeralProjectSnapshot(Workspace.Services, filePath);
}
public override bool IsDocumentOpen(string documentFilePath)
{
if (documentFilePath == null)
{
throw new ArgumentNullException(nameof(documentFilePath));
}
_foregroundDispatcher.AssertForegroundThread();
return _openDocuments.Contains(documentFilePath);
}
public override void DocumentAdded(HostProject hostProject, HostDocument document, TextLoader textLoader)
{
if (hostProject == null)
{
throw new ArgumentNullException(nameof(hostProject));
}
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
_foregroundDispatcher.AssertForegroundThread();
if (_projects.TryGetValue(hostProject.FilePath, out var entry))
{
var loader = textLoader == null ? DocumentState.EmptyLoader : (Func<Task<TextAndVersion>>)(() =>
{
return textLoader.LoadTextAndVersionAsync(Workspace, null, CancellationToken.None);
});
var state = entry.State.WithAddedHostDocument(document, loader);
// Document updates can no-op.
if (!object.ReferenceEquals(state, entry.State))
{
_projects[hostProject.FilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(hostProject.FilePath, document.FilePath, ProjectChangeKind.DocumentAdded));
}
}
}
public override void DocumentRemoved(HostProject hostProject, HostDocument document)
{
if (hostProject == null)
{
throw new ArgumentNullException(nameof(hostProject));
}
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
_foregroundDispatcher.AssertForegroundThread();
if (_projects.TryGetValue(hostProject.FilePath, out var entry))
{
var state = entry.State.WithRemovedHostDocument(document);
// Document updates can no-op.
if (!object.ReferenceEquals(state, entry.State))
{
_projects[hostProject.FilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(hostProject.FilePath, document.FilePath, ProjectChangeKind.DocumentRemoved));
}
}
}
public override void DocumentOpened(string projectFilePath, string documentFilePath, SourceText sourceText)
{
if (projectFilePath == null)
{
throw new ArgumentNullException(nameof(projectFilePath));
}
if (documentFilePath == null)
{
throw new ArgumentNullException(nameof(documentFilePath));
}
if (sourceText == null)
{
throw new ArgumentNullException(nameof(sourceText));
}
_foregroundDispatcher.AssertForegroundThread();
if (_projects.TryGetValue(projectFilePath, out var entry) &&
entry.State.Documents.TryGetValue(documentFilePath, out var older))
{
ProjectState state;
SourceText olderText;
VersionStamp olderVersion;
var currentText = sourceText;
if (older.TryGetText(out olderText) &&
older.TryGetTextVersion(out olderVersion))
{
var version = currentText.ContentEquals(olderText) ? olderVersion : olderVersion.GetNewerVersion();
state = entry.State.WithChangedHostDocument(older.HostDocument, currentText, version);
}
else
{
state = entry.State.WithChangedHostDocument(older.HostDocument, async () =>
{
olderText = await older.GetTextAsync().ConfigureAwait(false);
olderVersion = await older.GetTextVersionAsync().ConfigureAwait(false);
var version = currentText.ContentEquals(olderText) ? olderVersion : olderVersion.GetNewerVersion();
return TextAndVersion.Create(currentText, version, documentFilePath);
});
}
_openDocuments.Add(documentFilePath);
// Document updates can no-op.
if (!object.ReferenceEquals(state, entry.State))
{
_projects[projectFilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(projectFilePath, documentFilePath, ProjectChangeKind.DocumentChanged));
}
}
}
public override void DocumentClosed(string projectFilePath, string documentFilePath, TextLoader textLoader)
{
if (projectFilePath == null)
{
throw new ArgumentNullException(nameof(projectFilePath));
}
if (documentFilePath == null)
{
throw new ArgumentNullException(nameof(documentFilePath));
}
if (textLoader == null)
{
throw new ArgumentNullException(nameof(textLoader));
}
_foregroundDispatcher.AssertForegroundThread();
if (_projects.TryGetValue(projectFilePath, out var entry) &&
entry.State.Documents.TryGetValue(documentFilePath, out var older))
{
var state = entry.State.WithChangedHostDocument(older.HostDocument, async () =>
{
return await textLoader.LoadTextAndVersionAsync(Workspace, default, default);
});
_openDocuments.Remove(documentFilePath);
// Document updates can no-op.
if (!object.ReferenceEquals(state, entry.State))
{
_projects[projectFilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(projectFilePath, documentFilePath, ProjectChangeKind.DocumentChanged));
}
}
}
public override void DocumentChanged(string projectFilePath, string documentFilePath, SourceText sourceText)
{
if (projectFilePath == null)
{
throw new ArgumentNullException(nameof(projectFilePath));
}
if (documentFilePath == null)
{
throw new ArgumentNullException(nameof(documentFilePath));
}
if (sourceText == null)
{
throw new ArgumentNullException(nameof(sourceText));
}
_foregroundDispatcher.AssertForegroundThread();
if (_projects.TryGetValue(projectFilePath, out var entry) &&
entry.State.Documents.TryGetValue(documentFilePath, out var older))
{
ProjectState state;
SourceText olderText;
VersionStamp olderVersion;
var currentText = sourceText;
if (older.TryGetText(out olderText) &&
older.TryGetTextVersion(out olderVersion))
{
var version = currentText.ContentEquals(olderText) ? olderVersion : olderVersion.GetNewerVersion();
state = entry.State.WithChangedHostDocument(older.HostDocument, currentText, version);
}
else
{
state = entry.State.WithChangedHostDocument(older.HostDocument, async () =>
{
olderText = await older.GetTextAsync().ConfigureAwait(false);
olderVersion = await older.GetTextVersionAsync().ConfigureAwait(false);
var version = currentText.ContentEquals(olderText) ? olderVersion : olderVersion.GetNewerVersion();
return TextAndVersion.Create(currentText, version, documentFilePath);
});
}
// Document updates can no-op.
if (!object.ReferenceEquals(state, entry.State))
{
_projects[projectFilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(projectFilePath, documentFilePath, ProjectChangeKind.DocumentChanged));
}
}
}
public override void DocumentChanged(string projectFilePath, string documentFilePath, TextLoader textLoader)
{
if (projectFilePath == null)
{
throw new ArgumentNullException(nameof(projectFilePath));
}
if (documentFilePath == null)
{
throw new ArgumentNullException(nameof(documentFilePath));
}
if (textLoader == null)
{
throw new ArgumentNullException(nameof(textLoader));
}
_foregroundDispatcher.AssertForegroundThread();
if (_projects.TryGetValue(projectFilePath, out var entry) &&
entry.State.Documents.TryGetValue(documentFilePath, out var older))
{
var state = entry.State.WithChangedHostDocument(older.HostDocument, async () =>
{
return await textLoader.LoadTextAndVersionAsync(Workspace, default, default);
});
// Document updates can no-op.
if (!object.ReferenceEquals(state, entry.State))
{
_projects[projectFilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(projectFilePath, documentFilePath, ProjectChangeKind.DocumentChanged));
}
}
}
public override void HostProjectAdded(HostProject hostProject)
{
if (hostProject == null)
{
throw new ArgumentNullException(nameof(hostProject));
}
_foregroundDispatcher.AssertForegroundThread();
// We don't expect to see a HostProject initialized multiple times for the same path. Just ignore it.
if (_projects.ContainsKey(hostProject.FilePath))
{
return;
}
// It's possible that Workspace has already created a project for this, but it's not deterministic
// So if possible find a WorkspaceProject.
var workspaceProject = GetWorkspaceProject(hostProject.FilePath);
var state = ProjectState.Create(Workspace.Services, hostProject, workspaceProject);
_projects[hostProject.FilePath] = new Entry(state);
// We need to notify listeners about every project add.
NotifyListeners(new ProjectChangeEventArgs(hostProject.FilePath, ProjectChangeKind.ProjectAdded));
}
public override void HostProjectChanged(HostProject hostProject)
{
if (hostProject == null)
{
throw new ArgumentNullException(nameof(hostProject));
}
_foregroundDispatcher.AssertForegroundThread();
if (_projects.TryGetValue(hostProject.FilePath, out var entry))
{
var state = entry.State.WithHostProject(hostProject);
// HostProject updates can no-op.
if (!object.ReferenceEquals(state, entry.State))
{
_projects[hostProject.FilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(hostProject.FilePath, ProjectChangeKind.ProjectChanged));
}
}
}
public override void HostProjectRemoved(HostProject hostProject)
{
if (hostProject == null)
{
throw new ArgumentNullException(nameof(hostProject));
}
_foregroundDispatcher.AssertForegroundThread();
if (_projects.TryGetValue(hostProject.FilePath, out var snapshot))
{
_projects.Remove(hostProject.FilePath);
// We need to notify listeners about every project removal.
NotifyListeners(new ProjectChangeEventArgs(hostProject.FilePath, ProjectChangeKind.ProjectRemoved));
}
}
public override void WorkspaceProjectAdded(Project workspaceProject)
{
if (workspaceProject == null)
{
throw new ArgumentNullException(nameof(workspaceProject));
}
_foregroundDispatcher.AssertForegroundThread();
if (!IsSupportedWorkspaceProject(workspaceProject))
{
return;
}
// The WorkspaceProject initialization never triggers a "Project Add" from out point of view, we
// only care if the new WorkspaceProject matches an existing HostProject.
if (_projects.TryGetValue(workspaceProject.FilePath, out var entry))
{
// If this is a multi-targeting project then we are only interested in a single workspace project. If we already
// found one in the past just ignore this one.
if (entry.State.WorkspaceProject == null)
{
var state = entry.State.WithWorkspaceProject(workspaceProject);
_projects[workspaceProject.FilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(workspaceProject.FilePath, ProjectChangeKind.ProjectChanged));
}
}
}
public override void WorkspaceProjectChanged(Project workspaceProject)
{
if (workspaceProject == null)
{
throw new ArgumentNullException(nameof(workspaceProject));
}
_foregroundDispatcher.AssertForegroundThread();
if (!IsSupportedWorkspaceProject(workspaceProject))
{
return;
}
// We also need to check the projectId here. If this is a multi-targeting project then we are only interested
// in a single workspace project. Just use the one that showed up first.
if (_projects.TryGetValue(workspaceProject.FilePath, out var entry) &&
(entry.State.WorkspaceProject == null || entry.State.WorkspaceProject.Id == workspaceProject.Id) &&
(entry.State.WorkspaceProject == null || entry.State.WorkspaceProject.Version.GetNewerVersion(workspaceProject.Version) == workspaceProject.Version))
{
var state = entry.State.WithWorkspaceProject(workspaceProject);
// WorkspaceProject updates can no-op. This can be the case if a build is triggered, but we've
// already seen the update.
if (!object.ReferenceEquals(state, entry.State))
{
_projects[workspaceProject.FilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(workspaceProject.FilePath, ProjectChangeKind.ProjectChanged));
}
}
}
public override void WorkspaceProjectRemoved(Project workspaceProject)
{
if (workspaceProject == null)
{
throw new ArgumentNullException(nameof(workspaceProject));
}
_foregroundDispatcher.AssertForegroundThread();
if (!IsSupportedWorkspaceProject(workspaceProject))
{
return;
}
if (_projects.TryGetValue(workspaceProject.FilePath, out var entry))
{
// We also need to check the projectId here. If this is a multi-targeting project then we are only interested
// in a single workspace project. Make sure the WorkspaceProject we're using is the one that's being removed.
if (entry.State.WorkspaceProject?.Id != workspaceProject.Id)
{
return;
}
ProjectState state;
// So if the WorkspaceProject got removed, we should double check to make sure that there aren't others
// hanging around. This could happen if a project is multi-targeting and one of the TFMs is removed.
var otherWorkspaceProject = GetWorkspaceProject(workspaceProject.FilePath);
if (otherWorkspaceProject != null && otherWorkspaceProject.Id != workspaceProject.Id)
{
// OK there's another WorkspaceProject, use that.
state = entry.State.WithWorkspaceProject(otherWorkspaceProject);
_projects[otherWorkspaceProject.FilePath] = new Entry(state);
NotifyListeners(new ProjectChangeEventArgs(otherWorkspaceProject.FilePath, ProjectChangeKind.ProjectChanged));
}
else
{
state = entry.State.WithWorkspaceProject(null);
_projects[workspaceProject.FilePath] = new Entry(state);
// Notify listeners of a change because we've removed computed state.
NotifyListeners(new ProjectChangeEventArgs(workspaceProject.FilePath, ProjectChangeKind.ProjectChanged));
}
}
}
public override void ReportError(Exception exception)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
_errorReporter.ReportError(exception);
}
public override void ReportError(Exception exception, ProjectSnapshot project)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
_errorReporter.ReportError(exception, project);
}
public override void ReportError(Exception exception, HostProject hostProject)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
var snapshot = hostProject?.FilePath == null ? null : GetLoadedProject(hostProject.FilePath);
_errorReporter.ReportError(exception, snapshot);
}
public override void ReportError(Exception exception, Project workspaceProject)
{
if (exception == null)
{
throw new ArgumentNullException(nameof(exception));
}
_errorReporter.ReportError(exception, workspaceProject);
}
// We're only interested in CSharp projects that have a FilePath. We rely on the FilePath to
// unify the Workspace Project with our HostProject concept.
private bool IsSupportedWorkspaceProject(Project workspaceProject) => workspaceProject.Language == LanguageNames.CSharp && workspaceProject.FilePath != null;
private Project GetWorkspaceProject(string filePath)
{
var solution = Workspace.CurrentSolution;
if (solution == null)
{
return null;
}
foreach (var workspaceProject in solution.Projects)
{
if (IsSupportedWorkspaceProject(workspaceProject) &&
FilePathComparer.Instance.Equals(filePath, workspaceProject.FilePath))
{
// We don't try to handle mulitple TFMs anwhere in Razor, just take the first WorkspaceProject that is a match.
return workspaceProject;
}
}
return null;
}
// virtual so it can be overridden in tests
protected virtual void NotifyListeners(ProjectChangeEventArgs e)
{
_foregroundDispatcher.AssertForegroundThread();
var handler = Changed;
if (handler != null)
{
handler(this, e);
}
}
private class Entry
{
public ProjectSnapshot Snapshot;
public readonly ProjectState State;
public Entry(ProjectState state)
{
State = state;
}
}
}
}

View File

@ -1,52 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
[Shared]
[ExportLanguageServiceFactory(typeof(ProjectSnapshotManager), RazorLanguage.Name)]
internal class DefaultProjectSnapshotManagerFactory : ILanguageServiceFactory
{
private readonly IEnumerable<ProjectSnapshotChangeTrigger> _triggers;
private readonly ForegroundDispatcher _foregroundDispatcher;
[ImportingConstructor]
public DefaultProjectSnapshotManagerFactory(
ForegroundDispatcher foregroundDispatcher,
[ImportMany] IEnumerable<ProjectSnapshotChangeTrigger> triggers)
{
if (foregroundDispatcher == null)
{
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
if (triggers == null)
{
throw new ArgumentNullException(nameof(triggers));
}
_foregroundDispatcher = foregroundDispatcher;
_triggers = triggers;
}
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
if (languageServices == null)
{
throw new ArgumentNullException(nameof(languageServices));
}
return new DefaultProjectSnapshotManager(
_foregroundDispatcher,
languageServices.WorkspaceServices.GetRequiredService<ErrorReporter>(),
_triggers,
languageServices.WorkspaceServices.Workspace);
}
}
}

View File

@ -1,172 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Text;
using Microsoft.Extensions.Internal;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class DocumentGeneratedOutputTracker
{
private readonly object _lock;
private DocumentGeneratedOutputTracker _older;
private Task<RazorCodeDocument> _task;
private IReadOnlyList<TagHelperDescriptor> _tagHelpers;
private IReadOnlyList<ImportItem> _imports;
public DocumentGeneratedOutputTracker(DocumentGeneratedOutputTracker older)
{
_older = older;
_lock = new object();
}
public bool IsResultAvailable => _task?.IsCompleted == true;
public DocumentGeneratedOutputTracker Older => _older;
public Task<RazorCodeDocument> GetGeneratedOutputInitializationTask(ProjectSnapshot project, DocumentSnapshot document)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
if (_task == null)
{
lock (_lock)
{
if (_task == null)
{
_task = GetGeneratedOutputInitializationTaskCore(project, document);
}
}
}
return _task;
}
public DocumentGeneratedOutputTracker Fork()
{
return new DocumentGeneratedOutputTracker(this);
}
private async Task<RazorCodeDocument> GetGeneratedOutputInitializationTaskCore(ProjectSnapshot project, DocumentSnapshot document)
{
var tagHelpers = await project.GetTagHelpersAsync().ConfigureAwait(false);
var imports = await GetImportsAsync(project, document);
if (_older != null && _older.IsResultAvailable)
{
var tagHelperDifference = new HashSet<TagHelperDescriptor>(TagHelperDescriptorComparer.Default);
tagHelperDifference.UnionWith(_older._tagHelpers);
tagHelperDifference.SymmetricExceptWith(tagHelpers);
var importDifference = new HashSet<ImportItem>();
importDifference.UnionWith(_older._imports);
importDifference.SymmetricExceptWith(imports);
if (tagHelperDifference.Count == 0 && importDifference.Count == 0)
{
// We can use the cached result.
var result = _older._task.Result;
// Drop reference so it can be GC'ed
_older = null;
// Cache the tag helpers and imports so the next version can use them
_tagHelpers = tagHelpers;
_imports = imports;
return result;
}
}
// Drop reference so it can be GC'ed
_older = null;
// Cache the tag helpers and imports so the next version can use them
_tagHelpers = tagHelpers;
_imports = imports;
var importSources = new List<RazorSourceDocument>();
foreach (var item in imports)
{
var sourceDocument = await GetRazorSourceDocumentAsync(item.Import);
importSources.Add(sourceDocument);
}
var documentSource = await GetRazorSourceDocumentAsync(document);
var projectEngine = project.GetProjectEngine();
return projectEngine.ProcessDesignTime(documentSource, importSources, tagHelpers);
}
private async Task<RazorSourceDocument> GetRazorSourceDocumentAsync(DocumentSnapshot document)
{
var sourceText = await document.GetTextAsync();
return sourceText.GetRazorSourceDocument(document.FilePath);
}
private async Task<IReadOnlyList<ImportItem>> GetImportsAsync(ProjectSnapshot project, DocumentSnapshot document)
{
var imports = new List<ImportItem>();
foreach (var snapshot in document.GetImports())
{
var versionStamp = await snapshot.GetTextVersionAsync();
imports.Add(new ImportItem(snapshot.FilePath, versionStamp, snapshot));
}
return imports;
}
private struct ImportItem : IEquatable<ImportItem>
{
public ImportItem(string filePath, VersionStamp versionStamp, DocumentSnapshot import)
{
FilePath = filePath;
VersionStamp = versionStamp;
Import = import;
}
public string FilePath { get; }
public VersionStamp VersionStamp { get; }
public DocumentSnapshot Import { get; }
public bool Equals(ImportItem other)
{
return
FilePathComparer.Instance.Equals(FilePath, other.FilePath) &&
VersionStamp == other.VersionStamp;
}
public override bool Equals(object obj)
{
return obj is ImportItem item ? Equals(item) : false;
}
public override int GetHashCode()
{
var hash = new HashCodeCombiner();
hash.Add(FilePath, FilePathComparer.Instance);
hash.Add(VersionStamp);
return hash;
}
}
}
}

View File

@ -1,165 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class DocumentImportsTracker
{
private readonly object _lock;
private IReadOnlyList<DocumentSnapshot> _imports;
public DocumentImportsTracker()
{
_lock = new object();
}
public IReadOnlyList<DocumentSnapshot> GetImports(ProjectSnapshot project, DocumentSnapshot document)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
if (_imports == null)
{
lock (_lock)
{
if (_imports == null)
{
_imports = GetImportsCore(project, document);
}
}
}
return _imports;
}
private IReadOnlyList<DocumentSnapshot> GetImportsCore(ProjectSnapshot project, DocumentSnapshot document)
{
var projectEngine = project.GetProjectEngine();
var importFeature = projectEngine.ProjectFeatures.OfType<IImportProjectFeature>().FirstOrDefault();
var projectItem = projectEngine.FileSystem.GetItem(document.FilePath);
var importItems = importFeature?.GetImports(projectItem).Where(i => i.Exists);
if (importItems == null)
{
return Array.Empty<DocumentSnapshot>();
}
var imports = new List<DocumentSnapshot>();
foreach (var item in importItems)
{
if (item.PhysicalPath == null)
{
// This is a default import.
var defaultImport = new DefaultImportDocumentSnapshot(project, item);
imports.Add(defaultImport);
}
else
{
var import = project.GetDocument(item.PhysicalPath);
if (import == null)
{
// We are not tracking this document in this project. So do nothing.
continue;
}
imports.Add(import);
}
}
return imports;
}
private class DefaultImportDocumentSnapshot : DocumentSnapshot
{
private ProjectSnapshot _project;
private RazorProjectItem _importItem;
private SourceText _sourceText;
private VersionStamp _version;
private DocumentGeneratedOutputTracker _generatedOutput;
public DefaultImportDocumentSnapshot(ProjectSnapshot project, RazorProjectItem item)
{
_project = project;
_importItem = item;
_version = VersionStamp.Default;
_generatedOutput = new DocumentGeneratedOutputTracker(null);
}
public override string FilePath => null;
public override string TargetPath => null;
public override Task<RazorCodeDocument> GetGeneratedOutputAsync()
{
return _generatedOutput.GetGeneratedOutputInitializationTask(_project, this);
}
public override IReadOnlyList<DocumentSnapshot> GetImports()
{
return Array.Empty<DocumentSnapshot>();
}
public async override Task<SourceText> GetTextAsync()
{
using (var stream = _importItem.Read())
using (var reader = new StreamReader(stream))
{
var content = await reader.ReadToEndAsync();
_sourceText = SourceText.From(content);
}
return _sourceText;
}
public override Task<VersionStamp> GetTextVersionAsync()
{
return Task.FromResult(_version);
}
public override bool TryGetText(out SourceText result)
{
if (_sourceText != null)
{
result = _sourceText;
return true;
}
result = null;
return false;
}
public override bool TryGetTextVersion(out VersionStamp result)
{
result = _version;
return true;
}
public override bool TryGetGeneratedOutput(out RazorCodeDocument result)
{
if (_generatedOutput.IsResultAvailable)
{
result = GetGeneratedOutputAsync().Result;
return true;
}
result = null;
return false;
}
}
}
}

View File

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

View File

@ -1,219 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class DocumentState
{
private static readonly TextAndVersion EmptyText = TextAndVersion.Create(
SourceText.From(string.Empty),
VersionStamp.Default);
public static readonly Func<Task<TextAndVersion>> EmptyLoader = () => Task.FromResult(EmptyText);
private readonly object _lock;
private Func<Task<TextAndVersion>> _loader;
private Task<TextAndVersion> _loaderTask;
private SourceText _sourceText;
private VersionStamp? _version;
private DocumentGeneratedOutputTracker _generatedOutput;
private DocumentImportsTracker _imports;
public static DocumentState Create(
HostWorkspaceServices services,
HostDocument hostDocument,
Func<Task<TextAndVersion>> loader)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (hostDocument == null)
{
throw new ArgumentNullException(nameof(hostDocument));
}
loader = loader ?? EmptyLoader;
return new DocumentState(services, hostDocument, null, null, loader);
}
// Internal for testing
internal DocumentState(
HostWorkspaceServices services,
HostDocument hostDocument,
SourceText text,
VersionStamp? version,
Func<Task<TextAndVersion>> loader)
{
Services = services;
HostDocument = hostDocument;
_sourceText = text;
_version = version;
_loader = loader;
_lock = new object();
}
public HostDocument HostDocument { get; }
public HostWorkspaceServices Services { get; }
public DocumentGeneratedOutputTracker GeneratedOutput
{
get
{
if (_generatedOutput == null)
{
lock (_lock)
{
if (_generatedOutput == null)
{
_generatedOutput = new DocumentGeneratedOutputTracker(null);
}
}
}
return _generatedOutput;
}
}
public DocumentImportsTracker Imports
{
get
{
if (_imports == null)
{
lock (_lock)
{
if (_imports == null)
{
_imports = new DocumentImportsTracker();
}
}
}
return _imports;
}
}
public async Task<SourceText> GetTextAsync()
{
if (TryGetText(out var text))
{
return text;
}
lock (_lock)
{
_loaderTask = _loader();
}
return (await _loaderTask.ConfigureAwait(false)).Text;
}
public async Task<VersionStamp> GetTextVersionAsync()
{
if (TryGetTextVersion(out var version))
{
return version;
}
lock (_lock)
{
_loaderTask = _loader();
}
return (await _loaderTask.ConfigureAwait(false)).Version;
}
public bool TryGetText(out SourceText result)
{
if (_sourceText != null)
{
result = _sourceText;
return true;
}
if (_loaderTask != null && _loaderTask.IsCompleted)
{
result = _loaderTask.Result.Text;
return true;
}
result = null;
return false;
}
public bool TryGetTextVersion(out VersionStamp result)
{
if (_version != null)
{
result = _version.Value;
return true;
}
if (_loaderTask != null && _loaderTask.IsCompleted)
{
result = _loaderTask.Result.Version;
return true;
}
result = default;
return false;
}
public virtual DocumentState WithConfigurationChange()
{
var state = new DocumentState(Services, HostDocument, _sourceText, _version, _loader);
// The source could not have possibly changed.
state._sourceText = _sourceText;
state._version = _version;
state._loaderTask = _loaderTask;
return state;
}
public virtual DocumentState WithWorkspaceProjectChange()
{
var state = new DocumentState(Services, HostDocument, _sourceText, _version, _loader);
// The source could not have possibly changed.
state._sourceText = _sourceText;
state._version = _version;
state._loaderTask = _loaderTask;
// Opportunistically cache the generated code
state._generatedOutput = _generatedOutput?.Fork();
return state;
}
public virtual DocumentState WithText(SourceText sourceText, VersionStamp version)
{
if (sourceText == null)
{
throw new ArgumentNullException(nameof(sourceText));
}
return new DocumentState(Services, HostDocument, sourceText, version, null);
}
public virtual DocumentState WithTextLoader(Func<Task<TextAndVersion>> loader)
{
if (loader == null)
{
throw new ArgumentNullException(nameof(loader));
}
return new DocumentState(Services, HostDocument, null, null, loader);
}
}
}

View File

@ -1,81 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class EphemeralProjectSnapshot : ProjectSnapshot
{
private static readonly Task<IReadOnlyList<TagHelperDescriptor>> EmptyTagHelpers = Task.FromResult<IReadOnlyList<TagHelperDescriptor>>(Array.Empty<TagHelperDescriptor>());
private readonly HostWorkspaceServices _services;
private readonly Lazy<RazorProjectEngine> _projectEngine;
public EphemeralProjectSnapshot(HostWorkspaceServices services, string filePath)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (filePath == null)
{
throw new ArgumentNullException(nameof(filePath));
}
_services = services;
FilePath = filePath;
_projectEngine = new Lazy<RazorProjectEngine>(CreateProjectEngine);
}
public override RazorConfiguration Configuration => FallbackRazorConfiguration.MVC_2_1;
public override IEnumerable<string> DocumentFilePaths => Array.Empty<string>();
public override string FilePath { get; }
public override bool IsInitialized => false;
public override VersionStamp Version { get; } = VersionStamp.Default;
public override Project WorkspaceProject => null;
public override DocumentSnapshot GetDocument(string filePath)
{
if (filePath == null)
{
throw new ArgumentNullException(nameof(filePath));
}
return null;
}
public override RazorProjectEngine GetProjectEngine()
{
return _projectEngine.Value;
}
public override Task<IReadOnlyList<TagHelperDescriptor>> GetTagHelpersAsync()
{
return EmptyTagHelpers;
}
public override bool TryGetTagHelpers(out IReadOnlyList<TagHelperDescriptor> result)
{
result = EmptyTagHelpers.Result;
return true;
}
private RazorProjectEngine CreateProjectEngine()
{
var factory = _services.GetRequiredService<ProjectSnapshotProjectEngineFactory>();
return factory.Create(this);
}
}
}

View File

@ -1,88 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class FallbackRazorConfiguration : RazorConfiguration
{
public static readonly RazorConfiguration MVC_1_0 = new FallbackRazorConfiguration(
RazorLanguageVersion.Version_1_0,
"MVC-1.0",
new[] { new FallbackRazorExtension("MVC-1.0"), });
public static readonly RazorConfiguration MVC_1_1 = new FallbackRazorConfiguration(
RazorLanguageVersion.Version_1_1,
"MVC-1.1",
new[] { new FallbackRazorExtension("MVC-1.1"), });
public static readonly RazorConfiguration MVC_2_0 = new FallbackRazorConfiguration(
RazorLanguageVersion.Version_2_0,
"MVC-2.0",
new[] { new FallbackRazorExtension("MVC-2.0"), });
public static readonly RazorConfiguration MVC_2_1 = new FallbackRazorConfiguration(
RazorLanguageVersion.Version_2_1,
"MVC-2.1",
new[] { new FallbackRazorExtension("MVC-2.1"), });
public static RazorConfiguration SelectConfiguration(Version version)
{
if (version.Major == 1 && version.Minor == 0)
{
return MVC_1_0;
}
else if (version.Major == 1 && version.Minor == 1)
{
return MVC_1_1;
}
else if (version.Major == 2 && version.Minor == 0)
{
return MVC_2_0;
}
else if (version.Major == 2 && version.Minor == 1)
{
return MVC_2_1;
}
else
{
return MVC_2_1;
}
}
public FallbackRazorConfiguration(
RazorLanguageVersion languageVersion,
string configurationName,
RazorExtension[] extensions)
{
if (languageVersion == null)
{
throw new ArgumentNullException(nameof(languageVersion));
}
if (configurationName == null)
{
throw new ArgumentNullException(nameof(configurationName));
}
if (extensions == null)
{
throw new ArgumentNullException(nameof(extensions));
}
LanguageVersion = languageVersion;
ConfigurationName = configurationName;
Extensions = extensions;
}
public override string ConfigurationName { get; }
public override IReadOnlyList<RazorExtension> Extensions { get; }
public override RazorLanguageVersion LanguageVersion { get; }
}
}

View File

@ -1,23 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class FallbackRazorExtension : RazorExtension
{
public FallbackRazorExtension(string extensionName)
{
if (extensionName == null)
{
throw new ArgumentNullException(nameof(extensionName));
}
ExtensionName = extensionName;
}
public override string ExtensionName { get; }
}
}

View File

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

View File

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

View File

@ -1,36 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Razor.Workspaces.ProjectSystem
{
// This is a marker class to allow us to know when potential breaking changes might impact live share.
// This is intentionally not abstract so any API changes that happen to ProjectSnapshot will break this.
internal class LiveShareProjectSnapshotBase : ProjectSnapshot
{
public override RazorConfiguration Configuration => throw new NotImplementedException();
public override IEnumerable<string> DocumentFilePaths => throw new NotImplementedException();
public override string FilePath => throw new NotImplementedException();
public override bool IsInitialized => throw new NotImplementedException();
public override VersionStamp Version => throw new NotImplementedException();
public override Project WorkspaceProject => throw new NotImplementedException();
public override DocumentSnapshot GetDocument(string filePath) => throw new NotImplementedException();
public override RazorProjectEngine GetProjectEngine() => throw new NotImplementedException();
public override Task<IReadOnlyList<TagHelperDescriptor>> GetTagHelpersAsync() => throw new NotImplementedException();
public override bool TryGetTagHelpers(out IReadOnlyList<TagHelperDescriptor> result) => throw new NotImplementedException();
}
}

View File

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

View File

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

View File

@ -1,20 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
[Flags]
internal enum ProjectDifference
{
None = 0,
ConfigurationChanged = 1,
WorkspaceProjectAdded = 2,
WorkspaceProjectRemoved = 4,
WorkspaceProjectChanged = 8,
DocumentAdded = 16,
DocumentRemoved = 32,
DocumentChanged = 64,
}
}

View File

@ -1,66 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class ProjectEngineTracker
{
private const ProjectDifference Mask = ProjectDifference.ConfigurationChanged;
private readonly object _lock = new object();
private readonly HostWorkspaceServices _services;
private RazorProjectEngine _projectEngine;
public ProjectEngineTracker(ProjectState state)
{
if (state == null)
{
throw new ArgumentNullException(nameof(state));
}
_services = state.Services;
}
public ProjectEngineTracker ForkFor(ProjectState state, ProjectDifference difference)
{
if (state == null)
{
throw new ArgumentNullException(nameof(state));
}
if ((difference & Mask) != 0)
{
return null;
}
return this;
}
public RazorProjectEngine GetProjectEngine(ProjectSnapshot snapshot)
{
if (snapshot == null)
{
throw new ArgumentNullException(nameof(snapshot));
}
if (_projectEngine == null)
{
lock (_lock)
{
if (_projectEngine == null)
{
var factory = _services.GetRequiredService<ProjectSnapshotProjectEngineFactory>();
_projectEngine = factory.Create(snapshot);
}
}
}
return _projectEngine;
}
}
}

View File

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

View File

@ -1,10 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal abstract class ProjectSnapshotChangeTrigger
{
public abstract void Initialize(ProjectSnapshotManagerBase projectManager);
}
}

View File

@ -1,22 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal abstract class ProjectSnapshotManager : ILanguageService
{
public abstract event EventHandler<ProjectChangeEventArgs> Changed;
public abstract IReadOnlyList<ProjectSnapshot> Projects { get; }
public abstract bool IsDocumentOpen(string documentFilePath);
public abstract ProjectSnapshot GetLoadedProject(string filePath);
public abstract ProjectSnapshot GetOrCreateProject(string filePath);
}
}

View File

@ -1,46 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal abstract class ProjectSnapshotManagerBase : ProjectSnapshotManager
{
public abstract Workspace Workspace { get; }
public abstract void DocumentAdded(HostProject hostProject, HostDocument hostDocument, TextLoader textLoader);
// Yeah this is kinda ugly.
public abstract void DocumentOpened(string projectFilePath, string documentFilePath, SourceText sourceText);
public abstract void DocumentClosed(string projectFilePath, string documentFilePath, TextLoader textLoader);
public abstract void DocumentChanged(string projectFilePath, string documentFilePath, TextLoader textLoader);
public abstract void DocumentChanged(string projectFilePath, string documentFilePath, SourceText sourceText);
public abstract void DocumentRemoved(HostProject hostProject, HostDocument hostDocument);
public abstract void HostProjectAdded(HostProject hostProject);
public abstract void HostProjectChanged(HostProject hostProject);
public abstract void HostProjectRemoved(HostProject hostProject);
public abstract void WorkspaceProjectAdded(Project workspaceProject);
public abstract void WorkspaceProjectChanged(Project workspaceProject);
public abstract void WorkspaceProjectRemoved(Project workspaceProject);
public abstract void ReportError(Exception exception);
public abstract void ReportError(Exception exception, ProjectSnapshot project);
public abstract void ReportError(Exception exception, HostProject hostProject);
public abstract void ReportError(Exception exception, Project workspaceProject);
}
}

View File

@ -1,304 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Text;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
// Internal tracker for DefaultProjectSnapshot
internal class ProjectState
{
private static readonly IReadOnlyDictionary<string, DocumentState> EmptyDocuments = new Dictionary<string, DocumentState>();
private readonly object _lock;
private ProjectEngineTracker _projectEngine;
private ProjectTagHelperTracker _tagHelpers;
public static ProjectState Create(HostWorkspaceServices services, HostProject hostProject, Project workspaceProject = null)
{
if (services == null)
{
throw new ArgumentNullException(nameof(services));
}
if (hostProject == null)
{
throw new ArgumentNullException(nameof(hostProject));
}
return new ProjectState(services, hostProject, workspaceProject);
}
private ProjectState(
HostWorkspaceServices services,
HostProject hostProject,
Project workspaceProject)
{
Services = services;
HostProject = hostProject;
WorkspaceProject = workspaceProject;
Documents = EmptyDocuments;
Version = VersionStamp.Create();
_lock = new object();
}
private ProjectState(
ProjectState older,
ProjectDifference difference,
HostProject hostProject,
Project workspaceProject,
IReadOnlyDictionary<string, DocumentState> documents)
{
if (older == null)
{
throw new ArgumentNullException(nameof(older));
}
if (hostProject == null)
{
throw new ArgumentNullException(nameof(hostProject));
}
if (documents == null)
{
throw new ArgumentNullException(nameof(documents));
}
Services = older.Services;
Version = older.Version.GetNewerVersion();
HostProject = hostProject;
WorkspaceProject = workspaceProject;
Documents = documents;
_lock = new object();
_projectEngine = older._projectEngine?.ForkFor(this, difference);
_tagHelpers = older._tagHelpers?.ForkFor(this, difference);
}
// Internal set for testing.
public IReadOnlyDictionary<string, DocumentState> Documents { get; internal set; }
public HostProject HostProject { get; }
public HostWorkspaceServices Services { get; }
public Project WorkspaceProject { get; }
public VersionStamp Version { get; }
// Computed State
public ProjectEngineTracker ProjectEngine
{
get
{
if (_projectEngine == null)
{
lock (_lock)
{
if (_projectEngine == null)
{
_projectEngine = new ProjectEngineTracker(this);
}
}
}
return _projectEngine;
}
}
// Computed State
public ProjectTagHelperTracker TagHelpers
{
get
{
if (_tagHelpers == null)
{
lock (_lock)
{
if (_tagHelpers == null)
{
_tagHelpers = new ProjectTagHelperTracker(this);
}
}
}
return _tagHelpers;
}
}
public ProjectState WithAddedHostDocument(HostDocument hostDocument, Func<Task<TextAndVersion>> loader)
{
if (hostDocument == null)
{
throw new ArgumentNullException(nameof(hostDocument));
}
if (loader == null)
{
throw new ArgumentNullException(nameof(loader));
}
// Ignore attempts to 'add' a document with different data, we only
// care about one, so it might as well be the one we have.
if (Documents.ContainsKey(hostDocument.FilePath))
{
return this;
}
var documents = new Dictionary<string, DocumentState>(FilePathComparer.Instance);
foreach (var kvp in Documents)
{
documents.Add(kvp.Key, kvp.Value);
}
documents.Add(hostDocument.FilePath, DocumentState.Create(Services, hostDocument, loader));
var difference = ProjectDifference.DocumentAdded;
var state = new ProjectState(this, difference, HostProject, WorkspaceProject, documents);
return state;
}
public ProjectState WithRemovedHostDocument(HostDocument hostDocument)
{
if (hostDocument == null)
{
throw new ArgumentNullException(nameof(hostDocument));
}
if (!Documents.ContainsKey(hostDocument.FilePath))
{
return this;
}
var documents = new Dictionary<string, DocumentState>(FilePathComparer.Instance);
foreach (var kvp in Documents)
{
documents.Add(kvp.Key, kvp.Value);
}
documents.Remove(hostDocument.FilePath);
var difference = ProjectDifference.DocumentRemoved;
var state = new ProjectState(this, difference, HostProject, WorkspaceProject, documents);
return state;
}
public ProjectState WithChangedHostDocument(HostDocument hostDocument, SourceText sourceText, VersionStamp version)
{
if (hostDocument == null)
{
throw new ArgumentNullException(nameof(hostDocument));
}
if (!Documents.ContainsKey(hostDocument.FilePath))
{
return this;
}
var documents = new Dictionary<string, DocumentState>(FilePathComparer.Instance);
foreach (var kvp in Documents)
{
documents.Add(kvp.Key, kvp.Value);
}
if (documents.TryGetValue(hostDocument.FilePath, out var document))
{
documents[hostDocument.FilePath] = document.WithText(sourceText, version);
}
var state = new ProjectState(this, ProjectDifference.DocumentChanged, HostProject, WorkspaceProject, documents);
return state;
}
public ProjectState WithChangedHostDocument(HostDocument hostDocument, Func<Task<TextAndVersion>> loader)
{
if (hostDocument == null)
{
throw new ArgumentNullException(nameof(hostDocument));
}
if (!Documents.ContainsKey(hostDocument.FilePath))
{
return this;
}
var documents = new Dictionary<string, DocumentState>(FilePathComparer.Instance);
foreach (var kvp in Documents)
{
documents.Add(kvp.Key, kvp.Value);
}
if (documents.TryGetValue(hostDocument.FilePath, out var document))
{
documents[hostDocument.FilePath] = document.WithTextLoader(loader);
}
var state = new ProjectState(this, ProjectDifference.DocumentChanged, HostProject, WorkspaceProject, documents);
return state;
}
public ProjectState WithHostProject(HostProject hostProject)
{
if (hostProject == null)
{
throw new ArgumentNullException(nameof(hostProject));
}
if (HostProject.Configuration.Equals(hostProject.Configuration))
{
return this;
}
var difference = ProjectDifference.ConfigurationChanged;
var documents = new Dictionary<string, DocumentState>(FilePathComparer.Instance);
foreach (var kvp in Documents)
{
documents.Add(kvp.Key, kvp.Value.WithConfigurationChange());
}
var state = new ProjectState(this, difference, hostProject, WorkspaceProject, documents);
return state;
}
public ProjectState WithWorkspaceProject(Project workspaceProject)
{
var difference = ProjectDifference.None;
if (WorkspaceProject == null && workspaceProject != null)
{
difference |= ProjectDifference.WorkspaceProjectAdded;
}
else if (WorkspaceProject != null && workspaceProject == null)
{
difference |= ProjectDifference.WorkspaceProjectRemoved;
}
else
{
// We always update the snapshot right now when the project changes. This is how
// we deal with changes to the content of C# sources.
difference |= ProjectDifference.WorkspaceProjectChanged;
}
if (difference == ProjectDifference.None)
{
return this;
}
var documents = new Dictionary<string, DocumentState>(FilePathComparer.Instance);
foreach (var kvp in Documents)
{
documents.Add(kvp.Key, kvp.Value.WithWorkspaceProjectChange());
}
var state = new ProjectState(this, difference, HostProject, workspaceProject, documents);
return state;
}
}
}

View File

@ -1,43 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class ProjectSystemRazorConfiguration : RazorConfiguration
{
public ProjectSystemRazorConfiguration(
RazorLanguageVersion languageVersion,
string configurationName,
RazorExtension[] extensions)
{
if (languageVersion == null)
{
throw new ArgumentNullException(nameof(languageVersion));
}
if (configurationName == null)
{
throw new ArgumentNullException(nameof(configurationName));
}
if (extensions == null)
{
throw new ArgumentNullException(nameof(extensions));
}
LanguageVersion = languageVersion;
ConfigurationName = configurationName;
Extensions = extensions;
}
public override string ConfigurationName { get; }
public override IReadOnlyList<RazorExtension> Extensions { get; }
public override RazorLanguageVersion LanguageVersion { get; }
}
}

View File

@ -1,23 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class ProjectSystemRazorExtension : RazorExtension
{
public ProjectSystemRazorExtension(string extensionName)
{
if (extensionName == null)
{
throw new ArgumentNullException(nameof(extensionName));
}
ExtensionName = extensionName;
}
public override string ExtensionName { get; }
}
}

View File

@ -1,79 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
internal class ProjectTagHelperTracker
{
private const ProjectDifference Mask =
ProjectDifference.ConfigurationChanged |
ProjectDifference.WorkspaceProjectAdded |
ProjectDifference.WorkspaceProjectChanged |
ProjectDifference.WorkspaceProjectRemoved;
private readonly object _lock = new object();
private readonly HostWorkspaceServices _services;
private Task<IReadOnlyList<TagHelperDescriptor>> _task;
public ProjectTagHelperTracker(ProjectState state)
{
if (state == null)
{
throw new ArgumentNullException(nameof(state));
}
_services = state.Services;
}
public bool IsResultAvailable => _task?.IsCompleted == true;
public ProjectTagHelperTracker ForkFor(ProjectState state, ProjectDifference difference)
{
if (state == null)
{
throw new ArgumentNullException(nameof(state));
}
if ((difference & Mask) != 0)
{
return null;
}
return this;
}
public Task<IReadOnlyList<TagHelperDescriptor>> GetTagHelperInitializationTask(ProjectSnapshot snapshot)
{
if (snapshot == null)
{
throw new ArgumentNullException(nameof(snapshot));
}
if (_task == null)
{
lock (_lock)
{
if (_task == null)
{
_task = GetTagHelperInitializationTaskCore(snapshot);
}
}
}
return _task;
}
private async Task<IReadOnlyList<TagHelperDescriptor>> GetTagHelperInitializationTaskCore(ProjectSnapshot snapshot)
{
var resolver = _services.GetLanguageServices(RazorLanguage.Name).GetRequiredService<TagHelperResolver>();
return (await resolver.GetTagHelpersAsync(snapshot)).Descriptors;
}
}
}

View File

@ -1,116 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Composition;
using System.Diagnostics;
using System.Threading.Tasks;
namespace Microsoft.CodeAnalysis.Razor.ProjectSystem
{
[Export(typeof(ProjectSnapshotChangeTrigger))]
internal class WorkspaceProjectSnapshotChangeTrigger : ProjectSnapshotChangeTrigger
{
private ProjectSnapshotManagerBase _projectManager;
public int ProjectChangeDelay { get; set; } = 3 * 1000;
// We throttle updates to projects to prevent doing too much work while the projects
// are being initialized.
//
// Internal for testing
internal Dictionary<ProjectId, Task> _deferredUpdates;
public override void Initialize(ProjectSnapshotManagerBase projectManager)
{
_projectManager = projectManager;
_projectManager.Workspace.WorkspaceChanged += Workspace_WorkspaceChanged;
_deferredUpdates = new Dictionary<ProjectId, Task>();
InitializeSolution(_projectManager.Workspace.CurrentSolution);
}
private void InitializeSolution(Solution solution)
{
Debug.Assert(solution != null);
foreach (var project in solution.Projects)
{
_projectManager.WorkspaceProjectAdded(project);
}
}
// Internal for testing
internal void Workspace_WorkspaceChanged(object sender, WorkspaceChangeEventArgs e)
{
Project project;
switch (e.Kind)
{
case WorkspaceChangeKind.ProjectAdded:
{
project = e.NewSolution.GetProject(e.ProjectId);
Debug.Assert(project != null);
_projectManager.WorkspaceProjectAdded(project);
break;
}
case WorkspaceChangeKind.ProjectChanged:
case WorkspaceChangeKind.ProjectReloaded:
{
EnqueueUpdate(e.ProjectId);
break;
}
case WorkspaceChangeKind.ProjectRemoved:
{
project = e.OldSolution.GetProject(e.ProjectId);
Debug.Assert(project != null);
_projectManager.WorkspaceProjectRemoved(project);
break;
}
case WorkspaceChangeKind.SolutionAdded:
case WorkspaceChangeKind.SolutionChanged:
case WorkspaceChangeKind.SolutionCleared:
case WorkspaceChangeKind.SolutionReloaded:
case WorkspaceChangeKind.SolutionRemoved:
if (e.OldSolution != null)
{
foreach (var p in e.OldSolution.Projects)
{
_projectManager.WorkspaceProjectRemoved(p);
}
}
InitializeSolution(e.NewSolution);
break;
}
}
private void EnqueueUpdate(ProjectId projectId)
{
// A race is not possible here because we use the main thread to synchronize the updates
// by capturing the sync context.
if (!_deferredUpdates.TryGetValue(projectId, out var update) || update.IsCompleted)
{
_deferredUpdates[projectId] = UpdateAfterDelay(projectId);
}
}
private async Task UpdateAfterDelay(ProjectId projectId)
{
await Task.Delay(ProjectChangeDelay);
var solution = _projectManager.Workspace.CurrentSolution;
var workspaceProject = solution.GetProject(projectId);
if (workspaceProject != null)
{
_projectManager.WorkspaceProjectChanged(workspaceProject);
}
}
}
}

View File

@ -1,19 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.LiveShare.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.LiveShare.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Razor.Performance, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Mac.RazorAddin, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Remote.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor.Test.Common, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Mac.LanguageServices.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Mac.LanguageServices.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.LanguageServices.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.LanguageServices.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.RazorExtension, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

View File

@ -1,86 +0,0 @@
// <auto-generated />
namespace Microsoft.CodeAnalysis.Razor.Workspaces
{
using System.Globalization;
using System.Reflection;
using System.Resources;
internal static class Resources
{
private static readonly ResourceManager _resourceManager
= new ResourceManager("Microsoft.CodeAnalysis.Razor.Workspaces.Resources", typeof(Resources).GetTypeInfo().Assembly);
/// <summary>
/// Value cannot be null or an empty string.
/// </summary>
internal static string ArgumentCannotBeNullOrEmpty
{
get => GetString("ArgumentCannotBeNullOrEmpty");
}
/// <summary>
/// Value cannot be null or an empty string.
/// </summary>
internal static string FormatArgumentCannotBeNullOrEmpty()
=> GetString("ArgumentCannotBeNullOrEmpty");
/// <summary>
/// {0} must be called on a background thread.
/// </summary>
internal static string ForegroundDispatcher_AssertBackgroundThread
{
get => GetString("ForegroundDispatcher_AssertBackgroundThread");
}
/// <summary>
/// {0} must be called on a background thread.
/// </summary>
internal static string FormatForegroundDispatcher_AssertBackgroundThread(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("ForegroundDispatcher_AssertBackgroundThread"), p0);
/// <summary>
/// {0} must be called on the foreground thread.
/// </summary>
internal static string ForegroundDispatcher_AssertForegroundThread
{
get => GetString("ForegroundDispatcher_AssertForegroundThread");
}
/// <summary>
/// {0} must be called on the foreground thread.
/// </summary>
internal static string FormatForegroundDispatcher_AssertForegroundThread(object p0)
=> string.Format(CultureInfo.CurrentCulture, GetString("ForegroundDispatcher_AssertForegroundThread"), p0);
/// <summary>
/// The method
/// </summary>
internal static string ForegroundDispatcher_NoMethodNamePlaceholder
{
get => GetString("ForegroundDispatcher_NoMethodNamePlaceholder");
}
/// <summary>
/// The method
/// </summary>
internal static string FormatForegroundDispatcher_NoMethodNamePlaceholder()
=> GetString("ForegroundDispatcher_NoMethodNamePlaceholder");
private static string GetString(string name, params string[] formatterNames)
{
var value = _resourceManager.GetString(name);
System.Diagnostics.Debug.Assert(value != null);
if (formatterNames != null)
{
for (var i = 0; i < formatterNames.Length; i++)
{
value = value.Replace("{" + formatterNames[i] + "}", "{" + i + "}");
}
}
return value;
}
}
}

View File

@ -1,132 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<data name="ArgumentCannotBeNullOrEmpty" xml:space="preserve">
<value>Value cannot be null or an empty string.</value>
</data>
<data name="ForegroundDispatcher_AssertBackgroundThread" xml:space="preserve">
<value>{0} must be called on a background thread.</value>
</data>
<data name="ForegroundDispatcher_AssertForegroundThread" xml:space="preserve">
<value>{0} must be called on the foreground thread.</value>
</data>
<data name="ForegroundDispatcher_NoMethodNamePlaceholder" xml:space="preserve">
<value>The method</value>
</data>
</root>

View File

@ -1,23 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.CodeAnalysis.Text
{
internal static class SourceTextExtensions
{
public static RazorSourceDocument GetRazorSourceDocument(this SourceText sourceText, string fileName)
{
if (sourceText == null)
{
throw new ArgumentNullException(nameof(sourceText));
}
var content = sourceText.ToString();
return RazorSourceDocument.Create(content, fileName);
}
}
}

View File

@ -1,24 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.CodeAnalysis.Razor
{
public sealed class TagHelperResolutionResult
{
internal static TagHelperResolutionResult Empty = new TagHelperResolutionResult(Array.Empty<TagHelperDescriptor>(), Array.Empty<RazorDiagnostic>());
public TagHelperResolutionResult(IReadOnlyList<TagHelperDescriptor> descriptors, IReadOnlyList<RazorDiagnostic> diagnostics)
{
Descriptors = descriptors;
Diagnostics = diagnostics;
}
public IReadOnlyList<TagHelperDescriptor> Descriptors { get; }
public IReadOnlyList<RazorDiagnostic> Diagnostics { get; }
}
}

View File

@ -1,62 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Razor
{
internal abstract class TagHelperResolver : ILanguageService
{
public abstract Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, CancellationToken cancellationToken = default);
protected virtual async Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, RazorProjectEngine engine)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
if (engine == null)
{
throw new ArgumentNullException(nameof(engine));
}
if (project.WorkspaceProject == null)
{
return TagHelperResolutionResult.Empty;
}
var providers = engine.Engine.Features.OfType<ITagHelperDescriptorProvider>().ToArray();
if (providers.Length == 0)
{
return TagHelperResolutionResult.Empty;
}
var results = new List<TagHelperDescriptor>();
var context = TagHelperDescriptorProviderContext.Create(results);
context.ExcludeHidden = true;
context.IncludeDocumentation = true;
var compilation = await project.WorkspaceProject.GetCompilationAsync().ConfigureAwait(false);
if (CompilationTagHelperFeature.IsValidCompilation(compilation))
{
context.SetCompilation(compilation);
}
for (var i = 0; i < providers.Length; i++)
{
var provider = providers[i];
provider.Execute(context);
}
return new TagHelperResolutionResult(results, Array.Empty<RazorDiagnostic>());
}
}
}

View File

@ -7,10 +7,4 @@ using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.LiveShare.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.Mvc.Razor.Extensions.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Razor.Workspaces.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Remote.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.Editor.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.LanguageServices.Razor, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("Microsoft.VisualStudio.RazorExtension, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

View File

@ -1,28 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<Description>Razor is a markup syntax for adding server-side logic to web pages. This package contains the Razor design-time infrastructure.</Description>
<TargetFrameworks>net46</TargetFrameworks>
<EnableApiCheck>false</EnableApiCheck>
</PropertyGroup>
<ItemGroup>
<Compile Include="..\Microsoft.VisualStudio.LanguageServices.Razor\Serialization\*.cs">
<Link>Serialization\%(FileName)%(Extension)</Link>
</Compile>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Microsoft.CodeAnalysis.Razor.Workspaces\Microsoft.CodeAnalysis.Razor.Workspaces.csproj" />
<ProjectReference Include="..\Microsoft.AspNetCore.Razor.Language\Microsoft.AspNetCore.Razor.Language.csproj" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Microsoft.CodeAnalysis.CSharp" Version="$(VSIX_MicrosoftCodeAnalysisCSharpPackageVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.Common" Version="$(VSIX_MicrosoftCodeAnalysisCommonPackageVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.Remote.Razor.ServiceHub" Version="$(VSIX_MicrosoftCodeAnalysisRemoteRazorServiceHubPackageVersion)" />
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="$(VSIX_MicrosoftCodeAnalysisWorkspacesCommonPackageVersion)" />
<PackageReference Include="StreamJsonRpc" Version="$(StreamJsonRpcPackageVersion)" />
</ItemGroup>
</Project>

View File

@ -1,7 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Microsoft.CodeAnalysis.Remote.Razor.Test, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
[assembly: InternalsVisibleTo("DynamicProxyGenAssembly2, PublicKey=0024000004800000940000000602000000240000525341310004000001000100c547cac37abd99c8db225ef2f6c8a3602f3b3606cc9891605d02baa56104f4cfc0734aa39b93bf7852f7d9266654753cc297e7d2edfe0bac1cdcf9f717241550e0a7b191195b7667bb4f64bcb8e2121380fd1d9d46ad2d92d2d15605093924cceaf74c4861eff62abf69b9291ed0a340e113be11e6a7d3113e92484cf7045cc7")]

View File

@ -1,27 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Remote.Razor
{
internal class RazorLanguageService : RazorServiceBase
{
public RazorLanguageService(Stream stream, IServiceProvider serviceProvider)
: base(stream, serviceProvider)
{
}
public async Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshotHandle projectHandle, string factoryTypeName, CancellationToken cancellationToken = default)
{
var project = await GetProjectSnapshotAsync(projectHandle, cancellationToken).ConfigureAwait(false);
return await RazorServices.TagHelperResolver.GetTagHelpersAsync(project, factoryTypeName, cancellationToken);
}
}
}

View File

@ -1,95 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.IO;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Remote.Razor
{
internal abstract class RazorServiceBase : ServiceHubServiceBase
{
public RazorServiceBase(Stream stream, IServiceProvider serviceProvider)
: base(serviceProvider, stream)
{
RazorServices = new RazorServices();
Rpc.JsonSerializer.Converters.RegisterRazorConverters();
// Due to this issue - https://github.com/dotnet/roslyn/issues/16900#issuecomment-277378950
// We need to manually start the RPC connection. Otherwise we'd be opting ourselves into
// race condition prone call paths.
Rpc.StartListening();
}
protected RazorServices RazorServices { get; }
protected virtual async Task<ProjectSnapshot> GetProjectSnapshotAsync(ProjectSnapshotHandle projectHandle, CancellationToken cancellationToken)
{
if (projectHandle == null)
{
throw new ArgumentNullException(nameof(projectHandle));
}
var solution = await GetSolutionAsync(cancellationToken).ConfigureAwait(false);
var workspaceProject = solution.GetProject(projectHandle.WorkspaceProjectId);
return new SerializedProjectSnapshot(projectHandle.FilePath, projectHandle.Configuration, workspaceProject);
}
private class SerializedProjectSnapshot : ProjectSnapshot
{
public SerializedProjectSnapshot(string filePath, RazorConfiguration configuration, Project workspaceProject)
{
FilePath = filePath;
Configuration = configuration;
WorkspaceProject = workspaceProject;
IsInitialized = true;
Version = VersionStamp.Default;
}
public override RazorConfiguration Configuration { get; }
public override IEnumerable<string> DocumentFilePaths => Array.Empty<string>();
public override string FilePath { get; }
public override bool IsInitialized { get; }
public override VersionStamp Version { get; }
public override Project WorkspaceProject { get; }
public override DocumentSnapshot GetDocument(string filePath)
{
if (filePath == null)
{
throw new ArgumentNullException(nameof(filePath));
}
return null;
}
public override RazorProjectEngine GetProjectEngine()
{
throw new NotImplementedException();
}
public override Task<IReadOnlyList<TagHelperDescriptor>> GetTagHelpersAsync()
{
throw new NotImplementedException();
}
public override bool TryGetTagHelpers(out IReadOnlyList<TagHelperDescriptor> result)
{
throw new NotImplementedException();
}
}
}
}

View File

@ -1,22 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.CodeAnalysis.Razor
{
// Provides access to Razor language and workspace services that are avialable in the OOP host.
//
// Since we don't have access to the workspace we only have access to some specific things
// that we can construct directly.
internal class RazorServices
{
public RazorServices()
{
FallbackProjectEngineFactory = new FallbackProjectEngineFactory();
TagHelperResolver = new RemoteTagHelperResolver(FallbackProjectEngineFactory);
}
public IFallbackProjectEngineFactory FallbackProjectEngineFactory { get; }
public RemoteTagHelperResolver TagHelperResolver { get; }
}
}

View File

@ -1,80 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor.ProjectSystem;
namespace Microsoft.CodeAnalysis.Razor
{
internal class RemoteTagHelperResolver : TagHelperResolver
{
private readonly static RazorConfiguration DefaultConfiguration = FallbackRazorConfiguration.MVC_2_0;
private readonly IFallbackProjectEngineFactory _fallbackFactory;
public RemoteTagHelperResolver(IFallbackProjectEngineFactory fallbackFactory)
{
if (fallbackFactory == null)
{
throw new ArgumentNullException(nameof(fallbackFactory));
}
_fallbackFactory = fallbackFactory;
}
public override Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, CancellationToken cancellationToken = default)
{
throw new NotImplementedException();
}
public Task<TagHelperResolutionResult> GetTagHelpersAsync(ProjectSnapshot project, string factoryTypeName, CancellationToken cancellationToken = default)
{
if (project == null)
{
throw new ArgumentNullException(nameof(project));
}
if (project.Configuration == null || project.WorkspaceProject == null)
{
return Task.FromResult(TagHelperResolutionResult.Empty);
}
var engine = CreateProjectEngine(project, factoryTypeName);
return GetTagHelpersAsync(project, engine);
}
internal RazorProjectEngine CreateProjectEngine(ProjectSnapshot project, string factoryTypeName)
{
// This section is really similar to the code DefaultProjectEngineFactoryService
// but with a few differences that are significant in the remote scenario
//
// Most notably, we are going to find the Tag Helpers using a compilation, and we have
// no editor settings.
//
// The default configuration currently matches MVC-2.0. Beyond MVC-2.0 we added SDK support for
// properly detecting project versions, so that's a good version to assume when we can't find a
// configuration.
var configuration = project?.Configuration ?? DefaultConfiguration;
// If there's no factory to handle the configuration then fall back to a very basic configuration.
//
// This will stop a crash from happening in this case (misconfigured project), but will still make
// it obvious to the user that something is wrong.
var factory = CreateFactory(configuration, factoryTypeName) ?? _fallbackFactory;
return factory.Create(configuration, RazorProjectFileSystem.Empty, b => { });
}
private IProjectEngineFactory CreateFactory(RazorConfiguration configuration, string factoryTypeName)
{
if (factoryTypeName == null)
{
return null;
}
return (IProjectEngineFactory)Activator.CreateInstance(Type.GetType(factoryTypeName, throwOnError: true));
}
}
}

View File

@ -1,22 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.VisualStudio.Editor.Razor
{
[Flags]
public enum AcceptedCharacters
{
None = 0,
NewLine = 1,
WhiteSpace = 2,
NonWhiteSpace = 4,
AllWhiteSpace = NewLine | WhiteSpace,
Any = AllWhiteSpace | NonWhiteSpace,
AnyExceptNewline = NonWhiteSpace | WhiteSpace
}
}

View File

@ -1,73 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.VisualStudio.Editor.Razor
{
public class AttributeCompletionContext
{
public AttributeCompletionContext(
TagHelperDocumentContext documentContext,
IEnumerable<string> existingCompletions,
string currentTagName,
string currentAttributeName,
IEnumerable<KeyValuePair<string, string>> attributes,
string currentParentTagName,
bool currentParentIsTagHelper,
Func<string, bool> inHTMLSchema)
{
if (documentContext == null)
{
throw new ArgumentNullException(nameof(documentContext));
}
if (existingCompletions == null)
{
throw new ArgumentNullException(nameof(existingCompletions));
}
if (currentTagName == null)
{
throw new ArgumentNullException(nameof(currentTagName));
}
if (attributes == null)
{
throw new ArgumentNullException(nameof(attributes));
}
if (inHTMLSchema == null)
{
throw new ArgumentNullException(nameof(inHTMLSchema));
}
DocumentContext = documentContext;
ExistingCompletions = existingCompletions;
CurrentTagName = currentTagName;
CurrentAttributeName = currentAttributeName;
Attributes = attributes;
CurrentParentTagName = currentParentTagName;
CurrentParentIsTagHelper = currentParentIsTagHelper;
InHTMLSchema = inHTMLSchema;
}
public TagHelperDocumentContext DocumentContext { get; }
public IEnumerable<string> ExistingCompletions { get; }
public string CurrentTagName { get; }
public string CurrentAttributeName { get; }
public IEnumerable<KeyValuePair<string, string>> Attributes { get; }
public string CurrentParentTagName { get; }
public bool CurrentParentIsTagHelper { get; }
public Func<string, bool> InHTMLSchema { get; }
}
}

View File

@ -1,41 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System.Collections.Generic;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.VisualStudio.Editor.Razor
{
public abstract class AttributeCompletionResult
{
private AttributeCompletionResult()
{
}
public abstract IReadOnlyDictionary<string, IEnumerable<BoundAttributeDescriptor>> Completions { get; }
internal static AttributeCompletionResult Create(Dictionary<string, HashSet<BoundAttributeDescriptor>> completions)
{
var readonlyCompletions = completions.ToDictionary(
key => key.Key,
value => (IEnumerable<BoundAttributeDescriptor>)value.Value,
completions.Comparer);
var result = new DefaultAttributeCompletionResult(readonlyCompletions);
return result;
}
private class DefaultAttributeCompletionResult : AttributeCompletionResult
{
private readonly IReadOnlyDictionary<string, IEnumerable<BoundAttributeDescriptor>> _completions;
public DefaultAttributeCompletionResult(IReadOnlyDictionary<string, IEnumerable<BoundAttributeDescriptor>> completions)
{
_completions = completions;
}
public override IReadOnlyDictionary<string, IEnumerable<BoundAttributeDescriptor>> Completions => _completions;
}
}
}

View File

@ -1,403 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.VisualStudio.Text;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal class BackgroundParser : IDisposable
{
private MainThreadState _main;
private BackgroundThread _bg;
public BackgroundParser(RazorProjectEngine projectEngine, string filePath, string projectDirectory)
{
_main = new MainThreadState(filePath);
_bg = new BackgroundThread(_main, projectEngine, filePath, projectDirectory);
_main.ResultsReady += (sender, args) => OnResultsReady(args);
}
/// <summary>
/// Fired on the main thread.
/// </summary>
public event EventHandler<BackgroundParserResultsReadyEventArgs> ResultsReady;
public bool IsIdle
{
get { return _main.IsIdle; }
}
public void Start()
{
_bg.Start();
}
public void Cancel()
{
_main.Cancel();
}
public ChangeReference QueueChange(SourceChange change, ITextSnapshot snapshot)
{
var changeReference = new ChangeReference(change, snapshot);
_main.QueueChange(changeReference);
return changeReference;
}
public void Dispose()
{
_main.Cancel();
}
public IDisposable SynchronizeMainThreadState()
{
return _main.Lock();
}
protected virtual void OnResultsReady(BackgroundParserResultsReadyEventArgs args)
{
using (SynchronizeMainThreadState())
{
ResultsReady?.Invoke(this, args);
}
}
private abstract class ThreadStateBase
{
#if DEBUG
private int _id = -1;
#endif
protected ThreadStateBase()
{
}
[Conditional("DEBUG")]
protected void SetThreadId(int id)
{
#if DEBUG
_id = id;
#endif
}
[Conditional("DEBUG")]
protected void EnsureOnThread()
{
#if DEBUG
Debug.Assert(_id != -1, "SetThreadId was never called!");
Debug.Assert(Thread.CurrentThread.ManagedThreadId == _id, "Called from an unexpected thread!");
#endif
}
[Conditional("DEBUG")]
protected void EnsureNotOnThread()
{
#if DEBUG
Debug.Assert(_id != -1, "SetThreadId was never called!");
Debug.Assert(Thread.CurrentThread.ManagedThreadId != _id, "Called from an unexpected thread!");
#endif
}
}
private class MainThreadState : ThreadStateBase, IDisposable
{
private readonly CancellationTokenSource _cancelSource = new CancellationTokenSource();
private readonly ManualResetEventSlim _hasParcel = new ManualResetEventSlim(false);
private CancellationTokenSource _currentParcelCancelSource;
private string _fileName;
private readonly object _stateLock = new object();
private IList<ChangeReference> _changes = new List<ChangeReference>();
public MainThreadState(string fileName)
{
_fileName = fileName;
SetThreadId(Thread.CurrentThread.ManagedThreadId);
}
public event EventHandler<BackgroundParserResultsReadyEventArgs> ResultsReady;
public CancellationToken CancelToken
{
get { return _cancelSource.Token; }
}
public bool IsIdle
{
get
{
lock (_stateLock)
{
return _currentParcelCancelSource == null;
}
}
}
public void Cancel()
{
EnsureOnThread();
_cancelSource.Cancel();
}
public IDisposable Lock()
{
Monitor.Enter(_stateLock);
return new DisposableAction(() => Monitor.Exit(_stateLock));
}
public void QueueChange(ChangeReference change)
{
// Any thread can queue a change.
lock (_stateLock)
{
// CurrentParcel token source is not null ==> There's a parse underway
if (_currentParcelCancelSource != null)
{
_currentParcelCancelSource.Cancel();
}
_changes.Add(change);
_hasParcel.Set();
}
}
public WorkParcel GetParcel()
{
EnsureNotOnThread(); // Only the background thread can get a parcel
_hasParcel.Wait(_cancelSource.Token);
_hasParcel.Reset();
lock (_stateLock)
{
// Create a cancellation source for this parcel
_currentParcelCancelSource = new CancellationTokenSource();
var changes = _changes;
_changes = new List<ChangeReference>();
return new WorkParcel(changes, _currentParcelCancelSource.Token);
}
}
public void ReturnParcel(BackgroundParserResultsReadyEventArgs args)
{
lock (_stateLock)
{
// Clear the current parcel cancellation source
if (_currentParcelCancelSource != null)
{
_currentParcelCancelSource.Dispose();
_currentParcelCancelSource = null;
}
// If there are things waiting to be parsed, just don't fire the event because we're already out of date
if (_changes.Any())
{
return;
}
}
var handler = ResultsReady;
if (handler != null)
{
handler(this, args);
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
if (_currentParcelCancelSource != null)
{
_currentParcelCancelSource.Dispose();
_currentParcelCancelSource = null;
}
_cancelSource.Dispose();
_hasParcel.Dispose();
}
}
}
private class BackgroundThread : ThreadStateBase
{
private readonly string _filePath;
private readonly string _relativeFilePath;
private readonly string _projectDirectory;
private MainThreadState _main;
private Thread _backgroundThread;
private CancellationToken _shutdownToken;
private RazorProjectEngine _projectEngine;
private RazorSyntaxTree _currentSyntaxTree;
private IList<ChangeReference> _previouslyDiscarded = new List<ChangeReference>();
public BackgroundThread(MainThreadState main, RazorProjectEngine projectEngine, string filePath, string projectDirectory)
{
// Run on MAIN thread!
_main = main;
_shutdownToken = _main.CancelToken;
_projectEngine = projectEngine;
_filePath = filePath;
_relativeFilePath = GetNormalizedRelativeFilePath(filePath, projectDirectory);
_projectDirectory = projectDirectory;
_backgroundThread = new Thread(WorkerLoop);
SetThreadId(_backgroundThread.ManagedThreadId);
}
// **** ANY THREAD ****
public void Start()
{
_backgroundThread.Start();
}
// **** BACKGROUND THREAD ****
private void WorkerLoop()
{
try
{
EnsureOnThread();
while (!_shutdownToken.IsCancellationRequested)
{
// Grab the parcel of work to do
var parcel = _main.GetParcel();
if (parcel.Changes.Any())
{
try
{
BackgroundParserResultsReadyEventArgs args = null;
using (var linkedCancel = CancellationTokenSource.CreateLinkedTokenSource(_shutdownToken, parcel.CancelToken))
{
if (!linkedCancel.IsCancellationRequested)
{
// Collect ALL changes
List<ChangeReference> allChanges;
if (_previouslyDiscarded != null)
{
allChanges = Enumerable.Concat(_previouslyDiscarded, parcel.Changes).ToList();
}
else
{
allChanges = parcel.Changes.ToList();
}
var finalChange = allChanges.Last();
var results = ParseChange(finalChange.Snapshot, linkedCancel.Token);
if (results != null && !linkedCancel.IsCancellationRequested)
{
// Clear discarded changes list
_previouslyDiscarded = null;
_currentSyntaxTree = results.GetSyntaxTree();
// Build Arguments
args = new BackgroundParserResultsReadyEventArgs(finalChange, results);
}
else
{
// Parse completed but we were cancelled in the mean time. Add these to the discarded changes set
_previouslyDiscarded = allChanges;
}
}
}
if (args != null)
{
_main.ReturnParcel(args);
}
}
catch (OperationCanceledException)
{
}
}
else
{
Thread.Yield();
}
}
}
catch (OperationCanceledException)
{
// Do nothing. Just shut down.
}
finally
{
// Clean up main thread resources
_main.Dispose();
}
}
private RazorCodeDocument ParseChange(ITextSnapshot snapshot, CancellationToken token)
{
EnsureOnThread();
var projectItem = new TextSnapshotProjectItem(snapshot, _projectDirectory, _relativeFilePath, _filePath);
var codeDocument = _projectEngine.ProcessDesignTime(projectItem);
return codeDocument;
}
private string GetNormalizedRelativeFilePath(string filePath, string projectDirectory)
{
if (filePath.StartsWith(projectDirectory, StringComparison.OrdinalIgnoreCase))
{
filePath = filePath.Substring(projectDirectory.Length);
}
if (filePath.Length > 1)
{
filePath = filePath.Replace('\\', '/');
if (filePath[0] != '/')
{
filePath = "/" + filePath;
}
}
return filePath;
}
}
private class WorkParcel
{
public WorkParcel(IList<ChangeReference> changes, CancellationToken cancelToken)
{
Changes = changes;
CancelToken = cancelToken;
}
public CancellationToken CancelToken { get; }
public IList<ChangeReference> Changes { get; }
}
internal class ChangeReference
{
public ChangeReference(SourceChange change, ITextSnapshot snapshot)
{
Change = change;
Snapshot = snapshot;
}
public SourceChange Change { get; }
public ITextSnapshot Snapshot { get; }
}
}
}

View File

@ -1,22 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.AspNetCore.Razor.Language;
using static Microsoft.VisualStudio.Editor.Razor.BackgroundParser;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal class BackgroundParserResultsReadyEventArgs : EventArgs
{
public BackgroundParserResultsReadyEventArgs(ChangeReference edit, RazorCodeDocument codeDocument)
{
ChangeReference = edit;
CodeDocument = codeDocument;
}
public ChangeReference ChangeReference { get; }
public RazorCodeDocument CodeDocument { get; }
}
}

View File

@ -1,26 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.VisualStudio.Editor.Razor
{
public enum BlockKind
{
// Code
Statement,
Directive,
Functions,
Expression,
Helper,
// Markup
Markup,
Section,
Template,
// Special
Comment,
Tag,
HtmlComment
}
}

View File

@ -1,350 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Text;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.AspNetCore.Razor.Language.Legacy;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
using Microsoft.VisualStudio.Text.Operations;
using ITextBuffer = Microsoft.VisualStudio.Text.ITextBuffer;
using Span = Microsoft.AspNetCore.Razor.Language.Legacy.Span;
namespace Microsoft.VisualStudio.Editor.Razor
{
/// <summary>
/// This class is responsible for handling situations where Roslyn and the HTML editor cannot auto-indent Razor code.
/// </summary>
/// <example>
/// Attempting to insert a newline (pipe indicates the cursor):
/// @{ |}
/// Should result in the text buffer looking like the following:
/// @{
/// |
/// }
/// This is also true for directive block scenarios.
/// </example>
internal class BraceSmartIndenter : IDisposable
{
private readonly ForegroundDispatcher _dispatcher;
private readonly ITextBuffer _textBuffer;
private readonly VisualStudioDocumentTracker _documentTracker;
private readonly TextBufferCodeDocumentProvider _codeDocumentProvider;
private readonly IEditorOperationsFactoryService _editorOperationsFactory;
private readonly StringBuilder _indentBuilder = new StringBuilder();
private BraceIndentationContext _context;
// Internal for testing
internal BraceSmartIndenter()
{
}
public BraceSmartIndenter(
ForegroundDispatcher dispatcher,
VisualStudioDocumentTracker documentTracker,
TextBufferCodeDocumentProvider codeDocumentProvider,
IEditorOperationsFactoryService editorOperationsFactory)
{
if (dispatcher == null)
{
throw new ArgumentNullException(nameof(dispatcher));
}
if (documentTracker == null)
{
throw new ArgumentNullException(nameof(documentTracker));
}
if (codeDocumentProvider == null)
{
throw new ArgumentNullException(nameof(codeDocumentProvider));
}
if (editorOperationsFactory == null)
{
throw new ArgumentNullException(nameof(editorOperationsFactory));
}
_dispatcher = dispatcher;
_documentTracker = documentTracker;
_codeDocumentProvider = codeDocumentProvider;
_editorOperationsFactory = editorOperationsFactory;
_textBuffer = _documentTracker.TextBuffer;
_textBuffer.Changed += TextBuffer_OnChanged;
_textBuffer.PostChanged += TextBuffer_OnPostChanged;
}
public void Dispose()
{
_dispatcher.AssertForegroundThread();
_textBuffer.Changed -= TextBuffer_OnChanged;
_textBuffer.PostChanged -= TextBuffer_OnPostChanged;
}
// Internal for testing
internal void TriggerSmartIndent(ITextView textView)
{
// This forces the smart indent. For example attempting to enter a newline between the functions directive:
// @functions {} will not auto-indent in between the braces unless we forcefully move to end of line.
var editorOperations = _editorOperationsFactory.GetEditorOperations(textView);
editorOperations.MoveToEndOfLine(false);
}
// Internal for testing
internal void TextBuffer_OnChanged(object sender, TextContentChangedEventArgs args)
{
_dispatcher.AssertForegroundThread();
if (!args.TextChangeOccurred(out var changeInformation))
{
return;
}
var newText = changeInformation.newText;
if (!_codeDocumentProvider.TryGetFromBuffer(_documentTracker.TextBuffer, out var codeDocument))
{
// Parse not available.
return;
}
var syntaxTree = codeDocument.GetSyntaxTree();
if (TryCreateIndentationContext(changeInformation.firstChange.NewPosition, newText.Length, newText, syntaxTree, _documentTracker, out var context))
{
_context = context;
}
}
private void TextBuffer_OnPostChanged(object sender, EventArgs e)
{
_dispatcher.AssertForegroundThread();
var context = _context;
_context = null;
if (context != null)
{
// Save the current caret position
var textView = context.FocusedTextView;
var caret = textView.Caret.Position.BufferPosition;
var textViewBuffer = textView.TextBuffer;
var indent = CalculateIndent(textViewBuffer, context.ChangePosition);
// Current state, pipe is cursor:
// @{
// |}
// Insert the completion text, i.e. "\r\n "
InsertIndent(caret.Position, indent, textViewBuffer);
// @{
//
// |}
// Place the caret inbetween the braces (before our indent).
RestoreCaretTo(caret.Position, textView);
// @{
// |
// }
// For Razor metacode cases the editor's smart indent wont kick in automatically.
TriggerSmartIndent(textView);
// @{
// |
// }
}
}
private string CalculateIndent(ITextBuffer buffer, int from)
{
// Get the line text of the block start
var currentSnapshotPoint = new SnapshotPoint(buffer.CurrentSnapshot, from);
var line = buffer.CurrentSnapshot.GetLineFromPosition(currentSnapshotPoint);
var lineText = line.GetText();
// Gather up the indent from the start block
_indentBuilder.Append(line.GetLineBreakText());
foreach (var ch in lineText)
{
if (!char.IsWhiteSpace(ch))
{
break;
}
_indentBuilder.Append(ch);
}
var indent = _indentBuilder.ToString();
_indentBuilder.Clear();
return indent;
}
// Internal for testing
internal static void InsertIndent(int insertLocation, string indent, ITextBuffer textBuffer)
{
var edit = textBuffer.CreateEdit();
edit.Insert(insertLocation, indent);
edit.Apply();
}
// Internal for testing
internal static void RestoreCaretTo(int caretPosition, ITextView textView)
{
var currentSnapshotPoint = new SnapshotPoint(textView.TextBuffer.CurrentSnapshot, caretPosition);
textView.Caret.MoveTo(currentSnapshotPoint);
}
// Internal for testing
internal static bool TryCreateIndentationContext(
int changePosition,
int changeLength,
string finalText,
RazorSyntaxTree syntaxTree,
VisualStudioDocumentTracker documentTracker,
out BraceIndentationContext context)
{
var focusedTextView = documentTracker.GetFocusedTextView();
if (focusedTextView != null && ParserHelpers.IsNewLine(finalText))
{
if (!AtApplicableRazorBlock(changePosition, syntaxTree))
{
context = null;
return false;
}
var currentSnapshot = documentTracker.TextBuffer.CurrentSnapshot;
var preChangeLineSnapshot = currentSnapshot.GetLineFromPosition(changePosition);
// Handle the case where the \n comes through separately from the \r and the position
// on the line is beyond what the GetText call above gives back.
var linePosition = Math.Min(preChangeLineSnapshot.Length, changePosition - preChangeLineSnapshot.Start) - 1;
if (AfterOpeningBrace(linePosition, preChangeLineSnapshot))
{
var afterChangePosition = changePosition + changeLength;
var afterChangeLineSnapshot = currentSnapshot.GetLineFromPosition(afterChangePosition);
var afterChangeLinePosition = afterChangePosition - afterChangeLineSnapshot.Start;
if (BeforeClosingBrace(afterChangeLinePosition, afterChangeLineSnapshot))
{
context = new BraceIndentationContext(focusedTextView, changePosition);
return true;
}
}
}
context = null;
return false;
}
// Internal for testing
internal static bool AtApplicableRazorBlock(int changePosition, RazorSyntaxTree syntaxTree)
{
// Our goal here is to return true when we're acting on code blocks that have all
// whitespace content and are surrounded by metacode.
// Some examples:
// @functions { |}
// @section foo { |}
// @{ |}
var change = new SourceChange(changePosition, 0, string.Empty);
var owner = syntaxTree.Root.LocateOwner(change);
if (IsUnlinkedSpan(owner))
{
return false;
}
if (SurroundedByInvalidContent(owner))
{
return false;
}
if (ContainsInvalidContent(owner))
{
return false;
}
// Indentable content inside of a code block.
return true;
}
// Internal for testing
internal static bool ContainsInvalidContent(Span owner)
{
// We only support whitespace based content. Any non-whitespace content is an unkonwn to us
// in regards to indentation.
for (var i = 0; i < owner.Tokens.Count; i++)
{
if (!string.IsNullOrWhiteSpace(owner.Tokens[i].Content))
{
return true;
}
}
return false;
}
// Internal for testing
internal static bool IsUnlinkedSpan(Span owner)
{
return owner == null ||
owner.Next == null ||
owner.Previous == null;
}
// Internal for testing
internal static bool SurroundedByInvalidContent(Span owner)
{
return owner.Next.Kind != SpanKindInternal.MetaCode ||
owner.Previous.Kind != SpanKindInternal.MetaCode;
}
internal static bool BeforeClosingBrace(int linePosition, ITextSnapshotLine lineSnapshot)
{
var lineText = lineSnapshot.GetText();
for (; linePosition < lineSnapshot.Length; linePosition++)
{
if (!char.IsWhiteSpace(lineText[linePosition]))
{
break;
}
}
var beforeClosingBrace = linePosition < lineSnapshot.Length && lineText[linePosition] == '}';
return beforeClosingBrace;
}
internal static bool AfterOpeningBrace(int linePosition, ITextSnapshotLine lineSnapshot)
{
var lineText = lineSnapshot.GetText();
for (; linePosition >= 0; linePosition--)
{
if (!char.IsWhiteSpace(lineText[linePosition]))
{
break;
}
}
var afterClosingBrace = linePosition >= 0 && lineText[linePosition] == '{';
return afterClosingBrace;
}
internal class BraceIndentationContext
{
public BraceIndentationContext(ITextView focusedTextView, int changePosition)
{
FocusedTextView = focusedTextView;
ChangePosition = changePosition;
}
public ITextView FocusedTextView { get; }
public int ChangePosition { get; }
}
}
}

View File

@ -1,12 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.Host;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal abstract class BraceSmartIndenterFactory : ILanguageService
{
public abstract BraceSmartIndenter Create(VisualStudioDocumentTracker documentTracker);
}
}

View File

@ -1,22 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.ObjectModel;
using Microsoft.VisualStudio.Text.Projection;
namespace Microsoft.VisualStudio.Text
{
internal static class BufferGraphExtensions
{
public static Collection<ITextBuffer> GetRazorBuffers(this IBufferGraph bufferGraph)
{
if (bufferGraph == null)
{
throw new ArgumentNullException(nameof(bufferGraph));
}
return bufferGraph.GetTextBuffers(TextBufferExtensions.IsRazorBuffer);
}
}
}

View File

@ -1,29 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.AspNetCore.Razor.Language;
namespace Microsoft.VisualStudio.Editor.Razor
{
public struct ClassifiedSpan
{
public ClassifiedSpan(SourceSpan span, SourceSpan blockSpan, SpanKind spanKind, BlockKind blockKind, AcceptedCharacters acceptedCharacters)
{
Span = span;
BlockSpan = blockSpan;
SpanKind = spanKind;
BlockKind = blockKind;
AcceptedCharacters = acceptedCharacters;
}
public AcceptedCharacters AcceptedCharacters { get; }
public BlockKind BlockKind { get; }
public SourceSpan BlockSpan { get; }
public SourceSpan Span { get; }
public SpanKind SpanKind { get; }
}
}

View File

@ -1,17 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
namespace Microsoft.VisualStudio.Editor.Razor
{
public sealed class ContextChangeEventArgs : EventArgs
{
public ContextChangeEventArgs(ContextChangeKind kind)
{
Kind = kind;
}
public ContextChangeKind Kind { get; }
}
}

View File

@ -1,13 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
namespace Microsoft.VisualStudio.Editor.Razor
{
public enum ContextChangeKind
{
ProjectChanged,
EditorSettingsChanged,
TagHelpersChanged,
ImportsChanged,
}
}

View File

@ -1,55 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Text.Operations;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal class DefaultBraceSmartIndenterFactory : BraceSmartIndenterFactory
{
private readonly IEditorOperationsFactoryService _editorOperationsFactory;
private readonly ForegroundDispatcher _dispatcher;
private readonly TextBufferCodeDocumentProvider _codeDocumentProvider;
public DefaultBraceSmartIndenterFactory(
ForegroundDispatcher dispatcher,
TextBufferCodeDocumentProvider codeDocumentProvider,
IEditorOperationsFactoryService editorOperationsFactory)
{
if (dispatcher == null)
{
throw new ArgumentNullException(nameof(dispatcher));
}
if (codeDocumentProvider == null)
{
throw new ArgumentNullException(nameof(codeDocumentProvider));
}
if (editorOperationsFactory == null)
{
throw new ArgumentNullException(nameof(editorOperationsFactory));
}
_dispatcher = dispatcher;
_codeDocumentProvider = codeDocumentProvider;
_editorOperationsFactory = editorOperationsFactory;
}
public override BraceSmartIndenter Create(VisualStudioDocumentTracker documentTracker)
{
if (documentTracker == null)
{
throw new ArgumentNullException(nameof(documentTracker));
}
_dispatcher.AssertForegroundThread();
var braceSmartIndenter = new BraceSmartIndenter(_dispatcher, documentTracker, _codeDocumentProvider, _editorOperationsFactory);
return braceSmartIndenter;
}
}
}

View File

@ -1,57 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Text.Operations;
namespace Microsoft.VisualStudio.Editor.Razor
{
[Shared]
[ExportLanguageServiceFactory(typeof(BraceSmartIndenterFactory), RazorLanguage.Name, ServiceLayer.Default)]
internal class DefaultBraceSmartIndenterFactoryFactory : ILanguageServiceFactory
{
private readonly ForegroundDispatcher _foregroundDispatcher;
private readonly TextBufferCodeDocumentProvider _codeDocumentProvider;
private readonly IEditorOperationsFactoryService _editorOperationsFactory;
[ImportingConstructor]
public DefaultBraceSmartIndenterFactoryFactory(
ForegroundDispatcher foregroundDispatcher,
TextBufferCodeDocumentProvider codeDocumentProvider,
IEditorOperationsFactoryService editorOperationsFactory)
{
if (foregroundDispatcher == null)
{
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
if (codeDocumentProvider == null)
{
throw new ArgumentNullException(nameof(codeDocumentProvider));
}
if (editorOperationsFactory == null)
{
throw new ArgumentNullException(nameof(editorOperationsFactory));
}
_foregroundDispatcher = foregroundDispatcher;
_codeDocumentProvider = codeDocumentProvider;
_editorOperationsFactory = editorOperationsFactory;
}
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
if (languageServices == null)
{
throw new ArgumentNullException(nameof(languageServices));
}
return new DefaultBraceSmartIndenterFactory(_foregroundDispatcher, _codeDocumentProvider, _editorOperationsFactory);
}
}
}

View File

@ -1,62 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.ComponentModel.Composition;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.Razor;
namespace Microsoft.VisualStudio.Editor.Razor
{
[System.Composition.Shared]
[Export(typeof(RazorCodeDocumentProvider))]
internal class DefaultCodeDocumentProvider : RazorCodeDocumentProvider
{
private readonly RazorTextBufferProvider _bufferProvider;
private readonly TextBufferCodeDocumentProvider _codeDocumentProvider;
[ImportingConstructor]
public DefaultCodeDocumentProvider(
RazorTextBufferProvider bufferProvider,
TextBufferCodeDocumentProvider codeDocumentProvider)
{
if (bufferProvider == null)
{
throw new ArgumentNullException(nameof(bufferProvider));
}
if (codeDocumentProvider == null)
{
throw new ArgumentNullException(nameof(codeDocumentProvider));
}
_bufferProvider = bufferProvider;
_codeDocumentProvider = codeDocumentProvider;
}
public override bool TryGetFromDocument(TextDocument document, out RazorCodeDocument codeDocument)
{
if (document == null)
{
throw new ArgumentNullException(nameof(document));
}
if (!_bufferProvider.TryGetFromDocument(document, out var textBuffer))
{
// Could not find a Razor buffer associated with the document.
codeDocument = null;
return false;
}
if (_codeDocumentProvider.TryGetFromBuffer(textBuffer, out codeDocument))
{
return true;
}
// A Razor code document has not yet been associated with the buffer yet.
codeDocument = null;
return false;
}
}
}

View File

@ -1,67 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.CodeAnalysis.Razor.Editor;
namespace Microsoft.VisualStudio.Editor.Razor
{
[System.Composition.Shared]
[Export(typeof(EditorSettingsManager))]
internal class DefaultEditorSettingsManager : EditorSettingsManager
{
public override event EventHandler<EditorSettingsChangedEventArgs> Changed;
private readonly object SettingsAccessorLock = new object();
private readonly ForegroundDispatcher _foregroundDispatcher;
private EditorSettings _settings;
[ImportingConstructor]
public DefaultEditorSettingsManager(ForegroundDispatcher foregroundDispatcher)
{
_foregroundDispatcher = foregroundDispatcher;
_settings = EditorSettings.Default;
}
public override EditorSettings Current
{
get
{
lock (SettingsAccessorLock)
{
return _settings;
}
}
}
public override void Update(EditorSettings updatedSettings)
{
if (updatedSettings == null)
{
throw new ArgumentNullException(nameof(updatedSettings));
}
_foregroundDispatcher.AssertForegroundThread();
lock (SettingsAccessorLock)
{
if (!_settings.Equals(updatedSettings))
{
_settings = updatedSettings;
OnChanged();
}
}
}
private void OnChanged()
{
_foregroundDispatcher.AssertForegroundThread();
var args = new EditorSettingsChangedEventArgs(Current);
Changed?.Invoke(this, args);
}
}
}

View File

@ -1,161 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using Microsoft.AspNetCore.Razor.Language;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Editor.Razor.Documents;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal class DefaultImportDocumentManager : ImportDocumentManager
{
private readonly FileChangeTrackerFactory _fileChangeTrackerFactory;
private readonly ForegroundDispatcher _foregroundDispatcher;
private readonly ErrorReporter _errorReporter;
private readonly Dictionary<string, ImportTracker> _importTrackerCache;
public override event EventHandler<ImportChangedEventArgs> Changed;
public DefaultImportDocumentManager(
ForegroundDispatcher foregroundDispatcher,
ErrorReporter errorReporter,
FileChangeTrackerFactory fileChangeTrackerFactory)
{
if (foregroundDispatcher == null)
{
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
if (errorReporter == null)
{
throw new ArgumentNullException(nameof(errorReporter));
}
if (fileChangeTrackerFactory == null)
{
throw new ArgumentNullException(nameof(fileChangeTrackerFactory));
}
_foregroundDispatcher = foregroundDispatcher;
_errorReporter = errorReporter;
_fileChangeTrackerFactory = fileChangeTrackerFactory;
_importTrackerCache = new Dictionary<string, ImportTracker>(StringComparer.OrdinalIgnoreCase);
}
public override void OnSubscribed(VisualStudioDocumentTracker tracker)
{
if (tracker == null)
{
throw new ArgumentNullException(nameof(tracker));
}
_foregroundDispatcher.AssertForegroundThread();
var imports = GetImportItems(tracker);
foreach (var import in imports)
{
var importFilePath = import.PhysicalPath;
Debug.Assert(importFilePath != null);
if (!_importTrackerCache.TryGetValue(importFilePath, out var importTracker))
{
// First time seeing this import. Start tracking it.
var fileChangeTracker = _fileChangeTrackerFactory.Create(importFilePath);
importTracker = new ImportTracker(fileChangeTracker);
_importTrackerCache[importFilePath] = importTracker;
fileChangeTracker.Changed += FileChangeTracker_Changed;
fileChangeTracker.StartListening();
}
importTracker.AssociatedDocuments.Add(tracker.FilePath);
}
}
public override void OnUnsubscribed(VisualStudioDocumentTracker tracker)
{
if (tracker == null)
{
throw new ArgumentNullException(nameof(tracker));
}
_foregroundDispatcher.AssertForegroundThread();
var imports = GetImportItems(tracker);
foreach (var import in imports)
{
var importFilePath = import.PhysicalPath;
Debug.Assert(importFilePath != null);
if (_importTrackerCache.TryGetValue(importFilePath, out var importTracker))
{
importTracker.AssociatedDocuments.Remove(tracker.FilePath);
if (importTracker.AssociatedDocuments.Count == 0)
{
// There are no open documents that care about this import. We no longer need to track it.
importTracker.FileChangeTracker.StopListening();
_importTrackerCache.Remove(importFilePath);
}
}
}
}
private IEnumerable<RazorProjectItem> GetImportItems(VisualStudioDocumentTracker tracker)
{
var projectEngine = tracker.ProjectSnapshot.GetProjectEngine();
var trackerItem = projectEngine.FileSystem.GetItem(tracker.FilePath);
var importFeature = projectEngine.ProjectFeatures.OfType<IImportProjectFeature>().FirstOrDefault();
// There should always be an import feature unless someone has misconfigured their RazorProjectEngine.
// In that case once we attempt to parse the Razor file we'll explode and give the a user a decent
// error message; for now, lets just be extra protective and assume 0 imports to not give a bad error.
var importItems = importFeature?.GetImports(trackerItem) ?? Enumerable.Empty<RazorProjectItem>();
var physicalImports = importItems.Where(import => import.FilePath != null);
return physicalImports;
}
private void OnChanged(ImportTracker importTracker, FileChangeKind changeKind)
{
_foregroundDispatcher.AssertForegroundThread();
if (Changed == null)
{
return;
}
var args = new ImportChangedEventArgs(importTracker.FilePath, changeKind, importTracker.AssociatedDocuments);
Changed.Invoke(this, args);
}
private void FileChangeTracker_Changed(object sender, FileChangeEventArgs args)
{
_foregroundDispatcher.AssertForegroundThread();
if (_importTrackerCache.TryGetValue(args.FilePath, out var importTracker))
{
OnChanged(importTracker, args.Kind);
}
}
private class ImportTracker
{
public ImportTracker(FileChangeTracker fileChangeTracker)
{
FileChangeTracker = fileChangeTracker;
AssociatedDocuments = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
}
public string FilePath => FileChangeTracker.FilePath;
public FileChangeTracker FileChangeTracker { get; }
public HashSet<string> AssociatedDocuments { get; }
}
}
}

View File

@ -1,43 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Editor.Razor.Documents;
namespace Microsoft.VisualStudio.Editor.Razor
{
[Shared]
[ExportLanguageServiceFactory(typeof(ImportDocumentManager), RazorLanguage.Name, ServiceLayer.Default)]
internal class DefaultImportDocumentManagerFactory : ILanguageServiceFactory
{
private readonly ForegroundDispatcher _foregroundDispatcher;
[ImportingConstructor]
public DefaultImportDocumentManagerFactory(ForegroundDispatcher foregroundDispatcher)
{
if (foregroundDispatcher == null)
{
throw new ArgumentNullException(nameof(foregroundDispatcher));
}
_foregroundDispatcher = foregroundDispatcher;
}
public ILanguageService CreateLanguageService(HostLanguageServices languageServices)
{
if (languageServices == null)
{
throw new ArgumentNullException(nameof(languageServices));
}
var errorReporter = languageServices.WorkspaceServices.GetRequiredService<ErrorReporter>();
var fileChangeTrackerFactory = languageServices.WorkspaceServices.GetRequiredService<FileChangeTrackerFactory>();
return new DefaultImportDocumentManager(_foregroundDispatcher, errorReporter, fileChangeTrackerFactory);
}
}
}

View File

@ -1,41 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using Microsoft.VisualStudio.Text;
namespace Microsoft.VisualStudio.Editor.Razor
{
internal class DefaultProjectPathProvider : ProjectPathProvider
{
private readonly TextBufferProjectService _projectService;
public DefaultProjectPathProvider(TextBufferProjectService projectService)
{
if (projectService == null)
{
throw new ArgumentNullException(nameof(projectService));
}
_projectService = projectService;
}
public override bool TryGetProjectPath(ITextBuffer textBuffer, out string filePath)
{
if (textBuffer == null)
{
throw new ArgumentNullException(nameof(textBuffer));
}
var project = _projectService.GetHostProject(textBuffer);
if (project == null)
{
filePath = null;
return false;
}
filePath = _projectService.GetProjectPath(project);
return true;
}
}
}

View File

@ -1,38 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Composition;
using Microsoft.CodeAnalysis.Host;
using Microsoft.CodeAnalysis.Host.Mef;
namespace Microsoft.VisualStudio.Editor.Razor
{
[Shared]
[ExportWorkspaceServiceFactory(typeof(ProjectPathProvider), ServiceLayer.Default)]
internal class DefaultProjectPathProviderFactory : IWorkspaceServiceFactory
{
private readonly TextBufferProjectService _projectService;
[ImportingConstructor]
public DefaultProjectPathProviderFactory(TextBufferProjectService projectService)
{
if (projectService == null)
{
throw new ArgumentNullException(nameof(projectService));
}
_projectService = projectService;
}
public IWorkspaceService CreateService(HostWorkspaceServices workspaceServices)
{
if (workspaceServices == null)
{
throw new ArgumentNullException(nameof(workspaceServices));
}
return new DefaultProjectPathProvider(_projectService);
}
}
}

View File

@ -1,111 +0,0 @@
// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using System;
using System.Collections.Generic;
using System.ComponentModel.Composition;
using System.Diagnostics;
using Microsoft.CodeAnalysis.Razor;
using Microsoft.VisualStudio.Text;
using Microsoft.VisualStudio.Text.Editor;
namespace Microsoft.VisualStudio.Editor.Razor
{
[System.Composition.Shared]
[Export(typeof(RazorDocumentManager))]
internal class DefaultRazorDocumentManager : RazorDocumentManager
{
private readonly ForegroundDispatcher _foregroundDispatcher;
private readonly RazorEditorFactoryService _editorFactoryService;
[ImportingConstructor]
public DefaultRazorDocumentManager(
ForegroundDispatcher dispatcher,
RazorEditorFactoryService editorFactoryService)
{
if (dispatcher == null)
{
throw new ArgumentNullException(nameof(dispatcher));
}
if (editorFactoryService == null)
{
throw new ArgumentNullException(nameof(editorFactoryService));
}
_foregroundDispatcher = dispatcher;
_editorFactoryService = editorFactoryService;
}
public override void OnTextViewOpened(ITextView textView, IEnumerable<ITextBuffer> subjectBuffers)
{
if (textView == null)
{
throw new ArgumentNullException(nameof(textView));
}
if (subjectBuffers == null)
{
throw new ArgumentNullException(nameof(subjectBuffers));
}
_foregroundDispatcher.AssertForegroundThread();
foreach (var textBuffer in subjectBuffers)
{
if (!textBuffer.IsRazorBuffer())
{
continue;
}
if (!_editorFactoryService.TryGetDocumentTracker(textBuffer, out var documentTracker) ||
!(documentTracker is DefaultVisualStudioDocumentTracker tracker))
{
Debug.Fail("Tracker should always be available given our expectations of the VS workflow.");
return;
}
tracker.AddTextView(textView);
if (documentTracker.TextViews.Count == 1)
{
tracker.Subscribe();
}
}
}
public override void OnTextViewClosed(ITextView textView, IEnumerable<ITextBuffer> subjectBuffers)
{
if (textView == null)
{
throw new ArgumentNullException(nameof(textView));
}
if (subjectBuffers == null)
{
throw new ArgumentNullException(nameof(subjectBuffers));
}
_foregroundDispatcher.AssertForegroundThread();
// This means a Razor buffer has be detached from this ITextView or the ITextView is closing. Since we keep a
// list of all of the open text views for each text buffer, we need to update the tracker.
//
// Notice that this method is called *after* changes are applied to the text buffer(s). We need to check every
// one of them for a tracker because the content type could have changed.
foreach (var textBuffer in subjectBuffers)
{
DefaultVisualStudioDocumentTracker documentTracker;
if (textBuffer.Properties.TryGetProperty(typeof(VisualStudioDocumentTracker), out documentTracker))
{
documentTracker.RemoveTextView(textView);
if (documentTracker.TextViews.Count == 0)
{
documentTracker.Unsubscribe();
}
}
}
}
}
}

Some files were not shown because too many files have changed in this diff Show More