This PR represents the start of the work on Cascading User + default settings, #754. Cascading settings will be done in two parts: * [ ] Layered Default+User settings (this PR) * [ ] Dynamic Profile Generation (#2603). Until _both_ are done, _neither are going in. The dynamic profiles PR will target this PR when it's ready, but will go in as a separate commit into master. This PR covers adding one primary feature: the settings are now in two separate files: * a static `defaults.json` that ships with the package (the "default settings") * a `profiles.json` with the user's customizations (the "user settings) User settings are _layered_ upon the settings in the defaults settings. ## References Other things that might be related here: * #1378 - This seems like it's definitely fixed. The default keybindings are _much_ cleaner, and without the save-on-load behavior, the user's keybindings will be left in a good state * #1398 - This might have honestly been solved by #2475 ## PR Checklist * [x] Closes #754 * [x] Closes #1378 * [x] Closes #2566 * [x] I work here * [x] Tests added/passed * [x] Requires documentation to be updated - it **ABSOLUTELY DOES** ## Detailed Description of the Pull Request / Additional comments 1. We start by taking all of the `FromJson` functions in Profile, ColorScheme, Globals, etc, and converting them to `LayerJson` methods. These are effectively the same, with the change that instead of building a new object, they are simply layering the values on top of `this` object. 2. Next, we add tests for layering properties like that. 3. Now, we add a `defaults.json` to the package. This is the file the users can refer to as our default settings. 4. We then take that `defaults.json` and stamp it into an auto generated `.h` file, so we can use it's data without having to worry about reading it from disk. 5. We then change the `LoadAll` function in `CascadiaSettings`. Now, the function does two loads - one from the defaults, and then a second load from the `profiles.json` file, layering the settings from each source upon the previous values. 6. If the `profiles.json` file doesn't exist, we'll create it from a hardcoded `userDefaults.json`, which is stamped in similar to how `defaults.json` is. 7. We also add support for _unbinding_ keybindings that might exist in the `defaults.json`, but the user doesn't want to be bound to anything. 8. We add support for _hiding_ a profile, which is useful if a user doesn't want one of the default profiles to appear in the list of profiles. ## TODO: * [x] Still need to make Alt+Click work on the settings button * [x] Need to write some user documentation on how the new settings model works * [x] Fix the pair of tests I broke (re: Duplicate profiles) <hr> * Create profiles by layering them * Update test to layer multiple times on the same profile * Add support for layering an array of profiles, but break a couple tests * Add a defaults.json to the package * Layer colorschemes * Moves tests into individual classes * adds support for layering a colorscheme on top of another * Layer an array of color schemes * oh no, this was missed with #2481 must have committed without staging this change, uh oh. Not like those tests actually work so nbd * Layer keybindings * Read settings from defaults.json + profiles.json, layer appropriately This is like 80% of #754. Needs tests. * Add tests for keybindings * add support to unbind a key with `null` or `"unbound"` or `"garbage"` * Layer or clear optional properties * Add a helper to get an optional variable for a bunch of different types In the end, I think we need to ask _was this worth it_ * Do this with the stretch mode too * Add back in the GUID check for profiles * Add some tests for global settings layering * M A D W I T H P O W E R Add a MsBuild target to auto-generate a header with the defaults.json as a string in the file. That way, we can _always_ load the defaults. Literally impossible to not. * When the user's profile.json doesn't exist, create it from a template * Re-order profiles to match the order set in the user's profiles.json * Add tests for re-ordering profiles to match user ordering * Add support for hiding profiles using `"hidden": true` * Use the hardcoded defaults.json for the exception->"use defaults" case * Somehow I messed up the git submodules? * woo documentation * Fix a Terminal.App.Unit.Tests failure * signed/unsigned is hard * Use Alt+Settings button to open the default settings * Missed a signed/unsigned * Some very preliminary PR feedback * More PR feedback Use the wil helper for the exe path Move jsonutils into their own file kill some dead code * Add templates to these bois * remove some code for generating defaults, reorder defaults.json a tad * Make guid a std::optional * Large block of PR feedback * Remove some dead code * add some comments * tag some todos * stl is love, stl is life * add `-noprofile` * Fix the crash that dustin found * -Encoding ASCII * Set a profile's default scheme to Campbell * Fix the tests I regressed * Update UsingJsonSetting.md to reflect that changes from these PRs * Change how GenerateGuidForProfile works * Make AppKeyBindings do its own serialization * Remove leftover dead code from the previous commit * Fix up an enormous number of PR nits * Fix a typo; Update the defaults to match #2378 * Tiny nits * Some typos, PR nits * Fix this broken defaults case
101 lines
4.1 KiB
C++
101 lines
4.1 KiB
C++
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT license.
|
|
|
|
#pragma once
|
|
|
|
#include "Tab.h"
|
|
#include "CascadiaSettings.h"
|
|
#include "TerminalPage.h"
|
|
#include "App.g.h"
|
|
#include "App.base.h"
|
|
#include "../../cascadia/inc/cppwinrt_utils.h"
|
|
|
|
#include <winrt/Microsoft.Terminal.TerminalControl.h>
|
|
#include <winrt/Microsoft.Terminal.TerminalConnection.h>
|
|
|
|
#include <winrt/Microsoft.UI.Xaml.Controls.h>
|
|
#include <winrt/Microsoft.UI.Xaml.Controls.Primitives.h>
|
|
#include <winrt/Microsoft.UI.Xaml.XamlTypeInfo.h>
|
|
|
|
#include <winrt/Windows.ApplicationModel.DataTransfer.h>
|
|
|
|
namespace winrt::TerminalApp::implementation
|
|
{
|
|
struct App : AppT2<App>
|
|
{
|
|
public:
|
|
App();
|
|
~App() = default;
|
|
|
|
void Create();
|
|
void LoadSettings();
|
|
|
|
Windows::Foundation::Point GetLaunchDimensions(uint32_t dpi);
|
|
bool GetShowTabsInTitlebar();
|
|
|
|
Windows::UI::Xaml::UIElement GetRoot() noexcept;
|
|
|
|
hstring Title();
|
|
void TitlebarClicked();
|
|
|
|
// -------------------------------- WinRT Events ---------------------------------
|
|
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(TitleChanged, _titleChangeHandlers, winrt::Windows::Foundation::IInspectable, winrt::hstring);
|
|
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(LastTabClosed, _lastTabClosedHandlers, winrt::Windows::Foundation::IInspectable, winrt::TerminalApp::LastTabClosedEventArgs);
|
|
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(SetTitleBarContent, _setTitleBarContentHandlers, winrt::Windows::Foundation::IInspectable, winrt::Windows::UI::Xaml::UIElement);
|
|
DECLARE_EVENT_WITH_TYPED_EVENT_HANDLER(RequestedThemeChanged, _requestedThemeChangedHandlers, TerminalApp::App, winrt::Windows::UI::Xaml::ElementTheme);
|
|
|
|
private:
|
|
// If you add controls here, but forget to null them either here or in
|
|
// the ctor, you're going to have a bad time. It'll mysteriously fail to
|
|
// activate the app.
|
|
// ALSO: If you add any UIElements as roots here, make sure they're
|
|
// updated in _ApplyTheme. The root currently is _root.
|
|
winrt::com_ptr<TerminalPage> _root{ nullptr };
|
|
|
|
std::shared_ptr<::TerminalApp::CascadiaSettings> _settings{ nullptr };
|
|
|
|
std::shared_ptr<ScopedResourceLoader> _resourceLoader{ nullptr };
|
|
|
|
HRESULT _settingsLoadedResult;
|
|
winrt::hstring _settingsLoadExceptionText{};
|
|
|
|
bool _loadedInitialSettings;
|
|
|
|
wil::unique_folder_change_reader_nothrow _reader;
|
|
|
|
std::shared_mutex _dialogLock;
|
|
|
|
std::atomic<bool> _settingsReloadQueued{ false };
|
|
|
|
fire_and_forget _ShowDialog(const winrt::Windows::Foundation::IInspectable& sender, winrt::Windows::UI::Xaml::Controls::ContentDialog dialog);
|
|
void _ShowLoadErrorsDialog(const winrt::hstring& titleKey, const winrt::hstring& contentKey, HRESULT settingsLoadedResult);
|
|
void _ShowLoadWarningsDialog();
|
|
|
|
void _OnLoaded(const IInspectable& sender, const Windows::UI::Xaml::RoutedEventArgs& eventArgs);
|
|
|
|
[[nodiscard]] HRESULT _TryLoadSettings() noexcept;
|
|
void _LoadSettings();
|
|
void _RegisterSettingsChange();
|
|
fire_and_forget _DispatchReloadSettings();
|
|
void _ReloadSettings();
|
|
|
|
void _ApplyTheme(const Windows::UI::Xaml::ElementTheme& newTheme);
|
|
|
|
static Windows::UI::Xaml::Controls::IconElement _GetIconFromProfile(const ::TerminalApp::Profile& profile);
|
|
|
|
winrt::Microsoft::Terminal::TerminalControl::TermControl _GetFocusedControl();
|
|
|
|
void _CopyToClipboardHandler(const IInspectable& sender, const winrt::Microsoft::Terminal::TerminalControl::CopyToClipboardEventArgs& copiedData);
|
|
void _PasteFromClipboardHandler(const IInspectable& sender, const Microsoft::Terminal::TerminalControl::PasteFromClipboardEventArgs& eventArgs);
|
|
|
|
static void _SetAcceleratorForMenuItem(Windows::UI::Xaml::Controls::MenuFlyoutItem& menuItem, const winrt::Microsoft::Terminal::Settings::KeyChord& keyChord);
|
|
};
|
|
}
|
|
|
|
namespace winrt::TerminalApp::factory_implementation
|
|
{
|
|
struct App : AppT<App, implementation::App>
|
|
{
|
|
};
|
|
}
|