Skip to content

Commit

Permalink
Add "portable mode", where settings load from the install path (#15051)
Browse files Browse the repository at this point in the history
This pull request implements portable mode for Windows Terminal, which
will make side by side deployment of different versions generally more
feasible.

Portable mode was specified in #15032.

There are three broad categories of changes in this PR:

1. Changes to settings loading.
2. A new indicator in the settings UI plus a link to the portable mode
   docs.
3. A new application display name, `Terminal (Portable)`, which users
   will hopefully include in their bug reports.

It's surprisingly small for how big a deal it is!

Related to #15034
Closes #1386
  • Loading branch information
DHowett authored Mar 31, 2023
1 parent bbd4d1b commit e6a3fa8
Show file tree
Hide file tree
Showing 10 changed files with 72 additions and 10 deletions.
1 change: 1 addition & 0 deletions .github/actions/spelling/expect/expect.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1946,6 +1946,7 @@ trx
tsattrs
tsf
tsgr
tsm
TStr
TSTRFORMAT
TSub
Expand Down
31 changes: 24 additions & 7 deletions src/cascadia/TerminalSettingsEditor/MainPage.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
xmlns:local="using:Microsoft.Terminal.Settings.Editor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:muxc="using:Microsoft.UI.Xaml.Controls"
xmlns:tsm="using:Microsoft.Terminal.Settings.Model"
mc:Ignorable="d">

<Page.Resources>
Expand Down Expand Up @@ -189,13 +190,29 @@
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<TextBlock x:Uid="Settings_UnsavedSettingsWarning"
Margin="30,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Foreground="Goldenrod"
TextAlignment="Left"
Visibility="Collapsed" />
<StackPanel Margin="30,0,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
Orientation="Vertical">
<TextBlock x:Uid="Settings_UnsavedSettingsWarning"
Foreground="Goldenrod"
TextAlignment="Left"
Visibility="Collapsed" />
<StackPanel VerticalAlignment="Center"
Orientation="Horizontal"
Spacing="4"
Visibility="{x:Bind tsm:CascadiaSettings.IsPortableMode, Mode=OneTime}">
<FontIcon FontFamily="{StaticResource SymbolThemeFontFamily}"
Foreground="SlateBlue"
Glyph="&#xE946;" />
<TextBlock Foreground="SlateBlue">
<Run x:Uid="Settings_PortableModeNote" />
<Hyperlink x:Uid="Settings_PortableModeInfoLink">
<Run x:Uid="Settings_PortableModeInfoLinkTextRun" />
</Hyperlink>
</TextBlock>
</StackPanel>
</StackPanel>
<StackPanel Margin="0,0,30,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1585,4 +1585,16 @@
<value>Warn when closing more than one tab</value>
<comment>Header for a control to toggle whether to show a confirm dialog box when closing the application with multiple tabs open.</comment>
</data>
</root>
<data name="Settings_PortableModeNote.Text" xml:space="preserve">
<value>Windows Terminal is running in portable mode.</value>
<comment>A disclaimer that indicates that Terminal is running in a mode that saves settings to a different folder.</comment>
</data>
<data name="Settings_PortableModeInfoLink.NavigateUri" xml:space="preserve">
<value>https://go.microsoft.com/fwlink/?linkid=2229086</value>
<comment>{Locked}</comment>
</data>
<data name="Settings_PortableModeInfoLinkTextRun.Text" xml:space="preserve">
<value>Learn more.</value>
<comment>A hyperlink displayed near Settings_PortableModeNote.Text that the user can follow for more information.</comment>
</data>
</root>
2 changes: 1 addition & 1 deletion src/cascadia/TerminalSettingsModel/CascadiaSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1006,7 +1006,7 @@ winrt::hstring CascadiaSettings::ApplicationDisplayName()
}
CATCH_LOG();

return RS_(L"ApplicationDisplayNameUnpackaged");
return IsPortableMode() ? RS_(L"ApplicationDisplayNamePortable") : RS_(L"ApplicationDisplayNameUnpackaged");
}

winrt::hstring CascadiaSettings::ApplicationVersion()
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettingsModel/CascadiaSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ namespace winrt::Microsoft::Terminal::Settings::Model::implementation
static winrt::hstring DefaultSettingsPath();
static winrt::hstring ApplicationDisplayName();
static winrt::hstring ApplicationVersion();
static bool IsPortableMode();
static void ExportFile(winrt::hstring path, winrt::hstring content);

CascadiaSettings() noexcept = default;
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettingsModel/CascadiaSettings.idl
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace Microsoft.Terminal.Settings.Model

static String SettingsPath { get; };
static String DefaultSettingsPath { get; };
static Boolean IsPortableMode { get; };

static String ApplicationDisplayName { get; };
static String ApplicationVersion { get; };
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -822,7 +822,7 @@ try
// read settings.json from the Release stable file path if it exists.
// Otherwise use default settings file provided from original settings file
bool releaseSettingExists = false;
if (firstTimeSetup)
if (firstTimeSetup && !IsPortableMode())
{
#if defined(WT_BRANDING_PREVIEW)
{
Expand Down Expand Up @@ -1162,6 +1162,11 @@ winrt::hstring CascadiaSettings::SettingsPath()
return winrt::hstring{ _settingsPath().native() };
}

bool CascadiaSettings::IsPortableMode()
{
return Model::IsPortableMode();
}

winrt::hstring CascadiaSettings::DefaultSettingsPath()
{
// Both of these posts suggest getting the path to the exe, then removing
Expand Down
20 changes: 20 additions & 0 deletions src/cascadia/TerminalSettingsModel/FileUtils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,34 @@
static constexpr std::string_view Utf8Bom{ "\xEF\xBB\xBF", 3 };
static constexpr std::wstring_view UnpackagedSettingsFolderName{ L"Microsoft\\Windows Terminal\\" };
static constexpr std::wstring_view ReleaseSettingsFolder{ L"Packages\\Microsoft.WindowsTerminal_8wekyb3d8bbwe\\LocalState\\" };
static constexpr std::wstring_view PortableModeMarkerFile{ L".portable" };
static constexpr std::wstring_view PortableModeSettingsFolder{ L"settings" };

namespace winrt::Microsoft::Terminal::Settings::Model
{
// Returns a path like C:\Users\<username>\AppData\Local\Packages\<packagename>\LocalState
// You can put your settings.json or state.json in this directory.
bool IsPortableMode()
{
static auto portableMode = []() {
std::filesystem::path modulePath{ wil::GetModuleFileNameW<std::wstring>(wil::GetModuleInstanceHandle()) };
modulePath.replace_filename(PortableModeMarkerFile);
return std::filesystem::exists(modulePath);
}();
return portableMode;
}

std::filesystem::path GetBaseSettingsPath()
{
static auto baseSettingsPath = []() {
if (!IsPackaged() && IsPortableMode())
{
std::filesystem::path modulePath{ wil::GetModuleFileNameW<std::wstring>(wil::GetModuleInstanceHandle()) };
modulePath.replace_filename(PortableModeSettingsFolder);
std::filesystem::create_directories(modulePath);
return modulePath;
}

wil::unique_cotaskmem_string localAppDataFolder;
// KF_FLAG_FORCE_APP_DATA_REDIRECTION, when engaged, causes SHGet... to return
// the new AppModel paths (Packages/xxx/RoamingState, etc.) for standard path requests.
Expand Down
1 change: 1 addition & 0 deletions src/cascadia/TerminalSettingsModel/FileUtils.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@

namespace winrt::Microsoft::Terminal::Settings::Model
{
bool IsPortableMode();
std::filesystem::path GetBaseSettingsPath();
std::filesystem::path GetReleaseSettingsPath();
std::string ReadUTF8File(const std::filesystem::path& path, const bool elevatedOnly = false, FILETIME* lastWriteTime = nullptr);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,10 @@
<data name="SplitPaneParentCommandName" xml:space="preserve">
<value>Split Pane...</value>
</data>
<data name="ApplicationDisplayNamePortable" xml:space="preserve">
<value>Terminal (Portable)</value>
<comment>This display name is used when the Terminal application is running in a "portable" mode, where settings are not stored in a shared location.</comment>
</data>
<data name="ApplicationDisplayNameUnpackaged" xml:space="preserve">
<value>Terminal (Unpackaged)</value>
<comment>This display name is used when the application's name cannot be determined</comment>
Expand Down

0 comments on commit e6a3fa8

Please sign in to comment.