Backend/ReSharperPlugin/ForTea.ReSharperPlugin/T4ReSharperEnvironment.cs (178 lines of code) (raw):
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using GammaJul.ForTea.Core.Services;
using JetBrains.Annotations;
using JetBrains.Application;
using JetBrains.Application.Parts;
using JetBrains.Application.platforms;
using JetBrains.ReSharper.Psi.CSharp;
using JetBrains.Util;
using JetBrains.Util.DevEnv;
using JetBrains.Util.Dotnet.TargetFrameworkIds;
using Microsoft.Win32;
namespace JetBrains.ForTea.ReSharperPlugin
{
/// <summary>Contains environment-dependent information.</summary>
[ShellComponent(Instantiation.DemandAnyThreadSafe)]
public sealed class T4ReSharperEnvironment : T4DefaultEnvironment
{
// temporary solution until that constant is added into the SDK
private const int VsVersion2022 = 17;
[NotNull] private readonly IVsEnvironmentStaticInformation _vsEnvironmentInformation;
[NotNull] private readonly string[] _textTemplatingAssemblyNames;
[CanBeNull] private readonly TargetFrameworkId _targetFrameworkId;
[CanBeNull] private IList<VirtualFileSystemPath> _includePaths;
/// <summary>Gets the target framework ID.</summary>
public override TargetFrameworkId TargetFrameworkId
{
get
{
if (_targetFrameworkId == null) throw Unsupported();
return _targetFrameworkId;
}
}
/// <summary>Gets the C# language version.</summary>
public override CSharpLanguageLevel CSharpLanguageLevel { get; }
/// <summary>Gets the default included assemblies.</summary>
[NotNull]
private IEnumerable<string> TextTemplatingAssemblyNames
{
get
{
if (_targetFrameworkId == null)
throw Unsupported();
return _textTemplatingAssemblyNames;
}
}
public override IEnumerable<string> DefaultAssemblyNames =>
TextTemplatingAssemblyNames.Concat(base.DefaultAssemblyNames);
/// <summary>Gets whether the current environment is supported. VS2005 and VS2008 aren't.</summary>
public override bool IsSupported => _targetFrameworkId != null;
/// <summary>Gets the common include paths from the registry.</summary>
public override IEnumerable<VirtualFileSystemPath> IncludePaths
{
get
{
if (_targetFrameworkId == null)
return EmptyList<VirtualFileSystemPath>.InstanceList;
return _includePaths ?? (_includePaths = ReadIncludePaths());
}
}
[NotNull]
private IList<VirtualFileSystemPath> ReadIncludePaths()
{
string registryKey = _vsEnvironmentInformation.VisualStudioGlobalRegistryPath
+ @"_Config\TextTemplating\IncludeFolders\.tt";
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(registryKey))
{
if (key == null)
return EmptyList<VirtualFileSystemPath>.InstanceList;
string[] valueNames = key.GetValueNames();
if (valueNames.Length == 0)
return EmptyList<VirtualFileSystemPath>.InstanceList;
var paths = new List<VirtualFileSystemPath>(valueNames.Length);
foreach (string valueName in valueNames)
{
var value = key.GetValue(valueName) as string;
if (String.IsNullOrEmpty(value))
continue;
var path = VirtualFileSystemPath.TryParse(value, InteractionContext.SolutionContext);
if (!path.IsEmpty && path.IsAbsolute)
paths.Add(path);
}
return paths;
}
}
[NotNull, Pure]
private static NotSupportedException Unsupported() => new("Unsupported environment");
[NotNull]
private static string CreateGacAssemblyName([NotNull] string name, int majorVersion)
=> String.Format(
CultureInfo.InvariantCulture,
"{0}.{1}.0, Version={1}.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a",
name,
majorVersion);
[NotNull]
[Pure]
private static string CreateDevEnvPublicAssemblyName(
[NotNull] IVsEnvironmentStaticInformation vsEnvironmentInformation, [NotNull] string name)
=> vsEnvironmentInformation
.DevEnvInstallDir
.Combine(RelativePath.Parse("PublicAssemblies\\" + name + ".dll"))
.FullPath;
public T4ReSharperEnvironment([NotNull] IVsEnvironmentStaticInformation vsEnvironmentInformation)
{
_vsEnvironmentInformation = vsEnvironmentInformation;
switch (vsEnvironmentInformation.VsVersion2.Major)
{
case VsVersions.Vs2010:
_targetFrameworkId = TargetFrameworkId.Create(FrameworkIdentifier.NetFramework, new Version(4, 0));
CSharpLanguageLevel = CSharpLanguageLevel.CSharp40;
_textTemplatingAssemblyNames = new[]
{
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating", 10),
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating.Interfaces", 10)
};
break;
case VsVersions.Vs2012:
_targetFrameworkId = TargetFrameworkId.Create(FrameworkIdentifier.NetFramework, new Version(4, 5));
CSharpLanguageLevel = CSharpLanguageLevel.CSharp50;
_textTemplatingAssemblyNames = new[]
{
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating", 11),
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating.Interfaces", 11),
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating.Interfaces", 10)
};
break;
case VsVersions.Vs2013:
_targetFrameworkId = TargetFrameworkId.Create(FrameworkIdentifier.NetFramework, new Version(4, 5));
CSharpLanguageLevel = CSharpLanguageLevel.CSharp50;
_textTemplatingAssemblyNames = new[]
{
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating", 12),
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating.Interfaces", 11),
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating.Interfaces", 10)
};
break;
case VsVersions.Vs2015:
_targetFrameworkId = TargetFrameworkId.Create(FrameworkIdentifier.NetFramework, new Version(4, 5));
const int vs2015Update2Build = 25123;
CSharpLanguageLevel = vsEnvironmentInformation.VsVersion4.Build >= vs2015Update2Build
? CSharpLanguageLevel.CSharp60
: CSharpLanguageLevel.CSharp50;
_textTemplatingAssemblyNames = new[]
{
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating", 14),
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating.Interfaces", 11),
CreateGacAssemblyName("Microsoft.VisualStudio.TextTemplating.Interfaces", 10)
};
break;
case VsVersions.Vs2017:
_targetFrameworkId = TargetFrameworkId.Create(FrameworkIdentifier.NetFramework, new Version(4, 6));
CSharpLanguageLevel = CSharpLanguageLevel.CSharp70;
_textTemplatingAssemblyNames = new[]
{
CreateDevEnvPublicAssemblyName(vsEnvironmentInformation, "Microsoft.VisualStudio.TextTemplating.15.0"),
CreateDevEnvPublicAssemblyName(vsEnvironmentInformation,
"Microsoft.VisualStudio.TextTemplating.Interfaces.11.0"),
CreateDevEnvPublicAssemblyName(vsEnvironmentInformation,
"Microsoft.VisualStudio.TextTemplating.Interfaces.10.0")
};
break;
case VsVersions.Vs2019:
_targetFrameworkId = TargetFrameworkId.Create(FrameworkIdentifier.NetFramework, new Version(4, 7, 2));
CSharpLanguageLevel = CSharpLanguageLevel.CSharp73;
_textTemplatingAssemblyNames = new[]
{
CreateDevEnvPublicAssemblyName(vsEnvironmentInformation, "Microsoft.VisualStudio.TextTemplating.15.0"),
CreateDevEnvPublicAssemblyName(vsEnvironmentInformation,
"Microsoft.VisualStudio.TextTemplating.Interfaces.11.0"),
CreateDevEnvPublicAssemblyName(vsEnvironmentInformation,
"Microsoft.VisualStudio.TextTemplating.Interfaces.10.0")
};
break;
case VsVersion2022:
_targetFrameworkId = TargetFrameworkId.Create(FrameworkIdentifier.NetFramework, new Version(4, 8));
CSharpLanguageLevel = CSharpLanguageLevel.CSharp100;
_textTemplatingAssemblyNames = new[]
{
CreateDevEnvPublicAssemblyName(vsEnvironmentInformation, "Microsoft.VisualStudio.TextTemplating"),
CreateDevEnvPublicAssemblyName(vsEnvironmentInformation,
"Microsoft.VisualStudio.TextTemplating.Interfaces.11.0"),
CreateDevEnvPublicAssemblyName(vsEnvironmentInformation,
"Microsoft.VisualStudio.TextTemplating.Interfaces.10.0")
};
break;
default:
_textTemplatingAssemblyNames = EmptyArray<string>.Instance;
break;
}
}
}
}