Show only latest VS, VC prompts by default (#11326)

## Summary of the Pull Request

Similar to `vswhere -latest`, show only the latest Visual Studio command prompts / developer PowerShell. This was tested by deleting the local package state and testing against fresh state with both VS2019 and VS2022 Preview installed, and indeed VS2022 Preview (both cmd and powershell) show. The other profiles were generated but hidden by default.

## References

Modification of PR #7774

## PR Checklist
* [x] Closes #11307
* [x] CLA signed. If not, go over [here](https://cla.opensource.microsoft.com/microsoft/Terminal) and sign the CLA
* [x] Tests added/passed
* [ ] Documentation updated. If checked, please file a pull request on [our docs repo](https://github.com/MicrosoftDocs/terminal) and link it here: #xxx
* [ ] Schema updated.
* [x] I've discussed this with core contributors already. If not checked, I'm ready to accept this work might be rejected in favor of a different grand plan. Issue number where discussion took place: #xxx

## Detailed Description of the Pull Request / Additional comments

The sort algorithm is the same basic algorithm I used in https://github.com/microsoft/vswhere. It sorts first by installation version with a secondary sort based on the install date in case the installation versions are the same.

## Validation Steps Performed

With both VS2019 and VS2022 Preview installed, I made sure the initial state was expected, and tried different combinations of hiding and unhiding generated entries, and restarted Terminal to make sure my settings "stuck".
This commit is contained in:
Heath Stewart 2021-09-29 15:03:05 -07:00 committed by GitHub
parent d869913cfd
commit 37e8769b37
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 375 additions and 126 deletions

View File

@ -24,6 +24,7 @@ DTDs
DWINRT
enablewttlogging
Intelli
IVisual
LKG
LOCKFILE
Lxss

View File

@ -24,3 +24,4 @@ VERIFY_ARE_EQUAL\(L"[^"]+"
std::memory_order_[\w]+
D2DERR_SHADER_COMPILE_FAILED
TIL_FEATURE_[0-9A-Z_]+
vcvars\w*

View File

@ -1,36 +0,0 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "BaseVisualStudioGenerator.h"
#include "DynamicProfileUtils.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
void BaseVisualStudioGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
// There's no point in enumerating valid Visual Studio instances more than once,
// so cache them for use by both Visual Studio profile generators.
static const auto instances = VsSetupConfiguration::QueryInstances();
for (auto const& instance : instances)
{
try
{
if (!IsInstanceValid(instance))
{
continue;
}
const auto seed = GetProfileGuidSeed(instance);
const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
auto profile = winrt::make_self<implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ GetProfileName(instance) });
profile->Commandline(winrt::hstring{ GetProfileCommandLine(instance) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profile->Icon(winrt::hstring{ GetProfileIconPath() });
profiles.emplace_back(std::move(profile));
}
CATCH_LOG();
}
}

View File

@ -1,35 +0,0 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- BaseVisualStudioGenerator
Abstract:
- Base generator for Visual Studio Developer shell profiles
Author(s):
- Charles Willis - October 2020
--*/
#pragma once
#include "IDynamicProfileGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class BaseVisualStudioGenerator : public IDynamicProfileGenerator
{
public:
void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
protected:
virtual bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const = 0;
virtual std::wstring GetProfileIconPath() const = 0;
};
};

View File

@ -11,8 +11,7 @@
#include "AzureCloudShellGenerator.h"
#include "PowershellCoreProfileGenerator.h"
#include "VsDevCmdGenerator.h"
#include "VsDevShellGenerator.h"
#include "VisualStudioGenerator.h"
#include "WslDistroGenerator.h"
// The following files are generated at build time into the "Generated Files" directory.
@ -131,8 +130,7 @@ void SettingsLoader::GenerateProfiles()
_executeGenerator(PowershellCoreProfileGenerator{});
_executeGenerator(WslDistroGenerator{});
_executeGenerator(AzureCloudShellGenerator{});
_executeGenerator(VsDevCmdGenerator{});
_executeGenerator(VsDevShellGenerator{});
_executeGenerator(VisualStudioGenerator{});
}
// A new settings.json gets a special treatment:

View File

@ -14,7 +14,8 @@
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.pre.props" />
<!-- ========================= Headers ======================== -->
<ItemGroup>
<ClInclude Include="BaseVisualStudioGenerator.h" />
<ClInclude Include="VcDevCmdGenerator.h" />
<ClInclude Include="VisualStudioGenerator.h" />
<ClInclude Include="DefaultTerminal.h">
<DependentUpon>DefaultTerminal.idl</DependentUpon>
</ClInclude>
@ -84,7 +85,8 @@
</ItemGroup>
<!-- ========================= Cpp Files ======================== -->
<ItemGroup>
<ClCompile Include="BaseVisualStudioGenerator.cpp" />
<ClCompile Include="VcDevCmdGenerator.cpp" />
<ClCompile Include="VisualStudioGenerator.cpp" />
<ClCompile Include="DefaultTerminal.cpp">
<DependentUpon>DefaultTerminal.idl</DependentUpon>
</ClCompile>
@ -241,7 +243,6 @@
</ItemDefinitionGroup>
<!-- ========================= Globals ======================== -->
<Import Project="$(OpenConsoleDir)src\cppwinrt.build.post.props" />
<Import Project="..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets" Condition="Exists('..\..\..\packages\Microsoft.UI.Xaml.2.7.0-prerelease.210913003\build\native\Microsoft.UI.Xaml.targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
@ -266,4 +267,4 @@
</Target>
<Import Project="$(SolutionDir)build\rules\CollectWildcardResources.targets" />
<Import Project="..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets" Condition="Exists('..\..\..\packages\Microsoft.VisualStudio.Setup.Configuration.Native.2.3.2262\build\native\Microsoft.VisualStudio.Setup.Configuration.Native.targets')" />
</Project>
</Project>

View File

@ -34,7 +34,7 @@
<ClCompile Include="IconPathConverter.cpp" />
<ClCompile Include="DefaultTerminal.cpp" />
<ClCompile Include="FileUtils.cpp" />
<ClCompile Include="BaseVisualStudioGenerator.cpp">
<ClCompile Include="VisualStudioGenerator.cpp">
<Filter>profileGeneration</Filter>
</ClCompile>
<ClCompile Include="VsDevCmdGenerator.cpp">
@ -46,6 +46,9 @@
<ClCompile Include="VsSetupConfiguration.cpp">
<Filter>profileGeneration</Filter>
</ClCompile>
<ClCompile Include="VcDevCmdGenerator.cpp">
<Filter>profileGeneration</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
@ -80,7 +83,7 @@
<ClInclude Include="DefaultTerminal.h" />
<ClInclude Include="FileUtils.h" />
<ClInclude Include="HashUtils.h" />
<ClInclude Include="BaseVisualStudioGenerator.h">
<ClInclude Include="VisualStudioGenerator.h">
<Filter>profileGeneration</Filter>
</ClInclude>
<ClInclude Include="VsDevCmdGenerator.h">
@ -92,6 +95,9 @@
<ClInclude Include="VsSetupConfiguration.h">
<Filter>profileGeneration</Filter>
</ClInclude>
<ClInclude Include="VcDevCmdGenerator.h">
<Filter>profileGeneration</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<Midl Include="ActionArgs.idl" />
@ -123,4 +129,4 @@
<UniqueIdentifier>{81a6314f-aa5b-4533-a499-13bc3a5c4af0}</UniqueIdentifier>
</Filter>
</ItemGroup>
</Project>
</Project>

View File

@ -0,0 +1,94 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "DynamicProfileUtils.h"
#include "VcDevCmdGenerator.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
void VcDevCmdGenerator::GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
try
{
const std::filesystem::path root{ GetVcCmdScriptDirectory(instance) };
if (!std::filesystem::exists(root))
{
return;
}
// x64 environments only installed on 64-bit machines.
#ifdef _WIN64
const auto vcvars64 = root / L"vcvars64.bat";
if (std::filesystem::exists(vcvars64))
{
auto profile = CreateProfile(instance, L"x64", vcvars64, hidden);
profiles.emplace_back(std::move(profile));
// Only the VC environment for the matching architecture should be shown by default.
hidden = true;
}
const auto vcvarsamd64_x86 = root / L"vcvarsamd64_x86.bat";
if (std::filesystem::exists(vcvarsamd64_x86))
{
auto profile = CreateProfile(instance, L"x64_x86", vcvarsamd64_x86, true);
profiles.emplace_back(std::move(profile));
}
const auto vcvarsx86_amd64 = root / L"vcvarsx86_amd64.bat";
if (std::filesystem::exists(vcvarsx86_amd64))
{
auto profile = CreateProfile(instance, L"x86_x64", vcvarsx86_amd64, true);
profiles.emplace_back(std::move(profile));
}
#endif // _WIN64
const auto vcvars32 = root / L"vcvars32.bat";
if (std::filesystem::exists(vcvars32))
{
auto profile = CreateProfile(instance, L"x86", vcvars32, hidden);
profiles.emplace_back(std::move(profile));
}
}
CATCH_LOG();
}
winrt::com_ptr<implementation::Profile> VcDevCmdGenerator::CreateProfile(const VsSetupConfiguration::VsSetupInstance& instance, const std::wstring_view& prefix, const std::filesystem::path& path, bool hidden) const
{
const auto seed = GetProfileGuidSeed(instance, path);
const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
auto profile = winrt::make_self<implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ GetProfileName(instance, prefix) });
profile->Commandline(winrt::hstring{ GetProfileCommandLine(path) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profile->Icon(winrt::hstring{ GetProfileIconPath() });
profile->Hidden(hidden);
return profile;
}
std::wstring VcDevCmdGenerator::GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance, const std::filesystem::path& path) const
{
return L"VsDevCmd" + instance.GetInstanceId() + path.native();
}
std::wstring VcDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance, const std::wstring_view& prefix) const
{
std::wstring name{ prefix + L" Native Tools Command Prompt for VS " };
name.append(instance.GetProfileNameSuffix());
return name;
}
std::wstring VcDevCmdGenerator::GetProfileCommandLine(const std::filesystem::path& path) const
{
std::wstring commandLine{ L"cmd.exe /k \"" + path.native() + L"\"" };
return commandLine;
}
std::wstring VcDevCmdGenerator::GetVcCmdScriptDirectory(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return instance.ResolvePath(L"VC\\Auxiliary\\Build\\");
}

View File

@ -0,0 +1,40 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- VcDevCmdGenerator
Abstract:
- Dynamic profile generator for Visual C++ development environments.
Author(s):
- Heath Stewart - September 2021
--*/
#pragma once
#include "VisualStudioGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class VcDevCmdGenerator final : public VisualStudioGenerator::IVisualStudioProfileGenerator
{
public:
void GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
private:
winrt::com_ptr<implementation::Profile> CreateProfile(const VsSetupConfiguration::VsSetupInstance& instance, const std::wstring_view& prefix, const std::filesystem::path& path, bool hidden) const;
std::wstring GetProfileIconPath() const
{
return L"ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png";
}
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance, const std::filesystem::path& path) const;
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance, const std::wstring_view& prefix) const;
std::wstring GetProfileCommandLine(const std::filesystem::path& path) const;
std::wstring GetVcCmdScriptDirectory(const VsSetupConfiguration::VsSetupInstance& instance) const;
};
};

View File

@ -0,0 +1,36 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT license.
#include "pch.h"
#include "DynamicProfileUtils.h"
#include "VisualStudioGenerator.h"
#include "VcDevCmdGenerator.h"
#include "VsDevCmdGenerator.h"
#include "VsDevShellGenerator.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
std::wstring_view VisualStudioGenerator::GetNamespace() const noexcept
{
return std::wstring_view{ L"Windows.Terminal.VisualStudio" };
}
void VisualStudioGenerator::GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
const auto instances = VsSetupConfiguration::QueryInstances();
VsDevCmdGenerator devCmdGenerator;
VcDevCmdGenerator vcCmdGenerator;
VsDevShellGenerator devShellGenerator;
// Instances are ordered from latest to oldest. Hide all but the profiles for the latest instance.
bool hidden = false;
for (auto const& instance : instances)
{
devCmdGenerator.GenerateProfiles(instance, hidden, profiles);
vcCmdGenerator.GenerateProfiles(instance, hidden, profiles);
devShellGenerator.GenerateProfiles(instance, hidden, profiles);
hidden = true;
}
}

View File

@ -0,0 +1,38 @@
/*++
Copyright (c) Microsoft Corporation
Licensed under the MIT license.
Module Name:
- VisualStudioGenerator
Abstract:
- Generator for Visual Studio shell profiles. Actual profile generation is delegated
to separate classes that encapsulate different logic for cmd- and powershell-based shells,
as well as VC startup scripts specific to the current processor architecture.
Author(s):
- Charles Willis - October 2020
- Heath Stewart - September 2021
--*/
#pragma once
#include "IDynamicProfileGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class VisualStudioGenerator : public IDynamicProfileGenerator
{
public:
std::wstring_view GetNamespace() const noexcept override;
void GenerateProfiles(std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
class IVisualStudioProfileGenerator
{
public:
virtual void GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const = 0;
};
};
};

View File

@ -2,10 +2,33 @@
// Licensed under the MIT license.
#include "pch.h"
#include "DynamicProfileUtils.h"
#include "VsDevCmdGenerator.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
void VsDevCmdGenerator::GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
try
{
if (!IsInstanceValid(instance))
{
return;
}
const auto seed = GetProfileGuidSeed(instance);
const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
auto profile = winrt::make_self<implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ GetProfileName(instance) });
profile->Commandline(winrt::hstring{ GetProfileCommandLine(instance) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profile->Icon(winrt::hstring{ GetProfileIconPath() });
profile->Hidden(hidden);
profiles.emplace_back(std::move(profile));
}
CATCH_LOG();
}
std::wstring VsDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const
{
std::wstring name{ L"Developer Command Prompt for VS " };
@ -15,7 +38,12 @@ std::wstring VsDevCmdGenerator::GetProfileName(const VsSetupConfiguration::VsSet
std::wstring VsDevCmdGenerator::GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const
{
std::wstring commandLine{ L"cmd.exe /k \"" + instance.GetDevCmdScriptPath() + L"\"" };
std::wstring commandLine{ L"cmd.exe /k \"" + GetDevCmdScriptPath(instance) + L"\"" };
return commandLine;
}
std::wstring VsDevCmdGenerator::GetDevCmdScriptPath(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return instance.ResolvePath(L"Common7\\Tools\\VsDevCmd.bat");
}

View File

@ -10,23 +10,23 @@ Abstract:
Author(s):
- Charles Willis - October 2020
- Heath Stewart - September 2021
--*/
#pragma once
#include "BaseVisualStudioGenerator.h"
#include "VisualStudioGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class VsDevCmdGenerator final : public BaseVisualStudioGenerator
class VsDevCmdGenerator final : public VisualStudioGenerator::IVisualStudioProfileGenerator
{
public:
std::wstring_view GetNamespace() const noexcept override
{
return std::wstring_view{ L"Windows.Terminal.VisualStudio.CommandPrompt" };
}
void GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance&) const override
private:
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance&) const
{
// We only support version of VS from 15.0.
// Per heaths: The [ISetupConfiguration] COM server only supports Visual Studio 15.0 and newer anyway.
@ -34,17 +34,18 @@ namespace winrt::Microsoft::Terminal::Settings::Model
return true;
}
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const override
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return L"VsDevCmd" + instance.GetInstanceId();
}
std::wstring GetProfileIconPath() const override
std::wstring GetProfileIconPath() const
{
return L"ms-appx:///ProfileIcons/{0caa0dad-35be-5f56-a8ff-afceeeaa6101}.png";
}
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const override;
std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const override;
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const;
std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const;
std::wstring GetDevCmdScriptPath(const VsSetupConfiguration::VsSetupInstance& instance) const;
};
};

View File

@ -2,11 +2,34 @@
// Licensed under the MIT license.
#include "pch.h"
#include "DynamicProfileUtils.h"
#include "VsDevShellGenerator.h"
#include "VsSetupConfiguration.h"
using namespace winrt::Microsoft::Terminal::Settings::Model;
void VsDevShellGenerator::GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const
{
try
{
if (!IsInstanceValid(instance))
{
return;
}
const auto seed = GetProfileGuidSeed(instance);
const winrt::guid profileGuid{ ::Microsoft::Console::Utils::CreateV5Uuid(TERMINAL_PROFILE_NAMESPACE_GUID, gsl::as_bytes(gsl::make_span(seed))) };
auto profile = winrt::make_self<implementation::Profile>(profileGuid);
profile->Name(winrt::hstring{ GetProfileName(instance) });
profile->Commandline(winrt::hstring{ GetProfileCommandLine(instance) });
profile->StartingDirectory(winrt::hstring{ instance.GetInstallationPath() });
profile->Icon(winrt::hstring{ GetProfileIconPath() });
profile->Hidden(hidden);
profiles.emplace_back(std::move(profile));
}
CATCH_LOG();
}
std::wstring VsDevShellGenerator::GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const
{
std::wstring name{ L"Developer PowerShell for VS " };
@ -20,9 +43,20 @@ std::wstring VsDevShellGenerator::GetProfileCommandLine(const VsSetupConfigurati
// The "SkipAutomaticLocation" parameter will prevent "Enter-VsDevShell" from automatically setting the shell path
// so the path in the profile will be used instead.
std::wstring commandLine{ L"powershell.exe -NoExit -Command \"& {" };
commandLine.append(L"Import-Module \"\"\"" + instance.GetDevShellModulePath() + L"\"\"\";");
commandLine.append(L"Import-Module \"\"\"" + GetDevShellModulePath(instance) + L"\"\"\";");
commandLine.append(L"Enter-VsDevShell " + instance.GetInstanceId() + L" -SkipAutomaticLocation");
commandLine.append(L"}\"");
return commandLine;
}
std::wstring VsDevShellGenerator::GetDevShellModulePath(const VsSetupConfiguration::VsSetupInstance& instance) const
{
// The path of Microsoft.VisualStudio.DevShell.dll changed in 16.3
if (instance.VersionInRange(L"[16.3,"))
{
return instance.ResolvePath(L"Common7\\Tools\\Microsoft.VisualStudio.DevShell.dll");
}
return instance.ResolvePath(L"Common7\\Tools\\vsdevshell\\Microsoft.VisualStudio.DevShell.dll");
}

View File

@ -10,38 +10,39 @@ Abstract:
Author(s):
- Charles Willis - October 2020
- Heath Stewart - September 2021
--*/
#pragma once
#include "BaseVisualStudioGenerator.h"
#include "VisualStudioGenerator.h"
#include "VsSetupConfiguration.h"
namespace winrt::Microsoft::Terminal::Settings::Model
{
class VsDevShellGenerator final : public BaseVisualStudioGenerator
class VsDevShellGenerator final : public VisualStudioGenerator::IVisualStudioProfileGenerator
{
public:
std::wstring_view GetNamespace() const noexcept override
{
return std::wstring_view{ L"Windows.Terminal.VisualStudio.Powershell" };
}
void GenerateProfiles(const VsSetupConfiguration::VsSetupInstance& instance, bool hidden, std::vector<winrt::com_ptr<implementation::Profile>>& profiles) const override;
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const override
private:
bool IsInstanceValid(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return instance.VersionInRange(L"[16.2,)");
}
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const override
std::wstring GetProfileGuidSeed(const VsSetupConfiguration::VsSetupInstance& instance) const
{
return L"VsDevShell" + instance.GetInstanceId();
}
std::wstring GetProfileIconPath() const override
std::wstring GetProfileIconPath() const
{
return L"ms-appx:///ProfileIcons/{61c54bbd-c2c6-5271-96e7-009a87ff44bf}.png";
}
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const override;
std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const override;
std::wstring GetProfileName(const VsSetupConfiguration::VsSetupInstance& instance) const;
std::wstring GetProfileCommandLine(const VsSetupConfiguration::VsSetupInstance& instance) const;
std::wstring GetDevShellModulePath(const VsSetupConfiguration::VsSetupInstance& instance) const;
};
};

View File

@ -32,6 +32,19 @@ std::vector<VsSetupConfiguration::VsSetupInstance> VsSetupConfiguration::QueryIn
THROW_IF_FAILED(result);
// Sort instances based on version and install date from latest to oldest.
std::sort(instances.begin(), instances.end(), [](const VsSetupInstance& a, const VsSetupInstance& b) {
auto const aVersion = a.GetComparableVersion();
auto const bVersion = b.GetComparableVersion();
if (aVersion == bVersion)
{
return a.GetComparableInstallDate() > b.GetComparableInstallDate();
}
return aVersion > bVersion;
});
return instances;
}
@ -95,6 +108,13 @@ std::wstring VsSetupConfiguration::GetInstanceId(ISetupInstance* pInst)
return bstrInstanceId.get();
}
unsigned long long VsSetupConfiguration::GetInstallDate(ISetupInstance* pInst)
{
FILETIME ftInstallDate{ 0 };
THROW_IF_FAILED(pInst->GetInstallDate(&ftInstallDate));
return wil::filetime::to_int64(ftInstallDate);
}
std::wstring VsSetupConfiguration::GetStringProperty(ISetupPropertyStore* pProps, std::wstring_view name)
{
if (pProps == nullptr)

View File

@ -10,6 +10,7 @@ Abstract:
Author(s):
- Charles Willis - October 2020
- Heath Stewart - September 2021
--*/
@ -37,27 +38,14 @@ namespace winrt::Microsoft::Terminal::Settings::Model
public:
struct VsSetupInstance
{
VsSetupInstance(VsSetupInstance&& other) = default;
VsSetupInstance& operator=(VsSetupInstance&&) = default;
std::wstring ResolvePath(std::wstring_view relativePath) const
{
return VsSetupConfiguration::ResolvePath(inst.get(), relativePath);
}
std::wstring GetDevShellModulePath() const
{
// The path of Microsoft.VisualStudio.DevShell.dll changed in 16.3
if (VersionInRange(L"[16.3,"))
{
return ResolvePath(L"Common7\\Tools\\Microsoft.VisualStudio.DevShell.dll");
}
return ResolvePath(L"Common7\\Tools\\vsdevshell\\Microsoft.VisualStudio.DevShell.dll");
}
std::wstring GetDevCmdScriptPath() const
{
return ResolvePath(L"Common7\\Tools\\VsDevCmd.bat");
}
bool VersionInRange(std::wstring_view range) const
{
return InstallationVersionInRange(query.get(), inst.get(), range);
@ -65,7 +53,17 @@ namespace winrt::Microsoft::Terminal::Settings::Model
std::wstring GetVersion() const
{
return GetInstallationVersion(inst.get());
return VsSetupConfiguration::GetInstallationVersion(inst.get());
}
unsigned long long GetComparableInstallDate() const
{
return installDate;
}
unsigned long long GetComparableVersion() const
{
return version;
}
std::wstring GetInstallationPath() const
@ -120,9 +118,11 @@ namespace winrt::Microsoft::Terminal::Settings::Model
friend class VsSetupConfiguration;
VsSetupInstance(ComPtrSetupQuery pQuery, ComPtrSetupInstance pInstance) :
query(std::move(pQuery)),
inst(std::move(pInstance)),
profileNameSuffix(BuildProfileNameSuffix())
query(pQuery), // Copy and AddRef the query object.
inst(std::move(pInstance)), // Take ownership of the instance object.
profileNameSuffix(BuildProfileNameSuffix()),
installDate(GetInstallDate()),
version(GetInstallationVersion())
{
}
@ -131,6 +131,10 @@ namespace winrt::Microsoft::Terminal::Settings::Model
std::wstring profileNameSuffix;
// Cache oft-accessed properties used in sorting.
unsigned long long installDate;
unsigned long long version;
std::wstring BuildProfileNameSuffix() const
{
ComPtrCatalogPropertyStore catalogProperties = GetCatalogPropertyStore();
@ -167,6 +171,22 @@ namespace winrt::Microsoft::Terminal::Settings::Model
return GetVersion();
}
unsigned long long GetInstallDate() const
{
return VsSetupConfiguration::GetInstallDate(inst.get());
}
unsigned long long GetInstallationVersion() const
{
const auto helper = wil::com_query<ISetupHelper>(query);
std::wstring versionString{ GetVersion() };
unsigned long long version{ 0 };
THROW_IF_FAILED(helper->ParseVersion(versionString.data(), &version));
return version;
}
static std::wstring GetChannelNameSuffixTag(ISetupPropertyStore* instanceProperties)
{
std::wstring tag;
@ -229,6 +249,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model
static std::wstring GetInstallationVersion(ISetupInstance* pInst);
static std::wstring GetInstallationPath(ISetupInstance* pInst);
static std::wstring GetInstanceId(ISetupInstance* pInst);
static unsigned long long GetInstallDate(ISetupInstance* pInst);
static std::wstring GetStringProperty(ISetupPropertyStore* pProps, std::wstring_view name);
};
};